app scaffold
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
/// 扫码能力的对外 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<ScanResult> 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<bool> isModeSupported(ScanMode mode) async {
|
||||
try {
|
||||
return await _api.isModeSupported(mode);
|
||||
} on PlatformException {
|
||||
return false;
|
||||
} on MissingPluginException {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user