Laden...

Kamera blockiert Scanner in Xamarin Forms - UWP App

Erstellt von Urza vor 4 Jahren Letzter Beitrag vor 4 Jahren 2.413 Views
U
Urza Themenstarter:in
69 Beiträge seit 2019
vor 4 Jahren
Kamera blockiert Scanner in Xamarin Forms - UWP App

Hallo,

Ich habe ein Xamarin Forms (4.2.0.709249) Projekt.
Ich nutzte das Plugin Xam.Plugin.Media (4.0.1.5) um Fotos zu machen.
Ich nutze das Plugin ZXing.Net.Mobile.Forms (2.4.1) um Barcodes zu scannen.

Für ZXing habe ich im MainPage Konstruktor nach Anleitung folgendes hinzugefügt:

ZXing.Net.Mobile.Forms.WindowsUniversal.ZXingScannerViewRenderer.Init();

Und für das Xam.Plugin.Media habe ich nach Anleitung die Webcam Capability aktiviert.
Das folgende Problem tritt nur bei UWP auf. Bei Android und iOS Geräten habe ich kein Problem.

Testgerät: Microsoft Surface, Windows 10 Pro, mit zwei Kameras.
Nennen wir die Kameras mal Frontkamera und Webcam.
Zum Scannen von Barcodes wird die Frontkamera verwendet und es gibt keine Möglichkeit die Kamera zu wechseln.
Nach der Installation kann ich problemlos beliebig Barcodes scannen.
Öffne ich dann einmal die Kamera über meine App um ein Foto zu machen und stelle auch hier die Frontkamera ein kann ich danach keine Barcodes mehr scannen.
Der Bildschirm bleibt einfach weiß.
Um wieder Barcodes scannen zu können muss ich entweder

  • wieder die Kamera über meine App öffnen und die Webcam einstellen.
  • oder die Windows App "Kamera" starten. Dabei ist es widerrum egal ob ich die Frontkamera oder die Webcam einstelle. Nachdem ich die App geschlossen habe kann ich in meiner App wieder Barcodes scannen.

Sowohl die Windows App "Kamera" als auch die von mir aufgerufenen Kamera scheinen beide die Windows App "Kamera" aufzurufen.
Das Problem wird durch einen Neustart meiner App auch nicht behoben.

Ich habe mir zu dem Problem ein Testprojekt gebaut. Dazu habe ich ein Xamarin.Forms Projekt mit der Vorlage Master-Detail in Visual Studio angelegt.
In der About.xaml habe ich zwei Buttons unter dem "Learn more" Button hinzugefügt:

                <Button
                    Margin="0,10,0,0"
                    BackgroundColor="{StaticResource Primary}"
                    Command="{Binding ScanCommand}"
                    Text="Scan"
                    TextColor="White" />
                <Button
                    Margin="0,10,0,0"
                    BackgroundColor="{StaticResource Primary}"
                    Command="{Binding TakePhotoCommand}"
                    Text="TakePhoto"
                    TextColor="White" />

Mein AboutViewModel sieht so aus:

    public class AboutViewModel : BaseViewModel
    {
        public ICommand OpenWebCommand { get; }
        public ICommand ScanCommand { get; }
        public ICommand TakePhotoCommand { get; }

        public AboutViewModel()
        {
            Title = "About";
            OpenWebCommand = new Command(() => Device.OpenUri(new Uri("https://xamarin.com/platform")));
            ScanCommand = new Command(async () => await ScanAsync());
            TakePhotoCommand = new Command(async () => await TakePhotoAsync());
        }

        private async Task ScanAsync()
        {
            var camera = new Camera();
            await camera.ScanBarcode(p => Application.Current?.MainPage?.DisplayAlert("Barcode", p, "ok"));
        }

        private async Task TakePhotoAsync()
        {
            var camera = new Camera();
            await camera.TakePhoto(p => { });
        }
    }

