如何在Flutter中使用二维码数据保存手机联系人
Flutter 解析二维码并保存联系人到本地
1. 添加依赖
在pubspec.yaml中添加以下依赖:
dependencies: flutter: sdk: flutter qr_code_scanner: ^1.0.1 # 二维码扫描 contacts_service: ^0.6.3 # 联系人操作 permission_handler: ^10.2.0 # 权限申请
执行flutter pub get完成依赖安装。
2. 配置平台权限
- Android:在
android/app/src/main/AndroidManifest.xml中添加权限声明:
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_CONTACTS" /> <uses-permission android:name="android.permission.READ_CONTACTS" />
- iOS:在
ios/Runner/Info.plist中添加权限描述:
<key>NSCameraUsageDescription</key> <string>需要使用相机扫描二维码</string> <key>NSContactsUsageDescription</key> <string>需要访问通讯录保存联系人</string>
3. 实现核心逻辑
以下是完整的功能实现代码:
import 'package:flutter/material.dart'; import 'package:qr_code_scanner/qr_code_scanner.dart'; import 'package:contacts_service/contacts_service.dart'; import 'package:permission_handler/permission_handler.dart'; class QrContactSaver extends StatefulWidget { const QrContactSaver({super.key}); @override State<QrContactSaver> createState() => _QrContactSaverState(); } class _QrContactSaverState extends State<QrContactSaver> { final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); QRViewController? controller; bool _hasPermissions = false; @override void initState() { super.initState(); _checkPermissions(); } // 检查并申请必要权限 Future<void> _checkPermissions() async { final cameraStatus = await Permission.camera.status; final contactsStatus = await Permission.contacts.status; if (!cameraStatus.isGranted || !contactsStatus.isGranted) { final result = await [Permission.camera, Permission.contacts].request(); setState(() { _hasPermissions = result[Permission.camera]!.isGranted && result[Permission.contacts]!.isGranted; }); } else { setState(() { _hasPermissions = true; }); } } // 解析vCard格式的二维码数据 Contact? _parseVCard(String vCardData) { final lines = vCardData.split('\n'); String? name; String? phone; for (var line in lines) { if (line.startsWith('FN:')) { name = line.substring(3); } else if (line.startsWith('TEL:')) { phone = line.substring(4).replaceAll(RegExp(r'[^0-9+]'), ''); } } if (name != null && phone != null) { return Contact( displayName: name, phones: [Item(label: 'mobile', value: phone)], ); } return null; } // 保存联系人到本地通讯录 Future<void> _saveContact(Contact contact) async { try { await ContactsService.addContact(contact); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('联系人保存成功')), ); } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('保存失败: ${e.toString()}')), ); } } } @override Widget build(BuildContext context) { if (!_hasPermissions) { return Scaffold( appBar: AppBar(title: const Text('扫码保存联系人')), body: Center( child: ElevatedButton( onPressed: _checkPermissions, child: const Text('申请权限'), ), ), ); } return Scaffold( appBar: AppBar(title: const Text('扫码保存联系人')), body: Column( children: [ Expanded( flex: 5, child: QRView( key: qrKey, onQRViewCreated: (controller) { this.controller = controller; controller.scannedDataStream.listen((scanData) { controller.pauseCamera(); final contact = _parseVCard(scanData.code!); if (contact != null) { _saveContact(contact); } else { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('二维码不是有效的联系人数据')), ); } } // 2秒后恢复扫描,可根据需求调整 Future.delayed(const Duration(seconds: 2), () { controller.resumeCamera(); }); }); }, ), ), const Expanded( flex: 1, child: Center( child: Text('将二维码对准扫描框'), ), ), ], ), ); } @override void dispose() { controller?.dispose(); super.dispose(); } }
关键说明
- 二维码格式要求:代码默认解析标准vCard格式的二维码(包含
FN:姓名字段和TEL:电话字段),如果是自定义格式,需修改_parseVCard方法的解析逻辑。 - 权限前置:必须先获取相机和通讯录权限,否则无法完成扫描或保存操作。
- 异常处理:代码包含基础错误捕获,可根据业务需求扩展更多异常场景的处理。
内容的提问来源于stack exchange,提问作者Nihar
相关产品推荐
相关产品推荐

