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();
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