Und meine Klasse Camera sieht so aus:


    public class Camera
    {
        public Task TakePhoto(Action<MediaFile> onPhotoTakenAction, Action noCameraAction = null)
        {
            return TakePhoto(null, onPhotoTakenAction, noCameraAction);
        }

        public async Task TakePhoto(string directory, Action<MediaFile> onPhotoTakenAction, Action noCameraAction = null)
        {
            if (!await IsCameraAvailable())
            {
                noCameraAction?.Invoke();
                return;
            }

            var mediaOptions = new StoreCameraMediaOptions();
            mediaOptions.MaxWidthHeight = 1024;
            mediaOptions.PhotoSize = PhotoSize.MaxWidthHeight;
            mediaOptions.Name = Guid.NewGuid().ToString("N") + ".jpg";
            mediaOptions.CompressionQuality = 50;

            if (!string.IsNullOrEmpty(directory))
                mediaOptions.Directory = directory;

            var photo = await CrossMedia.Current.TakePhotoAsync(mediaOptions);

            if (photo != null)
                onPhotoTakenAction(photo);
        }

        public async Task ScanBarcode(Action<string> onScannedAction)
        {
            if (!await IsCameraAvailable())
                return;

            ZXingScannerPage scanPage;

            var stackLayout = new StackLayout();
            stackLayout.HorizontalOptions = LayoutOptions.FillAndExpand;
            stackLayout.VerticalOptions = LayoutOptions.FillAndExpand;
            var cancelButton = new Button();
            cancelButton.VerticalOptions = LayoutOptions.EndAndExpand;
            cancelButton.HorizontalOptions = LayoutOptions.EndAndExpand;
            cancelButton.Text = "Cancel";
            stackLayout.Children.Add(cancelButton);

            scanPage = new ZXingScannerPage(MobileBarcodeScanningOptions.Default, stackLayout);

            cancelButton.Clicked += async (sender, args) =>
            {
                await scanPage.Navigation.PopModalAsync();
            };

            scanPage.OnScanResult += result =>
            {
                scanPage.IsScanning = false;

                Device.BeginInvokeOnMainThread(async () =>
                {
                    await scanPage.Navigation.PopModalAsync();

                    if (!string.IsNullOrEmpty(result.Text))
                        onScannedAction(result.Text);
                });
            };

            await Application.Current.MainPage.Navigation.PushModalAsync(scanPage);
        }

        private async Task<bool> IsCameraAvailable()
        {
            var isInitialized = await CrossMedia.Current.Initialize();
            var isCameraAvailable = false;

            if (isInitialized)
                isCameraAvailable = CrossMedia.Current.IsCameraAvailable;

            return isCameraAvailable;
        }
    }

Alternativ habe ich den Zugriff auf die Kamera ohne das Plugin.Media mit Hilfe des DependencyServices realisiert. Gleiches Ergebnis...

[assembly: Dependency(typeof(Camera_UWP))]
namespace CameraScanTest.UWP
{
    public class Camera_UWP : ICamera
    {
        public async Task TakePhoto()
        {
            CameraCaptureUI captureUI = new CameraCaptureUI();
            captureUI.PhotoSettings.Format = CameraCaptureUIPhotoFormat.Jpeg;
            captureUI.PhotoSettings.CroppedSizeInPixels = new Windows.Foundation.Size(200, 200);

            StorageFile photo = await captureUI.CaptureFileAsync(CameraCaptureUIMode.Photo);

            if (photo == null)
            {
                // User cancelled photo capture
                return;
            }
        }
    }
}

Habt ihr nützliche Tips für mich?

Viele Grüße

Urza

“Knowledge cannot replace friendship. I'd rather be an idiot than lose you.”

  • Patrick to Spongebob
286 Beiträge seit 2011
vor 4 Jahren

Ich hab ZXing schon länger nicht mehr benutzt (und für UWP noch nie), aber solche Probleme hingen bei meinen iOS/Android-Projekten fast immer mit Rechten zusammen. Sprich aus irgend einem Grund möchte das Smartphone gerade nicht, dass du auf die Kamera zugreifen kannst.

So wie ich dein Problem lese fehlt irgend eine weitere Berechtigung im Manifest (Kamera wechseln o.ä. wie gesagt, ich weiß nicht welche Rechte bei UWP speziell festgelegt werden können).

Ich erinnere mich dunkel daran, dass es bei ZXing mal ein Problem mit dem Flashlight gab. Also Fehler auftraten, wenn du keine Rechte zum Nutzen des Flashlights angefordert hast (obwohl es nicht verwendet wird). Ist aber schon 2-3 Jahre her, dass ich damit zu tun hatte.

Beste Grüße
emuuu

