如何在Flutter中获取通讯录权限?附permission_handler代码示例
正确获取通讯录权限的实现方案
要顺利使用contact_services操作通讯录,你需要完成平台权限配置并完善权限请求逻辑,具体步骤如下:
1. 平台权限配置
Android
在android/app/src/main/AndroidManifest.xml中添加通讯录权限声明(按需选择读/写权限):
<!-- 读取通讯录权限 --> <uses-permission android:name="android.permission.READ_CONTACTS" /> <!-- 写入通讯录权限(如需修改通讯录) --> <uses-permission android:name="android.permission.WRITE_CONTACTS" />
iOS
在ios/Runner/Info.plist中添加权限用途描述,系统请求权限时会展示这段文字:
<key>NSContactsUsageDescription</key> <string>需要访问您的通讯录来管理联系人信息</string>
2. 完善权限请求逻辑
你的现有代码实现了基础权限请求,但缺少对不同权限状态的后续处理(比如用户永久拒绝时的引导),且需确保权限通过后再调用contact_services。修改后的完整代码如下:
import 'package:permission_handler/permission_handler.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; import 'calendar.dart'; import 'info.dart'; // 导入contact_services插件 import 'package:contact_services/contact_services.dart'; void main() => runApp(const PageScaffoldApp()); class PageScaffoldApp extends StatelessWidget { const PageScaffoldApp({super.key}); @override Widget build(BuildContext context) { return const CupertinoApp( theme: CupertinoThemeData(brightness: Brightness.light), home: HomeScreen(), debugShowCheckedModeBanner: false, ); } } class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @override State<HomeScreen> createState() => _HomeScreenState(); } class _HomeScreenState extends State<HomeScreen> { List<Widget> data = [CalendarScreen(), const InfoScreen()]; bool _contactsPermissionGranted = false; @override void initState() { super.initState(); _askPermissions(); } Future<void> _askPermissions() async { PermissionStatus permissionStatus = await _getContactPermission(); setState(() { _contactsPermissionGranted = permissionStatus == PermissionStatus.granted; }); if (_contactsPermissionGranted) { // 权限通过后初始化通讯录服务 _initContactServices(); } else if (permissionStatus == PermissionStatus.permanentlyDenied) { // 用户永久拒绝,引导去设置开启 _showOpenSettingsDialog(); } } Future<PermissionStatus> _getContactPermission() async { PermissionStatus permission = await Permission.contacts.status; if (permission != PermissionStatus.granted && permission != PermissionStatus.permanentlyDenied) { PermissionStatus permissionStatus = await Permission.contacts.request(); return permissionStatus; } else { return permission; } } void _initContactServices() async { // 示例:获取通讯录联系人 try { List<Contact> contacts = await ContactsService.getContacts(); print("获取到${contacts.length}个联系人"); // 这里可以处理联系人数据 } catch (e) { print("获取联系人失败: $e"); } } void _showOpenSettingsDialog() { showCupertinoDialog( context: context, builder: (context) => CupertinoAlertDialog( title: const Text("通讯录权限被拒绝"), content: const Text("请前往应用设置开启通讯录权限,否则无法使用相关功能"), actions: [ CupertinoDialogAction( child: const Text("取消"), onPressed: () => Navigator.pop(context), ), CupertinoDialogAction( child: const Text("去设置"), onPressed: () { Navigator.pop(context); openAppSettings(); }, ), ], ), ); } @override Widget build(BuildContext context) { return CupertinoTabScaffold( tabBar: CupertinoTabBar( items: const <BottomNavigationBarItem>[ BottomNavigationBarItem( icon: Icon(CupertinoIcons.calendar_circle), activeIcon: Icon(CupertinoIcons.calendar_circle_fill), label: 'Calendar', ), BottomNavigationBarItem( icon: Icon(CupertinoIcons.info_circle), activeIcon: Icon(CupertinoIcons.info_circle_fill), label: 'Info', ), ], ), tabBuilder: (BuildContext context, int index) { return CupertinoTabView( builder: (BuildContext context) { return data[index]; }, ); }, ); } }
关键说明
- 权限状态处理:新增
permanentlyDenied状态的处理逻辑,引导用户前往设置开启权限,避免用户误操作后无法再次触发权限请求。 - 权限验证时机:仅在权限通过后初始化
contact_services,避免无权限时调用相关功能抛出异常。 - 平台配置:必须在Android和iOS的配置文件中添加对应权限声明和描述,否则权限请求会直接失败。
内容的提问来源于stack exchange,提问作者M.K. Mandawar
相关产品推荐
相关产品推荐

