mintware-de / flutter_barcode_reader

A flutter plugin for reading 2D barcodes and QR codes.
MIT License
628 stars 462 forks source link

Web support #194

Open fercarcedo opened 4 years ago

fercarcedo commented 4 years ago

This PR introduces web support, using the JsQRScanner JavaScript library.

The interface is implemented in HTML and CSS and tries to resemble as much as possible the one found on the mobile versions.

As a limitation, this web version doesn't support enabling the flashlight. In order to check if a device has a flashlight and enable it, we need to use the ImageCapture class which, at the time of opening this PR, has support problems with Firefox and Safari. It also doesn't seem to offer the ability to turn off the flashlight once turned on (once you request the flashlight to be turned on this seems to stick to the current video track session and it's on until you start a whole new track).

This PR is implemented as a separate plugin. This seems to be the way to do it, as this post details https://medium.com/flutter/how-to-write-a-flutter-web-plugin-5e26c689ea1 (given the fact that this plugin does not follow the federated style). If you want it implemented in any other way, let me know :)

Closes #190

fercarcedo commented 4 years ago

@senatormas I have a problem while loading the library dynamically, like I did with JsQRScanner (what I do is to create a new script element and append it to the head element). The script element gets attached to the DOM, but after that the library is not being loaded (when trying to instantiate ZXing.BrowserMultiFormatReader it's undefined).

I tried the same code as JavaScript on an external html file and it works as expected. The documentation indicates the code to be placed inside a load event listener, so I tried to dispatch that event manually, but it still is undefined.

Do you have any ideas on this? Thank you for reaching out :)

odahcam commented 4 years ago

Hey, let me share my thoughts.

About that load event in the docs: that's only used to make sure the document is loaded before start playing with the DOM, it makes no difference for the library at all, that's there because document.getElementById('img') wouldn't work properly if the document wasn't loaded.

The ZXing library UMD build (which you are trying to load) is generated by Webpack, so it's possible that when it loads dynamically, it is not available as usual modules due to AMD behavior. I don't know how Webpack bundles it but it's probably stored inside some key inside the global window variable.

Another reason this could be happening is that you are trying to access ZXing on window right after adding the script to the head of the document, which of course will not work, because the script takes time to load, thus ZXing will only be available when the loading is complete. I think this is your issue.

Both last paragraphs are related to the same thing. That's why we have an UMD build, that implements AMD within it, and was designed to solve this issue.

I would recommend you using the ES6 build if possible, where you could use import('@zxing/library').then(zxing => { ... }) instead.

I hope you find this content and links useful.

fercarcedo commented 4 years ago

@odahcam Thank you for helping!

I was trying the UMD build because AFAIK on Flutter we can't use AMD. Also, regarding the problem of accessing ZXing on window right after adding the script to the head of the document, I also tried to access it using the browser JavaScript console, but it still is undefined.

I'll continue to try to fix this problem when I can. I'll try the UMD build that implements AMD within it, thank you

odahcam commented 4 years ago

You're welcome. I have really no idea how you handle this in Flutter so I'm sorry if something I said doesn't fit. I wish I could help more.

treeder commented 4 years ago

This seems to have broken at some point, not sure if it's related to updates to the mintware-de updates, but looks like this PR needs a rebase.

Screenshot 2020-05-07 at 5 02 15 PM

treeder commented 4 years ago

@fercarcedo why don't you just stick to JsQrScanner since it works and you already had it working. But can you rebase this PR so it fixes the conflicts then we can try to get this merged upstream so it doesn't get out of sync again?

fercarcedo commented 4 years ago

@fercarcedo why don't you just stick to JsQrScanner since it works and you already had it working. But can you rebase this PR so it fixes the conflicts then we can try to get this merged upstream so it doesn't get out of sync again?

Yes, I think this could be a better option (also this month I didn't have too much time to try to solve the problems with the new implementation). I'm going to then rebase this PR with the JsQRScanner implementation and will upload the code that I had for the zxing-js implementation to a branch of my fork in case anyone is interested in trying to contribute a fix to it

treeder commented 4 years ago

@fercarcedo can you try a rebase on this?

fercarcedo commented 4 years ago

Yes, I have a rebase in progress, but I think I have to modify the code to handle the new callbacks introduced. I'm not sure if this weekend I'll have time to implement this, but next week definitely, so I'll keep you updated

brockmcblockchain commented 4 years ago

any update on this @fercarcedo ?

fercarcedo commented 4 years ago

Yes, I had some time over the weekend to work on the rebase. In fact I'm finishing it up right now :) (currently I'm modifying the code to make use of the newly added Options api). Then if it continues to work properly I'll update this PR. I'll keep you updated, but shouldn't take long :)

brockmcblockchain commented 4 years ago

Awesome! thanks for the update!

treeder commented 4 years ago

Hey @fercarcedo , how goes it? :)

