Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Post History
I have a QR code which needs to read through Google's ML kit for Android since Zxing.MAUI doesnt read it. I followed the code in ml-kit/vision/barcode-scanning/android and VinayByte/mlkit-qr-code-s...
#2: Post edited
- I have a QR code which needs to read through Google's ML kit for Android since Zxing.MAUI doesnt read it. I followed the code in [ml-kit/vision/barcode-scanning/android](https://developers.google.com/ml-kit/vision/barcode-scanning/android) and [VinayByte/mlkit-qr-code-scan-android-kotlin](https://github.com/VinayByte/mlkit-qr-code-scan-android-kotlin) and also [hjam40/Camera.MAUI](https://github.com/hjam40/Camera.MAUI) I was not able to use Camera.MAUI since it doesnt work for .net 9
- Here is my custom control code, if anyone has an idea why the preview is not showing up that would be a great help!
- ```csharp
- builder.ConfigureMauiHandlers(handlers =>
- {
- handlers.AddHandler<QRCodeReaderView, QRCodeReaderViewHandler>();
- });
- ```
- Custom control
- ```csharp
- public class QRCodeReaderView : View {}
- ```
- ```csharp
- public partial class QRCodeReaderViewHandler
- {
- public static IPropertyMapper<QRCodeReaderView, QRCodeReaderViewHandler> PropertyMapper = new PropertyMapper<QRCodeReaderView, QRCodeReaderViewHandler>(ViewMapper)
- {
- };
- public static CommandMapper<QRCodeReaderView, QRCodeReaderViewHandler> CommandMapper = new CommandMapper<QRCodeReaderView, QRCodeReaderViewHandler>(ViewCommandMapper)
- {
- };
- public QRCodeReaderViewHandler() : base(PropertyMapper, CommandMapper) { }
- }
- ```
- ```csharp
- using System.Diagnostics;
- using AndroidX.Camera.Core;
- using AndroidX.Camera.Core.ResolutionSelector;
- using AndroidX.Camera.Lifecycle;
- using AndroidX.Camera.View;
- using AndroidX.Core.Content;
- using AndroidX.Lifecycle;
- using Java.Lang;
- using Java.Util.Concurrent;
- using Microsoft.Maui.Handlers;
- using Exception = System.Exception;
- using Size = Android.Util.Size;
- namespace QRCodeScanner;
- public partial class QRCodeReaderViewHandler : ViewHandler<QRCodeReaderView, AndroidQRCodeReaderView>
- {
- private Preview? _cameraPreview;
- private PreviewView _previewView;
- private IExecutorService? cameraExecutor;
- private ICamera? _camera;
- protected override AndroidQRCodeReaderView CreatePlatformView()
- {
- var context = MauiContext?.Context ?? Platform.AppContext;
- _previewView = new PreviewView(context);
- return new AndroidQRCodeReaderView(context, _previewView);
- }
- protected override void ConnectHandler(AndroidQRCodeReaderView platformView)
- {
- base.ConnectHandler(platformView);
- if (MauiContext is not null)
- {
- Connect(MauiContext, platformView.PreviewView);
- }
- }
- public void Connect(IMauiContext mauiContext, PreviewView previewView)
- {
- try
- {
- if (mauiContext.Context is null)
- {
- return;
- }
- cameraExecutor = Executors.NewSingleThreadExecutor();
- var cameraProviderFuture = ProcessCameraProvider.GetInstance(mauiContext.Context);
- if (cameraExecutor is null)
- return;
- var cameraProvider = cameraProviderFuture.Get() as ProcessCameraProvider;
- if (cameraProvider is null)
- return;
- cameraProviderFuture.AddListener(new Runnable(() =>
- {
- var resolutionSelector = new ResolutionSelector.Builder().SetResolutionStrategy(new ResolutionStrategy(boundSize: new Size(1280, 700),
- fallbackRule: ResolutionStrategy.FallbackRuleClosestHigherThenLower))
- .Build();
- _cameraPreview = new Preview.Builder().SetResolutionSelector(resolutionSelector).Build();
- _cameraPreview.SetSurfaceProvider(cameraExecutor, previewView.SurfaceProvider);
- var imageAnalyzer = new ImageAnalysis.Builder()
- .SetBackpressureStrategy(ImageAnalysis.StrategyKeepOnlyLatest)
- .SetResolutionSelector(resolutionSelector)
- .Build();
- var mLkitQrCodeAnalyzer = new MLkitQRCodeAnalyzer();
- imageAnalyzer.SetAnalyzer(cameraExecutor, mLkitQrCodeAnalyzer);
- cameraProvider.UnbindAll();
- var cameraSelector = CameraSelector.DefaultBackCamera;
- var hasCamera = cameraProvider.HasCamera(cameraSelector);
- Debug.WriteLine($"hasCamera: {hasCamera}");
- if (previewView.Context is ILifecycleOwner lifecycleOwner)
- {
- _camera = cameraProvider.BindToLifecycle(lifecycleOwner, cameraSelector, _cameraPreview, imageAnalyzer);
- }
- else if (Platform.CurrentActivity is ILifecycleOwner maLifecycleOwner)
- {
- _camera = cameraProvider.BindToLifecycle(maLifecycleOwner, cameraSelector, _cameraPreview, imageAnalyzer);
- }
- }),
- ContextCompat.GetMainExecutor(mauiContext.Context));
- }
- catch (Exception ex)
- {
- Debug.WriteLine(ex.StackTrace);
- }
- }
- }
- ```
- Camera permissions
- `<uses-permission android:name="android.permission.CAMERA"/>`
- ```csharp
- private async Task CheckAndRequestCameraPermission()
- {
- var status = await Permissions.CheckStatusAsync<Permissions.Camera>();
- if (status != PermissionStatus.Granted)
- {
- status = await Permissions.RequestAsync<Permissions.Camera>();
- if (status != PermissionStatus.Granted)
- {
- await DisplayAlert("Camera Permission Denied", "This app needs access to the camera to scan QR codes.", "OK");
- }
- }
- }
- protected override async void OnAppearing()
- {
- base.OnAppearing();
- await CheckAndRequestCameraPermission();
- }
- ```
- UI
- ```xml
- <?xml version="1.0" encoding="utf-8"?>
- <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
- xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
- xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
- xmlns:local="clr-namespace:QRCodeScanner"
- x:DataType="{x:Type local:MainViewModel}"
- x:Class="QRCodeScanner.MainPage">
- <ContentPage.Resources>
- <toolkit:BoolToObjectConverter x:TypeArguments="x:String"
- x:Key="BoolToStringConverter"
- TrueObject="On"
- FalseObject="Off" />
- </ContentPage.Resources>
- <VerticalStackLayout Spacing="10"
- Padding="20">
- <Label Text="Below is the scanner"
- HorizontalOptions="Center" />
- <local:QRCodeReaderView HorizontalOptions="Fill"
- VerticalOptions="Fill"
- HeightRequest="400"
- WidthRequest="400"
- ResultCommand="{Binding QRResultCommand}"
- IsFlashOn="{Binding IsFlashOn}"
- IsVisible="{Binding IsVisible}"
- x:Name="qrCodeReaderView" />
- <HorizontalStackLayout HorizontalOptions="Center"
- Spacing="20"
- IsVisible="{Binding IsVisible}">
- <Label Text="{Binding IsFlashOn, Source={Reference qrCodeReaderView}, Converter={StaticResource BoolToStringConverter}, StringFormat='Flash {0}'}"
- VerticalOptions="Center"
- VerticalTextAlignment="Center" />
- <Switch IsToggled="{Binding IsFlashOn}" />
- </HorizontalStackLayout>
- <Label HorizontalOptions="Center"
- VerticalOptions="End"
- Margin="0,0,0,20"
- Text="{Binding Result}" />
- </VerticalStackLayout>
- </ContentPage>
- ```
![Screenshot]()
- I have a QR code which needs to read through Google's ML kit for Android since Zxing.MAUI doesnt read it. I followed the code in [ml-kit/vision/barcode-scanning/android](https://developers.google.com/ml-kit/vision/barcode-scanning/android) and [VinayByte/mlkit-qr-code-scan-android-kotlin](https://github.com/VinayByte/mlkit-qr-code-scan-android-kotlin) and also [hjam40/Camera.MAUI](https://github.com/hjam40/Camera.MAUI) I was not able to use Camera.MAUI since it doesnt work for .net 9
- Here is my custom control code, if anyone has an idea why the preview is not showing up that would be a great help!
- ```csharp
- builder.ConfigureMauiHandlers(handlers =>
- {
- handlers.AddHandler<QRCodeReaderView, QRCodeReaderViewHandler>();
- });
- ```
- Custom control
- ```csharp
- public class QRCodeReaderView : View {}
- ```
- ```csharp
- public partial class QRCodeReaderViewHandler
- {
- public static IPropertyMapper<QRCodeReaderView, QRCodeReaderViewHandler> PropertyMapper = new PropertyMapper<QRCodeReaderView, QRCodeReaderViewHandler>(ViewMapper)
- {
- };
- public static CommandMapper<QRCodeReaderView, QRCodeReaderViewHandler> CommandMapper = new CommandMapper<QRCodeReaderView, QRCodeReaderViewHandler>(ViewCommandMapper)
- {
- };
- public QRCodeReaderViewHandler() : base(PropertyMapper, CommandMapper) { }
- }
- ```
- ```csharp
- using System.Diagnostics;
- using AndroidX.Camera.Core;
- using AndroidX.Camera.Core.ResolutionSelector;
- using AndroidX.Camera.Lifecycle;
- using AndroidX.Camera.View;
- using AndroidX.Core.Content;
- using AndroidX.Lifecycle;
- using Java.Lang;
- using Java.Util.Concurrent;
- using Microsoft.Maui.Handlers;
- using Exception = System.Exception;
- using Size = Android.Util.Size;
- namespace QRCodeScanner;
- public partial class QRCodeReaderViewHandler : ViewHandler<QRCodeReaderView, AndroidQRCodeReaderView>
- {
- private Preview? _cameraPreview;
- private PreviewView _previewView;
- private IExecutorService? cameraExecutor;
- private ICamera? _camera;
- protected override AndroidQRCodeReaderView CreatePlatformView()
- {
- var context = MauiContext?.Context ?? Platform.AppContext;
- _previewView = new PreviewView(context);
- return new AndroidQRCodeReaderView(context, _previewView);
- }
- protected override void ConnectHandler(AndroidQRCodeReaderView platformView)
- {
- base.ConnectHandler(platformView);
- if (MauiContext is not null)
- {
- Connect(MauiContext, platformView.PreviewView);
- }
- }
- public void Connect(IMauiContext mauiContext, PreviewView previewView)
- {
- try
- {
- if (mauiContext.Context is null)
- {
- return;
- }
- cameraExecutor = Executors.NewSingleThreadExecutor();
- var cameraProviderFuture = ProcessCameraProvider.GetInstance(mauiContext.Context);
- if (cameraExecutor is null)
- return;
- var cameraProvider = cameraProviderFuture.Get() as ProcessCameraProvider;
- if (cameraProvider is null)
- return;
- cameraProviderFuture.AddListener(new Runnable(() =>
- {
- var resolutionSelector = new ResolutionSelector.Builder().SetResolutionStrategy(new ResolutionStrategy(boundSize: new Size(1280, 700),
- fallbackRule: ResolutionStrategy.FallbackRuleClosestHigherThenLower))
- .Build();
- _cameraPreview = new Preview.Builder().SetResolutionSelector(resolutionSelector).Build();
- _cameraPreview.SetSurfaceProvider(cameraExecutor, previewView.SurfaceProvider);
- var imageAnalyzer = new ImageAnalysis.Builder()
- .SetBackpressureStrategy(ImageAnalysis.StrategyKeepOnlyLatest)
- .SetResolutionSelector(resolutionSelector)
- .Build();
- var mLkitQrCodeAnalyzer = new MLkitQRCodeAnalyzer();
- imageAnalyzer.SetAnalyzer(cameraExecutor, mLkitQrCodeAnalyzer);
- cameraProvider.UnbindAll();
- var cameraSelector = CameraSelector.DefaultBackCamera;
- var hasCamera = cameraProvider.HasCamera(cameraSelector);
- Debug.WriteLine($"hasCamera: {hasCamera}");
- if (previewView.Context is ILifecycleOwner lifecycleOwner)
- {
- _camera = cameraProvider.BindToLifecycle(lifecycleOwner, cameraSelector, _cameraPreview, imageAnalyzer);
- }
- else if (Platform.CurrentActivity is ILifecycleOwner maLifecycleOwner)
- {
- _camera = cameraProvider.BindToLifecycle(maLifecycleOwner, cameraSelector, _cameraPreview, imageAnalyzer);
- }
- }),
- ContextCompat.GetMainExecutor(mauiContext.Context));
- }
- catch (Exception ex)
- {
- Debug.WriteLine(ex.StackTrace);
- }
- }
- }
- ```
- Camera permissions
- `<uses-permission android:name="android.permission.CAMERA"/>`
- ```csharp
- private async Task CheckAndRequestCameraPermission()
- {
- var status = await Permissions.CheckStatusAsync<Permissions.Camera>();
- if (status != PermissionStatus.Granted)
- {
- status = await Permissions.RequestAsync<Permissions.Camera>();
- if (status != PermissionStatus.Granted)
- {
- await DisplayAlert("Camera Permission Denied", "This app needs access to the camera to scan QR codes.", "OK");
- }
- }
- }
- protected override async void OnAppearing()
- {
- base.OnAppearing();
- await CheckAndRequestCameraPermission();
- }
- ```
- UI
- ```xml
- <?xml version="1.0" encoding="utf-8"?>
- <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
- xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
- xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
- xmlns:local="clr-namespace:QRCodeScanner"
- x:DataType="{x:Type local:MainViewModel}"
- x:Class="QRCodeScanner.MainPage">
- <ContentPage.Resources>
- <toolkit:BoolToObjectConverter x:TypeArguments="x:String"
- x:Key="BoolToStringConverter"
- TrueObject="On"
- FalseObject="Off" />
- </ContentPage.Resources>
- <VerticalStackLayout Spacing="10"
- Padding="20">
- <Label Text="Below is the scanner"
- HorizontalOptions="Center" />
- <local:QRCodeReaderView HorizontalOptions="Fill"
- VerticalOptions="Fill"
- HeightRequest="400"
- WidthRequest="400"
- ResultCommand="{Binding QRResultCommand}"
- IsFlashOn="{Binding IsFlashOn}"
- IsVisible="{Binding IsVisible}"
- x:Name="qrCodeReaderView" />
- <HorizontalStackLayout HorizontalOptions="Center"
- Spacing="20"
- IsVisible="{Binding IsVisible}">
- <Label Text="{Binding IsFlashOn, Source={Reference qrCodeReaderView}, Converter={StaticResource BoolToStringConverter}, StringFormat='Flash {0}'}"
- VerticalOptions="Center"
- VerticalTextAlignment="Center" />
- <Switch IsToggled="{Binding IsFlashOn}" />
- </HorizontalStackLayout>
- <Label HorizontalOptions="Center"
- VerticalOptions="End"
- Margin="0,0,0,20"
- Text="{Binding Result}" />
- </VerticalStackLayout>
- </ContentPage>
- ```
- ### Edit:
- On further analysis through Logcat I found the issue to be as following
- ```log
- Unable to configure camera Camera@461d7c2[id=0]
- java.util.concurrent.TimeoutException: Future[androidx.camera.core.impl.utils.futures.ListFuture@4c0973e] is not done within 5000 ms.
- ```
- The possible solution to set [`android:hardwareAccelerated="true"` application level or MainActivity level](https://stackoverflow.com/questions/78777877/android-camerax-unable-to-configure-camera) is not working too.
- 
#1: Initial revision
Android CameraPreview not rendering for MLKit barcode analyis on MAUI custom control
I have a QR code which needs to read through Google's ML kit for Android since Zxing.MAUI doesnt read it. I followed the code in [ml-kit/vision/barcode-scanning/android](https://developers.google.com/ml-kit/vision/barcode-scanning/android) and [VinayByte/mlkit-qr-code-scan-android-kotlin](https://github.com/VinayByte/mlkit-qr-code-scan-android-kotlin) and also [hjam40/Camera.MAUI](https://github.com/hjam40/Camera.MAUI) I was not able to use Camera.MAUI since it doesnt work for .net 9 Here is my custom control code, if anyone has an idea why the preview is not showing up that would be a great help! ```csharp builder.ConfigureMauiHandlers(handlers => { handlers.AddHandler<QRCodeReaderView, QRCodeReaderViewHandler>(); }); ``` Custom control ```csharp public class QRCodeReaderView : View {} ``` ```csharp public partial class QRCodeReaderViewHandler { public static IPropertyMapper<QRCodeReaderView, QRCodeReaderViewHandler> PropertyMapper = new PropertyMapper<QRCodeReaderView, QRCodeReaderViewHandler>(ViewMapper) { }; public static CommandMapper<QRCodeReaderView, QRCodeReaderViewHandler> CommandMapper = new CommandMapper<QRCodeReaderView, QRCodeReaderViewHandler>(ViewCommandMapper) { }; public QRCodeReaderViewHandler() : base(PropertyMapper, CommandMapper) { } } ``` ```csharp using System.Diagnostics; using AndroidX.Camera.Core; using AndroidX.Camera.Core.ResolutionSelector; using AndroidX.Camera.Lifecycle; using AndroidX.Camera.View; using AndroidX.Core.Content; using AndroidX.Lifecycle; using Java.Lang; using Java.Util.Concurrent; using Microsoft.Maui.Handlers; using Exception = System.Exception; using Size = Android.Util.Size; namespace QRCodeScanner; public partial class QRCodeReaderViewHandler : ViewHandler<QRCodeReaderView, AndroidQRCodeReaderView> { private Preview? _cameraPreview; private PreviewView _previewView; private IExecutorService? cameraExecutor; private ICamera? _camera; protected override AndroidQRCodeReaderView CreatePlatformView() { var context = MauiContext?.Context ?? Platform.AppContext; _previewView = new PreviewView(context); return new AndroidQRCodeReaderView(context, _previewView); } protected override void ConnectHandler(AndroidQRCodeReaderView platformView) { base.ConnectHandler(platformView); if (MauiContext is not null) { Connect(MauiContext, platformView.PreviewView); } } public void Connect(IMauiContext mauiContext, PreviewView previewView) { try { if (mauiContext.Context is null) { return; } cameraExecutor = Executors.NewSingleThreadExecutor(); var cameraProviderFuture = ProcessCameraProvider.GetInstance(mauiContext.Context); if (cameraExecutor is null) return; var cameraProvider = cameraProviderFuture.Get() as ProcessCameraProvider; if (cameraProvider is null) return; cameraProviderFuture.AddListener(new Runnable(() => { var resolutionSelector = new ResolutionSelector.Builder().SetResolutionStrategy(new ResolutionStrategy(boundSize: new Size(1280, 700), fallbackRule: ResolutionStrategy.FallbackRuleClosestHigherThenLower)) .Build(); _cameraPreview = new Preview.Builder().SetResolutionSelector(resolutionSelector).Build(); _cameraPreview.SetSurfaceProvider(cameraExecutor, previewView.SurfaceProvider); var imageAnalyzer = new ImageAnalysis.Builder() .SetBackpressureStrategy(ImageAnalysis.StrategyKeepOnlyLatest) .SetResolutionSelector(resolutionSelector) .Build(); var mLkitQrCodeAnalyzer = new MLkitQRCodeAnalyzer(); imageAnalyzer.SetAnalyzer(cameraExecutor, mLkitQrCodeAnalyzer); cameraProvider.UnbindAll(); var cameraSelector = CameraSelector.DefaultBackCamera; var hasCamera = cameraProvider.HasCamera(cameraSelector); Debug.WriteLine($"hasCamera: {hasCamera}"); if (previewView.Context is ILifecycleOwner lifecycleOwner) { _camera = cameraProvider.BindToLifecycle(lifecycleOwner, cameraSelector, _cameraPreview, imageAnalyzer); } else if (Platform.CurrentActivity is ILifecycleOwner maLifecycleOwner) { _camera = cameraProvider.BindToLifecycle(maLifecycleOwner, cameraSelector, _cameraPreview, imageAnalyzer); } }), ContextCompat.GetMainExecutor(mauiContext.Context)); } catch (Exception ex) { Debug.WriteLine(ex.StackTrace); } } } ``` Camera permissions `<uses-permission android:name="android.permission.CAMERA"/>` ```csharp private async Task CheckAndRequestCameraPermission() { var status = await Permissions.CheckStatusAsync<Permissions.Camera>(); if (status != PermissionStatus.Granted) { status = await Permissions.RequestAsync<Permissions.Camera>(); if (status != PermissionStatus.Granted) { await DisplayAlert("Camera Permission Denied", "This app needs access to the camera to scan QR codes.", "OK"); } } } protected override async void OnAppearing() { base.OnAppearing(); await CheckAndRequestCameraPermission(); } ``` UI ```xml <?xml version="1.0" encoding="utf-8"?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit" xmlns:local="clr-namespace:QRCodeScanner" x:DataType="{x:Type local:MainViewModel}" x:Class="QRCodeScanner.MainPage"> <ContentPage.Resources> <toolkit:BoolToObjectConverter x:TypeArguments="x:String" x:Key="BoolToStringConverter" TrueObject="On" FalseObject="Off" /> </ContentPage.Resources> <VerticalStackLayout Spacing="10" Padding="20"> <Label Text="Below is the scanner" HorizontalOptions="Center" /> <local:QRCodeReaderView HorizontalOptions="Fill" VerticalOptions="Fill" HeightRequest="400" WidthRequest="400" ResultCommand="{Binding QRResultCommand}" IsFlashOn="{Binding IsFlashOn}" IsVisible="{Binding IsVisible}" x:Name="qrCodeReaderView" /> <HorizontalStackLayout HorizontalOptions="Center" Spacing="20" IsVisible="{Binding IsVisible}"> <Label Text="{Binding IsFlashOn, Source={Reference qrCodeReaderView}, Converter={StaticResource BoolToStringConverter}, StringFormat='Flash {0}'}" VerticalOptions="Center" VerticalTextAlignment="Center" /> <Switch IsToggled="{Binding IsFlashOn}" /> </HorizontalStackLayout> <Label HorizontalOptions="Center" VerticalOptions="End" Margin="0,0,0,20" Text="{Binding Result}" /> </VerticalStackLayout> </ContentPage> ``` ![Screenshot]()