Redth / ZXing.Net.Mobile

Barcode Scanner for Xamarin.iOS, Xamarin.Android, UWP and Tizen
MIT License
1.07k stars 703 forks source link

Scanner never starts on iOS #788

Closed Alexabreu007 closed 4 years ago

Alexabreu007 commented 6 years ago

Hi this is my code that I'm using for Xamarin Forms PCL, in Android works fine but not in iOS.

I have downgraded the version to 2.1.47 but still not working.

I also have the Permission on iOS: NSCameraUsageDescription

    {
        var scanner = new MobileBarcodeScanner();
        var result = await scanner.Scan();

        if (result != null)
        {
            string strValue = result.Text;
            LoadData(strValue);
        }
lobbo232 commented 6 years ago

I have a similar issue.

Code in my view model in Xamarin.Forms:

var scanner = new ZXing.Mobile.MobileBarcodeScanner();
var result = await scanner.Scan();

App crashes on the second line (scanner.Scan();) but does not hit an exception in a try/catch block. Instead the app just closes.

I also have this in AppDelegate.cs in my iOS project:

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
    global::Xamarin.Forms.Forms.Init();
    LoadApplication(new App());
    ZXing.Net.Mobile.Forms.iOS.Platform.Init();

    return base.FinishedLaunching(app, options);
}

You could try adding this if you don't have it

lobbo232 commented 6 years ago

I think it is a permission issue.

I added the permisison plugin by James Montemagno and requested the permission for the camera as below, which solved this problem for me. I know its another plugin in your app but James has pretty good stuff!

var cameraPermission = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Camera);
if (cameraPermission != PermissionStatus.Granted)
{
    if (await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(Permission.Camera))
    {
       await Application.Current.MainPage.DisplayAlert("Camera Unavailable", Constants.AppName + " requires the camera permission", "OK");
    }

    var results = await CrossPermissions.Current.RequestPermissionsAsync(new[] { Permission.Camera });
    cameraPermission = results[Permission.Camera];
    if (cameraPermission != PermissionStatus.Granted)
    {
        await Application.Current.MainPage.DisplayAlert("Camera Unavailable", Constants.AppName + " requires the camera permission", "OK");
        return;
    }
}

var scanner = new ZXing.Mobile.MobileBarcodeScanner();
var result = await scanner.Scan();
Alexabreu007 commented 6 years ago

Thank you Guys.

You're right @lobbo232 first of all I had to check the permission using the cross permission from Montemagno.

Second: that fix just works when you call the scanbarcode from the main page so in order to call scan barcode from another page or from the menu I had to create a DependencyService in IOS in order to call scan barcode from any place in Forms iOS.

if iOS

        if (Device.RuntimePlatform == "iOS")
        {               
            var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Camera);
            if (status != PermissionStatus.Granted)
            {
                if (await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(Permission.Camera))
                {
                    //await DisplayAlert("Need location", "Gunna need that location", "OK");
                }

                var results = await CrossPermissions.Current.RequestPermissionsAsync(Permission.Camera);

                if (results.ContainsKey(Permission.Camera))
                    status = results[Permission.Camera];

                if (status == PermissionStatus.Granted)
                {
                    string strResult = await DependencyService.Get<IQrCodeScanningService>().ScanAsync();
                    LoadDataCloud("", "", strResult);
                }
            }
            else
            {
                string strResult = await DependencyService.Get<IQrCodeScanningService>().ScanAsync();
                LoadDataCloud("", "", strResult);
            }
        }

if Android

        // Android-specific code
        if (Device.RuntimePlatform == "Android")
        {
            var scanner = new MobileBarcodeScanner();
            var result = await scanner.Scan();

            if (result != null)
            {
                string strValue = result.Text;
                LoadDataCloud("", "", strValue);
            }
        }

endif

Below the code to create the dependency Service in iOS project:

namespace DolphinMobile.iOS { public class QrCodeScanningService : IQrCodeScanningService { public QrCodeScanningService() {

    }

