/// 扫码能力的对外 API。来源:conti-docs/07-native-integration.md。 /// /// **调用方只允许 import 这个文件**,不允许直接 import `src/generated/` 里的 /// 生成代码(07 §使用规则)。调用方包括 `feature_scan` 和 `core_webview` 的 /// JSBridge——后者正是 01 里「`core_*` 允许依赖 `native_*`」这条例外存在的 /// 原因。 /// /// 本包按 01 的硬约束**不依赖仓库内任何其他包**(连 `core_foundation` 也不), /// 所以这里抛的是包内自定义的 [NativeScanException];转成统一错误体系里的 /// `NativeException` 由调用方完成。 library; import 'package:flutter/services.dart'; import 'src/generated/scan_api.g.dart'; export 'src/generated/scan_api.g.dart' show ScanMode, ScanOptions, ScanResult; /// 扫码失败的错误码。 /// /// 取值与 12 的 `NativeException.code` 对齐,调用方可以直接透传。 abstract final class NativeScanErrorCode { /// 用户主动取消。 /// /// 这不是异常流程,调用方通常应当静默返回,**不弹错误提示、不上报**。 static const String cancelled = 'CANCELLED'; /// 相机权限被拒绝。 static const String permissionDenied = 'PERMISSION_DENIED'; /// 能力暂时不可用(相机被占用、初始化失败等)。 static const String unavailable = 'UNAVAILABLE'; /// 当前平台没有实现。 /// /// 见 07 §「OHOS 后续演进」:**不允许静默返回空值或占位假数据**—— /// 静默返回会让"这个平台其实没实现"的问题一直藏到用户手里。 static const String unsupportedPlatform = 'UNSUPPORTED_PLATFORM'; /// 超时。 static const String timeout = 'TIMEOUT'; } /// 扫码相关的异常。 class NativeScanException implements Exception { /// [code] 取自 [NativeScanErrorCode]。 const NativeScanException(this.code, this.message); /// 稳定错误码。 final String code; /// 面向开发者的描述。**不要直接展示给用户**——文案由调用方按 12 的 /// `ErrorPresenter` 决定。 final String message; /// 是否是用户主动取消。 bool get isCancelled => code == NativeScanErrorCode.cancelled; @override String toString() => 'NativeScanException($code): $message'; } /// 扫码。 class NativeScan { /// [api] 仅供测试注入;生产走默认实例。 NativeScan({ScanHostApi? api}) : _api = api ?? ScanHostApi(); final ScanHostApi _api; /// 打开扫码页并等待一次结果。 /// /// 用户取消时抛 [NativeScanException](`code == CANCELLED`)而不是返回 null—— /// 「取消」和「扫到了空字符串」必须能区分开。 Future startScan(ScanOptions options) async { try { return await _api.startScan(options); } on PlatformException catch (e) { // 原生异常类型不外泄(07 §使用规则)。 throw NativeScanException(e.code, e.message ?? '扫码失败'); } on MissingPluginException { throw const NativeScanException(NativeScanErrorCode.unsupportedPlatform, '当前平台未实现扫码能力'); } } /// 当前平台是否支持指定识别类型。 /// /// 调用方应当先查这个再决定要不要显示入口,而不是等 [startScan] 抛错—— /// 车牌识别的技术路径尚未确定(07 待确认项),首版可能只有部分平台支持。 Future isModeSupported(ScanMode mode) async { try { return await _api.isModeSupported(mode); } on PlatformException { return false; } on MissingPluginException { return false; } } }