fercarcedo commented 4 years ago

I need to finish up the handling of some callbacks (for example, the permissions granted event, which has some problems right now), as well as to test everything again to make sure there are no regressions. Over the week of course I have less time than over the weekend, but everything seems to be progressing nicely. I expect this rebase to be finished during the course of the week :) Will keep you updated

fercarcedo commented 4 years ago

Update: added remaining callback handling and fixed errors. What I have to complete now is the ability to specify which camera to use (as opposed to always using the rear camera right now) and check that everything still works as expected. It's very likely that this PR will be updated tomorrow

fercarcedo commented 4 years ago

Another update: I need to do some more testing before updating the PR, but now the rebase is complete and everything seems to be working as expected. So tomorrow I'll update this PR if there are no problems found during testing :)

fercarcedo commented 4 years ago

Rebase completed :rocket: :rocket:

brockmcblockchain commented 4 years ago

@devtronic @treeder care to take a look?

treeder commented 4 years ago

I'm not sure what the expected behavior is for this anymore now that there's a ScanResult.type, but something is off. When a user cancels a scan, it throws a PlatformException that looks like this: PlatformException(USER_CANCELED, User closed the scan window, null). The problem is you can't check the type because it throws and there's not BarcodeScanner.userCancelled anymore.

fercarcedo commented 4 years ago

Good point. I just checked again the ScanResult proto and it seems likely that the expected behavior would be to return a ScanResult of type Cancelled

fercarcedo commented 4 years ago

Based on the Android source code of the plugin, I can confirm that indeed the expected behavior is to return a ScanResult of type Cancelled, and also that the remaining PlatformExceptions need to be converted to a ScanResult of type Error. I'm going to work on this later today and update this pull request

treeder commented 4 years ago

Seems strange to me that it would return an error type and not throw an error. 🤷‍♂️ I asked that here too: https://github.com/mintware-de/flutter_barcode_reader/issues/269

Do you know how to check an error message, ie: what caused the failure?

fercarcedo commented 4 years ago

Seems strange to me too, but it's implemented that way in the Android source code. You can check out the ScanResultHandler.kt file, it returns an error type with the error as the rawContent.

Also, if you look at the README of the 3.x branch they assume a ScanResult is always returned (previously there were multiple catch blocks for the different exception types).

My understanding from the code is that you can get the error code from the rawContent of the ScanResult and then compare that to the various constants exposed through BarcodeScanner

fercarcedo commented 4 years ago

PR updated :) I'm returning ScanResult for both errors and cancellations, with exactly the same code as the Android plugin

brockmcblockchain commented 4 years ago

@devtronic can we get a merge if it looks good to you?

RicardoHds commented 4 years ago

Any updates that how to use web support? I tried your options @fercarcedo @treeder but also have the same errors, also using the example folder. Capture

And in my project image

treeder commented 4 years ago

@fercarcedo needs to remove relative path he has in the pubspec.

treeder commented 4 years ago

Made a PR here: https://github.com/fercarcedo/flutter_barcode_reader/pull/1

SetNameHere commented 3 years ago

Hi, first of all thanks for your work. Is there any news on this? It would be really great to have web support for this package to use it in flutter PWAs