    async Task<String> IQrCodeScanningService.ScanAsync()
    {
        var window = UIApplication.SharedApplication.KeyWindow;
        var vc = window.RootViewController;
        while (vc.PresentedViewController != null)
        {
            vc = vc.PresentedViewController;
        }

        var scanner = new ZXing.Mobile.MobileBarcodeScanner(vc);
        var scanResults = await scanner.Scan();

        if (scanResults != null)
        {
            return scanResults.Text;
        }
        return "";
    }
}

}

vg2019 commented 5 years ago

Hi @Alexabreu007 , i am having the same issue but couldn't understand where exactly to use your code. Is it possible you could post a more specific code with exact locations for Ios and Mobile sections.

Thanks a lot.

Alexabreu007 commented 5 years ago

Hi,

  1. Create a class in your iOS Project called "QrCodeScanningService.cs"
  2. Define conditional compilation symbols : Android;iOS
  3. add CrossPermissions nuget package
  4. Add the code in your Scan button [ScanBarcode Click.txt]

QrCodeScanningService.txt

[ScanBarcode Click.txt] (https://github.com/Redth/ZXing.Net.Mobile/files/2654630/ScanBarcode.Click.txt)

vg2019 commented 5 years ago

Dear @Alexabreu007 , Thank you very much this solved my problem, for those who have the same problem , ZXing not running on IOS 8 And later, i would like to clarify the subject a little bit more

The problem is based on 2 issues

  1. Camera permission There are several ways of solving this , some more detail and a plugin is available at https://github.com/jamesmontemagno/PermissionsPlugin , or adding the related permissions to info.plist file so go with your own solution :)

  2. Missing QrScanningService at IOS Section At android project we add a File at Services> QrScanningService.cs with the following code

using System;
using System.Threading.Tasks;
using WareHouseCV.Services;
using ZXing.Mobile;
using Xamarin.Forms;

[assembly: Dependency(typeof(QrScanningService))]
namespace WareHouseCV.Services
{
    public class QrScanningService : IQrScanningService
    {
        public async Task<string> ScanAsync()
        {
            try
            {
                var scanner = new MobileBarcodeScanner()
                {
                    TopText = "Scan the QR Code",
                    BottomText = "Please Wait"
                };

                var scanResult = await scanner.Scan();
                if (scanResult != null)
                {
                    return scanResult.Text;
                }
                else
                {
                    return "";
                }

            }
            catch (Exception exc)
            {

                throw;
            }

        }
    }
}

However in all the setup manuals for ZXING Mobile that i checked, there is NOT a single one mentioning we need to have a version of QrScanningService at IOS Project, so based on @Alexabreu007 comments i added QrScanningService.cs directly in the root of IOS project and

using System;
using UIKit;
using System.Threading.Tasks;
using Xamarin.Forms;

[assembly: Dependency(typeof(WareHouseCV.iOS.IQrCodeScanningService))]

namespace WareHouseCV.iOS
{
    public class QrScanningService : IQrCodeScanningService
    {
        public QrScanningService()
        {

        }

        public async Task<String> ScanAsync()
        {
            var window = UIApplication.SharedApplication.KeyWindow;
            var vc = window.RootViewController;
            while (vc.PresentedViewController != null)
            {
                vc = vc.PresentedViewController;
            }

            var scanner = new ZXing.Mobile.MobileBarcodeScanner(vc);
            var scanResults = await scanner.Scan();

            if (scanResults != null)
            {
                return scanResults.Text;
            }
            return "";
        }
    }
}

Now when the project is compiled under Android it uses QrScanningService at the Android, and when compiled in IOS goes to IOS version of QrScanningService and therefore runs perfectly fine.

Redth commented 4 years ago

Thanks for reporting this issue! Unforunately it took me way too long to respond 😭. Sorry, I apologize! Recently the source code for this project was completely refactored to modernize it. Many PR's were included in this effort, and many bugs were hopefully fixed. Please try out the latest 3.x series of NuGet packages (currently in prerelease). To try and make the project more maintainable in my spare time going forward, I've decided to close all existing issues to start with a clean slate. If you're still experiencing this issue on the newest version, please open a new issue with as much detail as possible. Thank you for your patience and understanding! Happy scanning!