.NET MAUIでバーコードリーダーを実装するためにZXingを利用することがあると思います。
しかし、iOSで利用するとカメラが停止しないことがあります。当記事では、その対処方法を紹介していきます。
Android・Windowsでは、再表示にカメラが動作しない問題があります。問題の詳細は以下で紹介していますので確認してみてください。
紹介環境
当記事は以下の環境で作成しています。
開発環境
- Visual Studio 2022
- .Net 8
パッケージ
- ZXing.Net.Maui(パッケージのバージョン:0.4.0)
- ZXing.Net.Maui.Controls(パッケージのバージョン:0.4.0)
動作環境
- iOS 17.3.1
問題の動作について
問題の動作について説明していきます。
まずはZXingでカメラを動作させます。以下のようにカメラが起動していることが分かります。
このまま別の画面に移動すると、以下のようにカメラが動作しています。この画面にはカメラ機能が存在しないため、本来カメラは停止します。
実装方法
実装方法を説明していきます。当記事では「CameraBarcodeReaderView」をカスタムしハンドラーを利用していきます。
ファイル構成について
以下のようにクラスファイルを用意します。
各ファイルの内容について
「CameraBarcodeReaderView」のカスタマイズは以下のようになります。「IsCameraEnabled」はカメラの動作状況を制御しています。
using ZXing.Net.Maui.Controls;
namespace CustomIosZXing.CustomControls;
public class IosCameraBarcodeReaderView : CameraBarcodeReaderView
{
public static readonly BindableProperty IsCameraEnabledProperty =
BindableProperty.Create(
nameof(IsCameraEnabled),
typeof(bool),
typeof(IosCameraBarcodeReaderView),
true);
/// <summary>
/// カメラの動作状況(iOS用)
/// </summary>
public bool IsCameraEnabled
{
get
{
return (bool)GetValue(IsCameraEnabledProperty);
}
set
{
SetValue(IsCameraEnabledProperty, value);
}
}
}
iOSのカメラを停止するために以下のマッパーをPage(ContentPage など)のコンストラクタに実装します。「IsCameraEnabled」にfalseを設定すると、カメラが停止するようになっています。
CameraBarcodeReaderViewHandler.CameraBarcodeReaderViewMapper.Add(
nameof(IosCameraBarcodeReaderView.IsCameraEnabled),
(handler, virtualView) =>
{
if (handler is IosCameraBarcodeReaderViewHandler customHandler)
{
if (virtualView is IosCameraBarcodeReaderView customView)
{
if (!customView.IsCameraEnabled)
{
customHandler.StopCamera();
}
}
}
});
ハンドラーは以下のようになります。内容はiOSのカメラ停止になっています。
using ZXing.Net.Maui;
#if IOS
using UIKit;
#endif
namespace CustomIosZXing.CustomControls;
public class IosCameraBarcodeReaderViewHandler : CameraBarcodeReaderViewHandler
{
#if IOS
protected override void DisconnectHandler(UIView nativeView)
{
base.DisconnectHandler(nativeView);
}
#endif
public void StopCamera()
{
#if IOS
DisconnectHandler(new UIView());
#endif
}
}
カスタマイズしたハンドラーを利用するために、MauiProgramに対して以下の内容を記載します。
using CustomIosZXing.CustomControls;
using Microsoft.Extensions.Logging;
using ZXing.Net.Maui.Controls;
namespace CustomIosZXing;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
})
.ConfigureMauiHandlers(handlers =>
{
#if IOS || ANDROID
// ハンドラーを実装します。
handlers.AddHandler<IosCameraBarcodeReaderView, IosCameraBarcodeReaderViewHandler>();
#endif
})
// ZXingを利用するために必要になります。
.UseBarcodeReader();
#if DEBUG
builder.Logging.AddDebug();
#endif
return builder.Build();
}
}
利用方法
ContentPageでの利用方法は以下のようになります。以下の利用方法ではAndroid・Windowsの問題にも対策しています。
<?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"
x:Class="CustomIosZXing.Pages.ZXingPage"
Title="ZXingPage">
<Grid x:Name="gridBarcode">
<Grid.RowDefinitions>
<RowDefinition Height="1*"></RowDefinition>
<RowDefinition Height="100"></RowDefinition>
</Grid.RowDefinitions>
<Label
x:Name="lblText"
Grid.Row="1"
Text="" />
</Grid>
</ContentPage>
以下では、画面から離れる時(OnDisappearing)に「IsCameraEnabled」に対してfalseを設定しています。そうすることで画面から離れる時にカメラが停止されます。
using CustomIosZXing.CustomControls;
using ZXing.Net.Maui;
namespace CustomIosZXing.Pages;
public partial class ZXingPage : ContentPage
{
private IosCameraBarcodeReaderView _cameraBarcodeReader;
public ZXingPage()
{
InitializeComponent();
// カメラ停止用のマッパー
CameraBarcodeReaderViewHandler.CameraBarcodeReaderViewMapper.Add(
nameof(IosCameraBarcodeReaderView.IsCameraEnabled),
(handler, virtualView) =>
{
if (handler is IosCameraBarcodeReaderViewHandler customHandler)
{
if (virtualView is IosCameraBarcodeReaderView customView)
{
if (!customView.IsCameraEnabled)
{
customHandler.StopCamera();
}
}
}
});
}
/// <summary>
/// 画面表示時
/// </summary>
protected override void OnAppearing()
{
base.OnAppearing();
this.lblText.Text = "";
/*
* IosCameraBarcodeReaderViewを追加します。
*/
_cameraBarcodeReader = new IosCameraBarcodeReaderView();
_cameraBarcodeReader.Options = new BarcodeReaderOptions
{
Formats = BarcodeFormats.TwoDimensional,
};
_cameraBarcodeReader.BarcodesDetected += _cameraBarcodeReader_BarcodesDetected;
this.gridBarcode.Add(_cameraBarcodeReader, row: 0);
}
private void _cameraBarcodeReader_BarcodesDetected(object? sender, BarcodeDetectionEventArgs e)
{
/*
* スレッドが異なるためエラーになります。
* そのエラーを回避するために「this.Dispatcher.Dispatch()」を利用します。
*/
this.Dispatcher.Dispatch(() =>
{
foreach (BarcodeResult barcodeResult in e.Results)
{
this.lblText.Text = barcodeResult.Value;
}
});
}
/// <summary>
/// 画面から離れる時
/// </summary>
protected override void OnDisappearing()
{
// カメラを停止します。
_cameraBarcodeReader.IsCameraEnabled = false;
this.gridBarcode.Remove(_cameraBarcodeReader);
base.OnDisappearing();
}
}
おわりに
.NET MAUIで二次元バーコードの読み込みにZXingを利用していましたが、iOSでカメラが停止しなかったので困っていました・・・
当記事の内容を利用することで対応することができました。同じような境遇の方の役に立てば幸いです。