如何在Xamarin.Forms中基于ZXing实现跨平台读取本地条码二维码图片
跨平台实现本地图片二维码读取方案
前置依赖安装
首先确保你已经在项目中安装了对应的NuGet包:
- 共享项目:安装
ZXing.Net - Android 平台项目:安装
ZXing.Net.Bindings.XamarinAndroid - iOS 平台项目:安装
ZXing.Net.Bindings.XamarinIOS - UWP 平台项目:安装
ZXing.Net.Bindings.Windows.Universal
实现跨平台服务
因为不同平台的图片处理API不同,我们用Xamarin.Forms自带的DependencyService来封装各平台的解码逻辑。
1. 共享项目定义公共接口
在共享项目中新增接口:
public interface IBarcodeDecoderService { Task<ZXing.Result> DecodeImageAsync(string filePath, ZXing.BarcodeFormat? targetFormat = null, KeyValuePair<ZXing.DecodeHintType, object>[] extraHints = null); }
注意:代码中的命名空间请替换为你项目实际使用的命名空间。
2. 各平台实现接口
Android 端实现
在Android项目中新增服务类,记得添加依赖注册特性:
[assembly: Dependency(typeof(YourNamespace.Droid.BarcodeDecoderService))] namespace YourNamespace.Droid { public class BarcodeDecoderService : IBarcodeDecoderService { public async Task<ZXing.Result> DecodeImageAsync(string filePath, ZXing.BarcodeFormat? targetFormat = null, KeyValuePair<ZXing.DecodeHintType, object>[] extraHints = null) { // 加载本地图片为Bitmap var bitmap = await BitmapFactory.DecodeFileAsync(filePath); // 转成ZXing可用的LuminanceSource var source = new ZXing.Mobile.RGBLuminanceSource(bitmap, bitmap.Width, bitmap.Height); var binaryBitmap = new ZXing.BinaryBitmap(new ZXing.Common.HybridBinarizer(source)); // 初始化解码器 var reader = new ZXing.MultiFormatReader(); var hints = new Dictionary<ZXing.DecodeHintType, object>(); if (targetFormat.HasValue) { hints.Add(ZXing.DecodeHintType.POSSIBLE_FORMATS, new List<ZXing.BarcodeFormat> { targetFormat.Value }); } // 添加高优先级识别提示,提高识别成功率 hints.Add(ZXing.DecodeHintType.TRY_HARDER, true); if (extraHints != null) { foreach (var hint in extraHints) { hints[hint.Key] = hint.Value; } } reader.Hints = hints; return reader.decode(binaryBitmap); } } }
iOS 端实现
在iOS项目中新增服务类:
[assembly: Dependency(typeof(YourNamespace.iOS.BarcodeDecoderService))] namespace YourNamespace.iOS { public class BarcodeDecoderService : IBarcodeDecoderService { public async Task<ZXing.Result> DecodeImageAsync(string filePath, ZXing.BarcodeFormat? targetFormat = null, KeyValuePair<ZXing.DecodeHintType, object>[] extraHints = null) { var uiImage = UIImage.FromFile(filePath); var source = new ZXing.Mobile.RGBLuminanceSource(uiImage.CGImage); var binaryBitmap = new ZXing.BinaryBitmap(new ZXing.Common.HybridBinarizer(source)); // 解码器初始化逻辑和Android端一致 var reader = new ZXing.MultiFormatReader(); var hints = new Dictionary<ZXing.DecodeHintType, object>(); if (targetFormat.HasValue) { hints.Add(ZXing.DecodeHintType.POSSIBLE_FORMATS, new List<ZXing.BarcodeFormat> { targetFormat.Value }); } hints.Add(ZXing.DecodeHintType.TRY_HARDER, true); if (extraHints != null) { foreach (var hint in extraHints) { hints[hint.Key] = hint.Value; } } reader.Hints = hints; return reader.decode(binaryBitmap); } } }
UWP 端实现
在UWP项目中新增服务类:
[assembly: Dependency(typeof(YourNamespace.UWP.BarcodeDecoderService))] namespace YourNamespace.UWP { public class BarcodeDecoderService : IBarcodeDecoderService { public async Task<ZXing.Result> DecodeImageAsync(string filePath, ZXing.BarcodeFormat? targetFormat = null, KeyValuePair<ZXing.DecodeHintType, object>[] extraHints = null) { var file = await StorageFile.GetFileFromPathAsync(filePath); using (var stream = await file.OpenAsync(FileAccessMode.Read)) { var bitmap = new WriteableBitmap(1, 1); await bitmap.SetSourceAsync(stream); var source = new ZXing.PresentationCore.WriteableBitmapLuminanceSource(bitmap); var binaryBitmap = new ZXing.BinaryBitmap(new ZXing.Common.HybridBinarizer(source)); // 解码器初始化逻辑和Android端一致 var reader = new ZXing.MultiFormatReader(); var hints = new Dictionary<ZXing.DecodeHintType, object>(); if (targetFormat.HasValue) { hints.Add(ZXing.DecodeHintType.POSSIBLE_FORMATS, new List<ZXing.BarcodeFormat> { targetFormat.Value }); } hints.Add(ZXing.DecodeHintType.TRY_HARDER, true); if (extraHints != null) { foreach (var hint in extraHints) { hints[hint.Key] = hint.Value; } } reader.Hints = hints; return reader.decode(binaryBitmap); } } } }
原有业务代码修改
你原来的调用代码可以直接替换为调用依赖服务的逻辑:
string file = ""; var filePickerOptions = new PickOptions { PickerTitle = "Select Barcode Image", FileTypes = FilePickerFileType.Images }; var result = await FilePicker.PickAsync(filePickerOptions); if (result != null) { file = result.FullPath; // 调用跨平台解码服务 var decoder = DependencyService.Get<IBarcodeDecoderService>(); var res = await decoder.DecodeImageAsync(file, BarcodeFormat.QR_CODE); if (res != null) { Console.WriteLine(res.Text); } else { Console.WriteLine("未识别到二维码内容"); } }
注意事项
- Android端需要提前申请
READ_EXTERNAL_STORAGE权限,Android 13及以上需要申请READ_MEDIA_IMAGES权限 - iOS端需要在Info.plist中添加
NSPhotoLibraryUsageDescription权限说明 - UWP端需要在Package.appxmanifest中开启
图片库访问权限 - 针对清晰度低、角度倾斜的二维码,可以额外添加
DecodeHintType.PURE_BARCODE等hint提高识别率
内容的提问来源于stack exchange,提问作者Kikanye
相关产品推荐
相关产品推荐