2+2=5( (für extrem große Werte von 2)

U
Urza Themenstarter:in
69 Beiträge seit 2019
vor 4 Jahren

Hallo emuuu,

danke für die Antwort.
Ich habe gerade mal einfach alle Capabilities aktiviert. Keine Änderung.
Grundsätzlich klappt ja sowohl das wechseln der Kamera als auch das Scannen von Barcodes.
Es ist nur die Kombination von beidem...

Viele Grüße

Urza

“Knowledge cannot replace friendship. I'd rather be an idiot than lose you.”

  • Patrick to Spongebob
1.040 Beiträge seit 2007
vor 4 Jahren

Was liefert denn IsCameraAvailable zurück?

Ohne dir eine genaue Lösung zu liefern, liest es sich so, als wenn die Camera im Gerät einfach "blockiert" ist, evtl. muss sie explizit wieder freigegeben werden.

Was passiert, wenn du deine Kamera-App, die augenscheinlich für die Blockade zuständig ist, schließt - kannst du dann wieder Barcodes scannen?

T
708 Beiträge seit 2008
vor 4 Jahren

Hallo Urza,

da ich selbiges Szenario habe aber die Kombination unter UWP so noch nicht getestet habe, hier meine Ergebnisse:*Barcodescan mit der Webcam: OK *Kamera Aufnahme mit der Webcam: OK *Barcodescan mit der Webcam: OK *Kamera Aufnahme mit der Haupt-Kamera: OK *Barcodescan mit der Webcam: OK

Über eine Einrichtung in einer Datenbank kann ich den Barcodescan ebenfalls mit der Hauptkamera tätigen. Das hat aber unter UWP nach wie vor die Webcam geöffnet. Ohne erst die Hauptkamera zu starten.
Unter Android wechselt die Webcam und Hauptkamera freudig hin und her, je nach dem wie ich den Haken setze.

Surfacebook 1
Xamarin Forms 3.6.0.539721
ZXing: 2.4.1
Xam.Plugin.Media: 4.0.1.5

Und ja, ich weiß: Die Forms Version ist veraltet. Sobald ich diese hochziehe, läuft die Anwendung aber nicht mehr unter Android 4.0.3. Bzw. sie startet, man kann sie aber nicht mehr bedienen, da Pop & Push nix mehr machen.

U
Urza Themenstarter:in
69 Beiträge seit 2019
vor 4 Jahren

Hallo p!lle,

IsCameraAvailable liefert true zurück.
Sonst würde sich der Scanner/die Foto-App gar nicht erst öffnen. In der ursprünglichen Anwendung bekommt der Nutzer dann einen entsprechenden Hinweis.
Die Methode prüft aber nicht ob die Kamera blockiert ist o.ä. sondern fragt nur ab, ob das Gerät eine Kamera verbaut hat.
Das Initialize() wird auch im Beispiel des Plugin-Erstellers vor jedem Aufruf der Kamera aufgerufen...

Was passiert, wenn du deine Kamera-App, die augenscheinlich für die Blockade zuständig ist, schließt - kannst du dann wieder Barcodes scannen?

Das mache ich immer. Ohne meine Kamera-App zu schließen kann ich die App nicht weiter bedienen. Die Kamera-App ist quasi ein modales Fenster.

...liest es sich so, als wenn die Camera im Gerät einfach "blockiert" ist

Ja das sehe ich auch so, wie ich ich auch im Titel des Beitrags angedeutet habe. Aber ich habe bisher noch keine Möglichkeit gefunden die "Blockade" aufzuheben. Für die Windows eigene Kamera-App ist die Kamera ja auch wiederum nicht blockiert.

Btw.: Der Code wie er im Dependency-Service steht ist ein 1:1 Kopie aus den Microsoft docs...

Viele Grüße

Urza

“Knowledge cannot replace friendship. I'd rather be an idiot than lose you.”

  • Patrick to Spongebob
U
Urza Themenstarter:in
69 Beiträge seit 2019
vor 4 Jahren

Hallo trib,

danke, dass du dir die Mühe gemacht hast das Problem nachzuvollziehen.
Ich habe beim Nachvollziehen deiner Schritte noch folgendes festgestellt.

Öffne ich die Kamera und mache tatsächlich ein Foto läuft alles super.
Öffne ich die Kamera und schließe sie ohne ein Foto zu machen oder verwerfe ich das gemachte Foto dann habe ich das besagte Problem, dass ich keine Barcodes mehr scannen kann.

Viele Grüße

Urza

“Knowledge cannot replace friendship. I'd rather be an idiot than lose you.”

  • Patrick to Spongebob
16.806 Beiträge seit 2008
vor 4 Jahren

Auch für mich liest sich das so, dass die Camera blockiert it.

Ich würde hier zwei Dinge mal prüfen:

  • Hast Du irgendwo ein Dispose vergessen und ein Handle ist noch offen?
  • Musst Du die ZXing Lib informieren?

Soweit ich ZXing noch in Erinnerung hatte, muss man bei einem Page Wechsel zB das Scannen von Barcodes deaktivieren und bei einer anderen Page entsprechend wieder aktivieren.

Bei Dir wird das Scannen nur deaktiviert, wenn etwas gefunden wurde

scanPage.OnScanResult += result =>
            {
                scanPage.IsScanning = false;
U
Urza Themenstarter:in
69 Beiträge seit 2019
vor 4 Jahren

Hallo Abt,

danke für die Hilfe.
Ich habe alle relevanten Typen überprüft. Ich kann nirgendwo ein Dispose, Close o.ä. aufrufen.
Den Tip mit dem IsScanning = false habe ich gerade mal getestet.


cancelButton.Clicked += async (sender, args) =>
{
    scanPage.IsScanning = false;
    await scanPage.Navigation.PopModalAsync();
};

Leider ohne Erfolg.

“Knowledge cannot replace friendship. I'd rather be an idiot than lose you.”

  • Patrick to Spongebob
U
Urza Themenstarter:in
69 Beiträge seit 2019
vor 4 Jahren

Hallo zusammen,

hier ein kleines Update.
Die Kamera wird tatsächlich von der Windows-Kamera App blockiert.
Schließe ich die Kamera in meiner App, ohne ein Foto zu machen, taucht im Task-Manager ein "Kamera" Prozess auf.
Solange dieser Prozess nicht beendet wird kann keine andere App mehr auf die Kamera zugreifen.
Es liegt wohl auch nicht an meiner App. Ich habe testweise die App "Ultimate Photo Editor" installiert. Dort kann ich das Verhalten auch reproduzieren.

Leider kann ich den Prozess in UWP nicht einfach beenden...

Viele Grüße

Urza

“Knowledge cannot replace friendship. I'd rather be an idiot than lose you.”

  • Patrick to Spongebob