Flutter设备唯一标识插件ad_hoc_ident的使用
Flutter设备唯一标识插件ad_hoc_ident的使用
ad_hoc_ident
插件提供了从NFC标签和MRZ文档中提取标识符的功能。本指南将帮助您了解如何在Flutter应用中使用该插件。
特性
ad_hoc_ident
包包含三个域包。每个域包都有相应的实现包:
-
主域:
ad_hoc_ident
- 哈希算法:
ad_hoc_ident_util_crypto
- 可读伪名生成:
ad_hoc_ident_util_readable_pseudonym
- 后台隔离:
ad_hoc_ident_util_flutter
-
NFC域:
ad_hoc_ident_nfc
- 基于流的输入:
ad_hoc_ident_nfc_scanner_nfc_manager
- 基于轮询的输入:
ad_hoc_ident_nfc_scanner_flutter_nfc_kit
- EMV卡号检测:
ad_hoc_ident_nfc_detect_emv
-
OCR域:
ad_hoc_ident_ocr
- 基本相机输入:
ad_hoc_ident_ocr_camera
- 基于camerawesome包的相机输入:
ad_hoc_ident_ocr_camerawesome
- 基于google_mlkit_text_recognition的文本提取:
ad_hoc_ident_ocr_extract_google
- 基于flutter_vision(Tesseract)的文本提取:
ad_hoc_ident_ocr_extract_tesseract
- 基于mrz_parser的MRZ文档类型和编号检测:
ad_hoc_ident_ocr_parse_mrz
开始使用
在您的应用的pubspec.yaml
文件中添加主域包和其他需要的功能包:
dependencies:
ad_hoc_ident: ^x.x.x
ad_hoc_ident_nfc: ^x.x.x
ad_hoc_ident_ocr: ^x.x.x
...
使用示例
以下是一个完整的示例代码,展示了如何使用ad_hoc_ident
插件来获取设备的唯一标识符。
import 'dart:async';
import 'dart:convert';
import 'dart:math';
import 'package:ad_hoc_ident/ad_hoc_ident.dart';
import 'package:ad_hoc_ident_nfc/ad_hoc_ident_nfc.dart';
import 'package:ad_hoc_ident_nfc_detect_emv/ad_hoc_ident_nfc_detect_emv.dart';
import 'package:ad_hoc_ident_nfc_scanner_nfc_manager/ad_hoc_ident_nfc_scanner_nfc_manager.dart';
import 'package:ad_hoc_ident_ocr/ad_hoc_ident_ocr.dart';
import 'package:ad_hoc_ident_ocr_camerawesome/ad_hoc_ident_ocr_camerawesome.dart';
import 'package:ad_hoc_ident_ocr_extract_google/ad_hoc_ident_ocr_extract_google.dart';
import 'package:ad_hoc_ident_ocr_parse_mrz/ad_hoc_ident_ocr_parse_mrz.dart';
import 'package:ad_hoc_ident_util_crypto/ad_hoc_ident_util_crypto.dart';
import 'package:ad_hoc_ident_util_flutter/ad_hoc_ident_util_flutter.dart';
import 'package:ad_hoc_ident_util_readable_pseudonym/ad_hoc_ident_util_readable_pseudonym.dart';
import 'package:async/async.dart';
import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';
import 'ad_hoc_identity_display.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
[@override](/user/override)
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final MemoryPseudonymStorage _storage = PseudonymStorage.memory();
late final NfcScanner _nfcScanner;
late final AdHocIdentityScanner<OcrImage> _ocrScanner;
late final OcrTextExtractor _extractor;
late final StreamController<OcrImage> _cameraStreamController;
Stream<AdHocIdentity?>? _identityStream;
bool _showCamera = true;
void _toggleCamera() => setState(() {
_showCamera = !_showCamera;
});
[@override](/user/override)
void initState() {
final securePepper = _initPepper();
final encrypter = WordPseudonymEncrypter(
innerEncrypter: CryptoAdHocIdentityEncrypter.sha512,
storage: _storage)
// 在生产代码中,你可能希望添加一个盐并混淆类型
// .secureType()
// .withSalt((identity) => 'someSecurelyCreatedOrFetchedSalt')
.withPepper(securePepper);
final nfcDetector = AdHocIdentityDetector.fromList([
// 保持UID检测器在首位,
// 因为它会重启NFC适配器,
// 导致之前的所有适配器重新评估。
NfcDetectorUid(restartTimeout: const Duration(seconds: 1)),
NfcDetectorEmv(),
]);
_nfcScanner = _initNfcManagerScanner(nfcDetector, encrypter);
// _nfcScanner = _initNfcKitScanner(nfcDetector, encrypter);
// 如果在启动时NFC不可用,则此实现需要重新启动应用。
// 在生产环境中,你可能希望在NFC状态变为可用之前重复检查其状态。
_nfcScanner.isAvailable().then((available) {
if (available) {
_nfcScanner.start();
}
});
_cameraStreamController = StreamController.broadcast();
// 将Google提取器包装在一个Future中,以便更容易地切换引擎。
Future.value(GoogleOcrTextExtractor()).then(
// TesseractOcrTextExtractor.fromFile().then(
(extractor) {
_extractor = extractor;
_ocrScanner = AdHocIdentityScanner(
inputStream: _cameraStreamController.stream,
// 使用后台检测器将OCR卸载到另一个隔离区
detector: BackgroundIdentityDetector(
OcrIdentityDetector(
extractor: extractor,
parser: MrzTextIdentityParser(),
),
),
debounce: true,
encrypter: encrypter,
);
final stream = StreamGroup.merge([
_nfcScanner.stream,
_ocrScanner.stream.whereNotNull(),
]).distinct().shareValue().asBroadcastStream();
if (mounted) {
setState(() {
_identityStream = stream;
});
}
},
);
super.initState();
}
NfcScanner _initNfcManagerScanner(AdHocIdentityDetector<NfcTag> detector,
AdHocIdentityEncrypter encrypter) {
final unhandledScanner = NfcManagerNfcScanner(
detector: detector,
preferredTagTypes: [
PlatformTagType.isoDep, // 优先选择isoDep以支持EMV功能
],
encrypter: encrypter);
return unhandledScanner.handle<FirstScanException>(
FirstScanException.createDefaultHandler(unhandledScanner));
}
// NfcScanner _initNfcKitScanner(AdHocIdentityDetector<NfcTag> detector,
// AdHocIdentityEncrypter encrypter) {
// final unhandledScanner = NfcKitNfcScanner.repeatPolling(
// detector: detector,
// idleDuration: const Duration(milliseconds: 100),
// encrypter: encrypter);
// return unhandledScanner.handle<FirstScanException>(
// (error, stackTrace) {
// //忽略错误
// },
// );
// }
String _initPepper() {
// 在生产环境中,
// 应将pepper管理在安全存储或外部API中
final rng = Random.secure();
final List<int> securePepperBytes = [];
for (var i = 0; i < 32; i++) {
final byte = rng.nextInt(256);
securePepperBytes.add(byte);
}
return base64Encode(securePepperBytes);
}
[@override](/user/override)
void dispose() {
_cameraStreamController.close();
_nfcScanner.stop();
_extractor.close();
super.dispose();
}
[@override](/user/override)
Widget build(BuildContext context) {
const waitingMessage = '请扫描NFC标签或护照。'
'在扫描NFC标签前,请关闭相机顶部右侧按钮。'
'在相机激活时使用NFC可能导致某些设备崩溃。';
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Ad hoc ident'),
actions: [
Padding(
padding: const EdgeInsets.all(5),
child: _RestartButton(
restart: () async {
final available = await _nfcScanner.isAvailable();
if (available) {
_nfcScanner.restart();
}
},
),
),
Padding(
padding: const EdgeInsets.all(5),
child: IconButton(
onPressed: _toggleCamera,
icon: Icon(_showCamera ? Icons.videocam_off : Icons.videocam),
),
),
],
),
body: Padding(
padding: const EdgeInsets.all(5),
child: Flex(
direction: MediaQuery.orientationOf(context) == Orientation.portrait
? Axis.vertical
: Axis.horizontal,
children: [
Expanded(
flex: 2,
child: Card(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(5)),
side: BorderSide(
color: Colors.black,
width: 2,
),
),
clipBehavior: Clip.antiAlias,
child: AspectRatio(
aspectRatio: 4 / 3,
child: _showCamera
? CamerawesomeAdapter(
onImage: _cameraStreamController.add)
// ? CameraView(
// onImage: _cameraStreamController.add,
// imageFormatGroupName: 'jpeg', // 'nv21',
// )
: TextButton.icon(
onPressed: _toggleCamera,
label: const Text('启用相机'),
icon: const Icon(Icons.videocam),
),
),
),
),
const SizedBox.square(
dimension: 10,
),
Flexible(
flex: 1,
child: Center(
child: Padding(
padding: const EdgeInsets.all(15),
child: _identityStream != null
? AdHocIdentityDisplay.fromStream(
stream: _identityStream!,
nullMessage: '未检测到身份。',
waitingMessage: waitingMessage,
errorBuilder: (error, _) => Text(error.toString()),
)
: const Text(waitingMessage),
),
),
),
],
),
),
),
);
}
}
class _RestartButton extends StatelessWidget {
final Future<void> Function() restart;
const _RestartButton({required this.restart});
[@override](/user/override)
Widget build(BuildContext context) {
return IconButton(
onPressed: () async {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text('尝试重新连接NFC...'),
));
await restart();
},
icon: const Icon(Icons.nfc),
);
}
}
更多关于Flutter设备唯一标识插件ad_hoc_ident的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter设备唯一标识插件ad_hoc_ident的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter项目中使用ad_hoc_ident
插件来获取设备唯一标识的示例代码。这个插件提供了一种生成设备唯一标识符的方法,可以用于广告跟踪、用户识别等场景。
首先,你需要在你的pubspec.yaml
文件中添加ad_hoc_ident
依赖:
dependencies:
flutter:
sdk: flutter
ad_hoc_ident: ^x.y.z # 请将x.y.z替换为当前最新版本号
然后运行flutter pub get
来安装依赖。
接下来,在你的Flutter应用中,你可以使用以下代码来获取设备的唯一标识符:
import 'package:flutter/material.dart';
import 'package:ad_hoc_ident/ad_hoc_ident.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String? deviceIdentifier;
@override
void initState() {
super.initState();
_getDeviceIdentifier();
}
Future<void> _getDeviceIdentifier() async {
try {
String id = await AdHocIdent.getAdHocId;
setState(() {
deviceIdentifier = id;
});
} catch (e) {
print("Error getting device identifier: $e");
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Device Identifier Example'),
),
body: Center(
child: Text(
deviceIdentifier ?? 'Loading...',
style: TextStyle(fontSize: 24),
),
),
),
);
}
}
在这个示例中,我们做了以下几件事:
- 在
pubspec.yaml
中添加ad_hoc_ident
依赖。 - 在主应用文件中(通常是
main.dart
),导入ad_hoc_ident
包。 - 创建一个Flutter应用,并在
initState
方法中调用_getDeviceIdentifier
函数来获取设备唯一标识符。 - 使用
AdHocIdent.getAdHocId
异步方法来获取设备标识符,并在获取成功后更新UI。
请注意,设备唯一标识符的生成可能会受到各种因素的影响,比如设备的重置、操作系统的更新等,这可能会导致标识符的变化。因此,在使用这类标识符时,请确保你了解这些潜在的限制。
此外,确保在实际发布应用时遵守相关的隐私政策和法规,特别是在处理用户数据时。