Search code examples
c#androidxamarinandroid-webviewzxing

Launching a QR scanner from Android web view and returning the scanned result using Xamarin


I have this Xamarin application that launches a QR scanner when a button is clicked. This button click is handled in Javascript. When the button is clicked, below C# code gets called. This supposed to launch the QR scanner and once the value is scanned, the scanned value is returned to a Javascript function. But as soon as the button to scan QR code is clicked, web view app gets to the background but camera is not launched to scan the QR code.

 public class QRScannerJSInterface : Java.Lang.Object
    {
        QRScanner qrScanner;
        WebView webView;

        public QRScannerJSInterface(WebView webView)
        {
            this.webView = webView;
            qrScanner = new QRScanner();
        }

        [Export]
        [JavascriptInterface]
        public void ScanQR()
        {
            String result = qrScanner.ScanQR();
            var js = string.Format("getQRValue('{0}');", result);
            webView.LoadUrl("javascript:" + js);
            //call the Javascript method here with "result" as its parameter to get the scanned value
        }

Below is how the main activity calls this class.

        webView = FindViewById<WebView>(Resource.Id.webView);
        webView.Settings.JavaScriptEnabled = true;
        webView.Settings.AllowFileAccessFromFileURLs = true;
        webView.Settings.AllowUniversalAccessFromFileURLs = true;
        webView.Settings.AllowFileAccess = true;
        webView.AddJavascriptInterface(new QRScannerJSInterface(webView),"CSharpQRInterface");

Below is the QRScanner code.

class QRScanner
    {
        MobileBarcodeScanner scanner;

        public QRScanner()
        {
            scanner = new MobileBarcodeScanner();
        }

        public String ScanQR()
        {
            scanner.UseCustomOverlay = false;
            scanner.TopText = "Scanning for barcode";
            Task<ZXing.Result> result = scanner.Scan();
            return result.ToString();
        }
    }

What am I doing wrong here? Any help would be much appreciated.


Solution

  • Below is working solution. Please note scanner async Scan changes. before you would get Task into your js file, you need to await for result.

    Asset scannerPage.html

    <html>
    <head>
        <title></title>
    
        <script type='text/javascript'>
    
            function getQRValue(result) {
        };
    
            function scan() {
                CSharpQRInterface.ScanQR();
            };
    
    
        </script>
    
    </head>
    <body style="background-color:powderblue;">
        <button type="button" onclick="scan()">Click Me!</button>
    </body>
    </html>
    

    MainActivity

    public class MainActivity : Activity
        {
            WebView webView;
    
            protected override void OnCreate(Bundle bundle)
            {
                base.OnCreate(bundle);
    
                MobileBarcodeScanner.Initialize(Application);
    
                // Set our view from the "main" layout resource
                SetContentView(Resource.Layout.Main);
    
                webView = FindViewById<WebView>(Resource.Id.webView);
                webView.Settings.JavaScriptEnabled = true;
                webView.Settings.AllowFileAccessFromFileURLs = true;
                webView.Settings.AllowUniversalAccessFromFileURLs = true;
                webView.Settings.AllowFileAccess = true;
                webView.AddJavascriptInterface(new QRScannerJSInterface(webView), "CSharpQRInterface");
                webView.LoadUrl("file:///android_asset/scannerPage.html");
    
            }
    

    Scanner interface

    public class QRScannerJSInterface : Java.Lang.Object
        {
            QRScanner qrScanner;
            WebView webView;
    
            public QRScannerJSInterface(WebView webView)
            {
                this.webView = webView;
                qrScanner = new QRScanner();
            }
    
            [Export("ScanQR")]
            public void ScanQR()
            {
                qrScanner.ScanQR()
                    .ContinueWith((t) =>
                    {
                        //var js = string.Format("getQRValue('{0}');", t.Result);
                        //webView.LoadUrl("javascript:" + js);
                        //call the Javascript method here with "result" as its parameter to get the scanned value
                        if (t.Status == TaskStatus.RanToCompletion)
                            webView.LoadUrl(@"javascript:getQRValue('" + t.Result + "')");
                    });
            }
        }
    

    Scanner class

    class QRScanner
        {
            MobileBarcodeScanner scanner;
    
            public QRScanner()
            {
                scanner = new MobileBarcodeScanner();
            }
    
            public async Task<string> ScanQR()
            {
                scanner.UseCustomOverlay = false;
                scanner.TopText = "Scanning for barcode";
                var result = await scanner.Scan();
                return result.ToString();
            }
        }