在这里插入图片描述

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net


🔍 一、第三方库概述与应用场景

📱 1.1 为什么需要通讯录管理?

通讯录是移动设备中最基础也是最重要的数据之一。几乎每个社交应用、CRM 系统、电话拨号器都需要访问用户的联系人信息。一个完善的通讯录管理系统可以让用户轻松管理联系人,提高工作效率。

想象一下这样的场景:用户打开一个社交应用,想要邀请朋友加入,应用自动读取通讯录并匹配已有用户;用户在 CRM 系统中添加客户信息,可以直接从通讯录导入;用户使用电话拨号器,可以快速搜索并拨打联系人电话。这些都是通讯录管理功能的典型应用。

📋 1.2 flutter_contacts 是什么?

flutter_contacts 是 Flutter 生态中功能最完善的通讯录管理插件,提供了完整的联系人增删改查功能。它支持联系人详细信息的管理,包括姓名、电话、邮箱、地址、组织等,并且支持分组管理和数据监听。

🎯 1.3 核心功能特性

功能特性 详细说明 OpenHarmony 支持
联系人读取 获取联系人列表和详情 ✅ 完全支持
联系人创建 创建新联系人 ✅ 完全支持
联系人更新 更新联系人信息 ✅ 完全支持
联系人删除 删除单个或多个联系人 ✅ 完全支持
分组管理 管理联系人分组 ✅ 完全支持
数据监听 监听通讯录变化 ✅ 完全支持

💡 1.4 典型应用场景

通讯录应用:完整的联系人管理功能。

社交应用:读取通讯录匹配好友。

CRM 系统:导入客户联系人信息。

电话拨号器:快速搜索并拨打电话。


🏗️ 二、系统架构设计

📐 2.1 整体架构

┌─────────────────────────────────────────────────────────┐
│                    UI 层 (展示层)                        │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │  联系人列表 │  │  详情页面   │  │  编辑页面   │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
├─────────────────────────────────────────────────────────┤
│                  服务层 (业务逻辑)                       │
│  ┌─────────────────────────────────────────────────┐   │
│  │            ContactsService                       │   │
│  │  • 权限请求                                      │   │
│  │  • 联系人 CRUD                                   │   │
│  │  • 搜索过滤                                      │   │
│  │  • 分组管理                                      │   │
│  └─────────────────────────────────────────────────┘   │
├─────────────────────────────────────────────────────────┤
│                  基础设施层 (底层实现)                   │
│  ┌─────────────────────────────────────────────────┐   │
│  │          flutter_contacts 库                     │   │
│  │  • Contact - 联系人模型                          │   │
│  │  • Name - 姓名模型                               │   │
│  │  • Phone - 电话模型                              │   │
│  │  • Email - 邮箱模型                              │   │
│  └─────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────┘

📊 2.2 数据模型设计

/// 联系人数据模型
class Contact {
  /// 联系人 ID
  final String id;
  
  /// 姓名
  final Name name;
  
  /// 电话列表
  final List<Phone> phones;
  
  /// 邮箱列表
  final List<Email> emails;
  
  /// 地址列表
  final List<Address> addresses;

  const Contact({
    required this.id,
    required this.name,
    this.phones = const [],
    this.emails = const [],
    this.addresses = const [],
  });
}

/// 姓名模型
class Name {
  final String first;
  final String last;
  final String middle;
  final String nickname;

  const Name({
    this.first = '',
    this.last = '',
    this.middle = '',
    this.nickname = '',
  });
}

📦 三、项目配置与依赖安装

📥 3.1 添加依赖

打开项目根目录下的 pubspec.yaml 文件,添加以下配置:

dependencies:
  flutter:
    sdk: flutter
  
  # flutter_contacts - 通讯录管理插件
  flutter_contacts:
    git:
      url: https://atomgit.com/openharmony-sig/flutter_contacts

配置说明

  • 使用 git 方式引用开源鸿蒙适配的 flutter_contacts 仓库
  • url:指定 AtomGit 托管的仓库地址
  • 本项目基于 flutter_contacts@1.1.7+1 开发,适配 Flutter 3.7.12-ohos-1.0.6

⚠️ 重要:对于 OpenHarmony 平台,必须使用 git 方式引用适配版本,不能直接使用 pub.dev 的版本号。

🔧 3.2 下载依赖

配置完成后,需要在项目根目录执行以下命令下载依赖:

flutter pub get

🔐 3.3 权限配置

通讯录访问需要读写权限,在 OpenHarmony 平台上需要配置:

ohos/entry/src/main/module.json5:

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.READ_CONTACTS",
        "reason": "$string:contacts_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.WRITE_CONTACTS",
        "reason": "$string:contacts_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      }
    ]
  }
}

ohos/entry/src/main/resources/base/element/string.json:

{
  "string": [
    {
      "name": "contacts_reason",
      "value": "读取和写入联系人信息"
    }
  ]
}

⚠️ 3.4 OpenHarmony 权限等级说明

通讯录权限属于 system_basic 级别权限,默认应用权限等级是 normal。要使用通讯录权限,需要修改应用的权限等级。

修改 Debug 签名模板

找到 SDK 目录下的签名模板文件:

{SDK路径}/openharmony/toolchains/lib/UnsgnedDebugProfileTemplate.json

修改以下内容:

{
  "bundle-info": {
    "apl": "system_basic"
  },
  "acls": {
    "allowed-acls": [
      "ohos.permission.READ_CONTACTS",
      "ohos.permission.WRITE_CONTACTS"
    ]
  },
  "permissions": {
    "restricted-permissions": [
      "ohos.permission.READ_CONTACTS",
      "ohos.permission.WRITE_CONTACTS"
    ]
  }
}

⚠️ 重要:修改签名模板后需要在 DevEco Studio 中重新签名才能生效。


🛠️ 四、核心 API 详解

🎬 4.1 权限请求

// 请求通讯录权限
bool granted = await FlutterContacts.requestPermission(readonly: false);

// readonly: true - 只请求读取权限
// readonly: false - 请求读写权限

📋 4.2 获取联系人列表

// 获取联系人列表
final contacts = await FlutterContacts.getContacts(
  withProperties: true,    // 包含电话、邮箱等属性
  withThumbnail: true,     // 包含缩略图
  withPhoto: false,        // 不包含高清照片
  sorted: true,            // 按名称排序
);

// 获取单个联系人详情
final contact = await FlutterContacts.getContact(
  contactId,
  withProperties: true,
  withThumbnail: true,
  withPhoto: true,
);

➕ 4.3 创建联系人

final newContact = Contact(
  name: Name(
    first: '张',
    last: '三',
  ),
  phones: [Phone('13800138000', label: PhoneLabel.mobile)],
  emails: [Email('zhangsan@example.com', label: EmailLabel.work)],
);

final savedContact = await FlutterContacts.insertContact(newContact);

✏️ 4.4 更新联系人

contact.phones.add(Phone('13900139000', label: PhoneLabel.home));
final updatedContact = await FlutterContacts.updateContact(contact);

🗑️ 4.5 删除联系人

// 删除单个联系人
await FlutterContacts.deleteContact(contact);

// 批量删除联系人
await FlutterContacts.deleteContacts(contacts);

📊 4.6 数据模型

模型 说明
Contact 联系人主模型
Name 结构化姓名
Phone 电话号码
Email 电子邮件
Address 邮政地址
Organization 组织/公司信息
Website 网站
Event 事件/生日
Note 备注

📝 五、完整示例代码

下面是一个完整的智能通讯录管理系统示例:

import 'package:flutter/material.dart';
import 'package:flutter_contacts/flutter_contacts.dart';

void main() {
  runApp(const ContactsApp());
}

class ContactsApp extends StatelessWidget {
  const ContactsApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '通讯录管理',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF10B981)),
        useMaterial3: true,
      ),
      home: const MainPage(),
    );
  }
}

class MainPage extends StatefulWidget {
  const MainPage({super.key});

  
  State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  int _currentIndex = 0;

  final List<Widget> _pages = [
    const ContactsListPage(),
    const GroupsPage(),
    const SettingsPage(),
  ];

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: _pages[_currentIndex],
      bottomNavigationBar: NavigationBar(
        selectedIndex: _currentIndex,
        onDestinationSelected: (index) {
          setState(() => _currentIndex = index);
        },
        destinations: const [
          NavigationDestination(icon: Icon(Icons.contacts), label: '联系人'),
          NavigationDestination(icon: Icon(Icons.group), label: '分组'),
          NavigationDestination(icon: Icon(Icons.settings), label: '设置'),
        ],
      ),
    );
  }
}

// ============ 联系人列表页面 ============

class ContactsListPage extends StatefulWidget {
  const ContactsListPage({super.key});

  
  State<ContactsListPage> createState() => _ContactsListPageState();
}

class _ContactsListPageState extends State<ContactsListPage> {
  List<Contact>? _contacts;
  List<Contact>? _filteredContacts;
  bool _permissionDenied = false;
  bool _isLoading = true;
  final TextEditingController _searchController = TextEditingController();

  
  void initState() {
    super.initState();
    _fetchContacts();
  }

  
  void dispose() {
    _searchController.dispose();
    super.dispose();
  }

  Future<void> _fetchContacts() async {
    setState(() {
      _isLoading = true;
      _permissionDenied = false;
    });

    bool granted = await FlutterContacts.requestPermission(readonly: false);
    if (!granted) {
      setState(() {
        _permissionDenied = true;
        _isLoading = false;
      });
      return;
    }

    try {
      final contacts = await FlutterContacts.getContacts(
        withProperties: true,
        withThumbnail: true,
        sorted: true,
      );
      setState(() {
        _contacts = contacts;
        _filteredContacts = contacts;
        _isLoading = false;
      });
    } catch (e) {
      setState(() => _isLoading = false);
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('获取联系人失败: $e')),
        );
      }
    }
  }

  void _filterContacts(String query) {
    if (query.isEmpty) {
      setState(() => _filteredContacts = _contacts);
    } else {
      setState(() {
        _filteredContacts = _contacts?.where((contact) {
          final name = contact.displayName.toLowerCase();
          final phone = contact.phones.isNotEmpty
              ? contact.phones.first.number
              : '';
          return name.contains(query.toLowerCase()) ||
              phone.contains(query);
        }).toList();
      });
    }
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('通讯录'),
        actions: [
          IconButton(
            icon: const Icon(Icons.refresh),
            onPressed: _fetchContacts,
          ),
        ],
      ),
      body: _buildBody(),
      floatingActionButton: FloatingActionButton(
        onPressed: () => _navigateToAddContact(),
        child: const Icon(Icons.add),
      ),
    );
  }

  Widget _buildBody() {
    if (_isLoading) {
      return const Center(child: CircularProgressIndicator());
    }

    if (_permissionDenied) {
      return _buildPermissionDenied();
    }

    return Column(
      children: [
        _buildSearchBar(),
        Expanded(
          child: _filteredContacts == null || _filteredContacts!.isEmpty
              ? _buildEmptyState()
              : _buildContactsList(),
        ),
      ],
    );
  }

  Widget _buildPermissionDenied() {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Icon(Icons.perm_contact_cal, size: 64, color: Colors.grey.shade400),
          const SizedBox(height: 16),
          const Text('需要通讯录权限'),
          const SizedBox(height: 16),
          ElevatedButton(
            onPressed: _fetchContacts,
            child: const Text('重新请求权限'),
          ),
        ],
      ),
    );
  }

  Widget _buildSearchBar() {
    return Padding(
      padding: const EdgeInsets.all(16),
      child: TextField(
        controller: _searchController,
        decoration: InputDecoration(
          hintText: '搜索联系人',
          prefixIcon: const Icon(Icons.search),
          suffixIcon: _searchController.text.isNotEmpty
              ? IconButton(
                  icon: const Icon(Icons.clear),
                  onPressed: () {
                    _searchController.clear();
                    _filterContacts('');
                  },
                )
              : null,
          border: OutlineInputBorder(
            borderRadius: BorderRadius.circular(12),
          ),
          filled: true,
          fillColor: Colors.grey.shade100,
        ),
        onChanged: _filterContacts,
      ),
    );
  }

  Widget _buildEmptyState() {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Icon(Icons.contact_page_outlined, size: 64, color: Colors.grey.shade400),
          const SizedBox(height: 16),
          Text(
            _searchController.text.isEmpty ? '暂无联系人' : '未找到匹配的联系人',
            style: TextStyle(color: Colors.grey.shade500),
          ),
        ],
      ),
    );
  }

  Widget _buildContactsList() {
    return ListView.builder(
      itemCount: _filteredContacts!.length,
      itemBuilder: (context, index) {
        final contact = _filteredContacts![index];
        return _buildContactTile(contact);
      },
    );
  }

  Widget _buildContactTile(Contact contact) {
    String subtitle = '';
    if (contact.phones.isNotEmpty) {
      subtitle = contact.phones.first.number;
    } else if (contact.emails.isNotEmpty) {
      subtitle = contact.emails.first.address;
    }

    return ListTile(
      leading: CircleAvatar(
        backgroundColor: const Color(0xFF10B981).withOpacity(0.1),
        child: Text(
          contact.displayName.isNotEmpty ? contact.displayName[0] : '?',
          style: const TextStyle(
            color: Color(0xFF10B981),
            fontWeight: FontWeight.bold,
          ),
        ),
      ),
      title: Text(
        contact.displayName.isNotEmpty ? contact.displayName : '未知联系人',
        style: const TextStyle(fontWeight: FontWeight.w500),
      ),
      subtitle: subtitle.isNotEmpty ? Text(subtitle) : null,
      trailing: const Icon(Icons.chevron_right),
      onTap: () => _navigateToContactDetail(contact),
    );
  }

  Future<void> _navigateToAddContact() async {
    final result = await Navigator.push<bool>(
      context,
      MaterialPageRoute(builder: (_) => const AddContactPage()),
    );
    if (result == true) {
      _fetchContacts();
    }
  }

  Future<void> _navigateToContactDetail(Contact contact) async {
    final fullContact = await FlutterContacts.getContact(
      contact.id,
      withProperties: true,
      withThumbnail: true,
    );
    if (fullContact != null && mounted) {
      Navigator.push(
        context,
        MaterialPageRoute(builder: (_) => ContactDetailPage(fullContact)),
      );
    }
  }
}

// ============ 联系人详情页面 ============

class ContactDetailPage extends StatelessWidget {
  final Contact contact;

  const ContactDetailPage(this.contact, {super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(contact.displayName),
        actions: [
          IconButton(
            icon: const Icon(Icons.edit),
            onPressed: () {},
          ),
          IconButton(
            icon: const Icon(Icons.delete),
            onPressed: () => _deleteContact(context),
          ),
        ],
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            _buildHeader(),
            const SizedBox(height: 24),
            if (contact.phones.isNotEmpty) ...[
              _buildSection('电话', _buildPhones()),
              const SizedBox(height: 16),
            ],
            if (contact.emails.isNotEmpty) ...[
              _buildSection('邮箱', _buildEmails()),
              const SizedBox(height: 16),
            ],
            if (contact.addresses.isNotEmpty) ...[
              _buildSection('地址', _buildAddresses()),
              const SizedBox(height: 16),
            ],
          ],
        ),
      ),
    );
  }

  Widget _buildHeader() {
    return Center(
      child: Column(
        children: [
          CircleAvatar(
            radius: 48,
            backgroundColor: const Color(0xFF10B981).withOpacity(0.1),
            child: Text(
              contact.displayName.isNotEmpty ? contact.displayName[0] : '?',
              style: const TextStyle(
                fontSize: 32,
                color: Color(0xFF10B981),
                fontWeight: FontWeight.bold,
              ),
            ),
          ),
          const SizedBox(height: 16),
          Text(
            contact.displayName,
            style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
          ),
          if (contact.name.first.isNotEmpty || contact.name.last.isNotEmpty)
            Text(
              '${contact.name.first} ${contact.name.last}',
              style: TextStyle(fontSize: 14, color: Colors.grey[600]),
            ),
        ],
      ),
    );
  }

  Widget _buildSection(String title, Widget content) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          title,
          style: const TextStyle(
            fontSize: 14,
            fontWeight: FontWeight.bold,
            color: Color(0xFF10B981),
          ),
        ),
        const SizedBox(height: 8),
        content,
      ],
    );
  }

  Widget _buildPhones() {
    return Column(
      children: contact.phones.map((phone) {
        return ListTile(
          contentPadding: EdgeInsets.zero,
          leading: const Icon(Icons.phone),
          title: Text(phone.number),
          subtitle: Text(_getPhoneLabel(phone.label)),
          trailing: IconButton(
            icon: const Icon(Icons.copy),
            onPressed: () {},
          ),
        );
      }).toList(),
    );
  }

  Widget _buildEmails() {
    return Column(
      children: contact.emails.map((email) {
        return ListTile(
          contentPadding: EdgeInsets.zero,
          leading: const Icon(Icons.email),
          title: Text(email.address),
          subtitle: Text(_getEmailLabel(email.label)),
        );
      }).toList(),
    );
  }

  Widget _buildAddresses() {
    return Column(
      children: contact.addresses.map((address) {
        return ListTile(
          contentPadding: EdgeInsets.zero,
          leading: const Icon(Icons.location_on),
          title: Text(address.address),
          subtitle: Text(_getAddressLabel(address.label)),
        );
      }).toList(),
    );
  }

  String _getPhoneLabel(PhoneLabel label) {
    switch (label) {
      case PhoneLabel.mobile:
        return '手机';
      case PhoneLabel.home:
        return '住宅';
      case PhoneLabel.work:
        return '工作';
      default:
        return '其他';
    }
  }

  String _getEmailLabel(EmailLabel label) {
    switch (label) {
      case EmailLabel.home:
        return '住宅';
      case EmailLabel.work:
        return '工作';
      default:
        return '其他';
    }
  }

  String _getAddressLabel(AddressLabel label) {
    switch (label) {
      case AddressLabel.home:
        return '住宅';
      case AddressLabel.work:
        return '工作';
      default:
        return '其他';
    }
  }

  void _deleteContact(BuildContext context) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('删除联系人'),
        content: Text('确定要删除 ${contact.displayName} 吗?'),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('取消'),
          ),
          ElevatedButton(
            onPressed: () async {
              await FlutterContacts.deleteContact(contact);
              if (context.mounted) {
                Navigator.pop(context);
                Navigator.pop(context);
              }
            },
            child: const Text('删除'),
          ),
        ],
      ),
    );
  }
}

// ============ 添加联系人页面 ============

class AddContactPage extends StatefulWidget {
  const AddContactPage({super.key});

  
  State<AddContactPage> createState() => _AddContactPageState();
}

class _AddContactPageState extends State<AddContactPage> {
  final _formKey = GlobalKey<FormState>();
  final _firstNameController = TextEditingController();
  final _lastNameController = TextEditingController();
  final _phoneController = TextEditingController();
  final _emailController = TextEditingController();
  bool _isSaving = false;

  
  void dispose() {
    _firstNameController.dispose();
    _lastNameController.dispose();
    _phoneController.dispose();
    _emailController.dispose();
    super.dispose();
  }

  Future<void> _saveContact() async {
    if (!_formKey.currentState!.validate()) return;

    setState(() => _isSaving = true);

    try {
      final newContact = Contact(
        name: Name(
          first: _firstNameController.text,
          last: _lastNameController.text,
        ),
        phones: _phoneController.text.isNotEmpty
            ? [Phone(_phoneController.text, label: PhoneLabel.mobile)]
            : [],
        emails: _emailController.text.isNotEmpty
            ? [Email(_emailController.text, label: EmailLabel.work)]
            : [],
      );

      await FlutterContacts.insertContact(newContact);

      if (mounted) {
        Navigator.pop(context, true);
      }
    } catch (e) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('保存失败: $e')),
        );
      }
    } finally {
      setState(() => _isSaving = false);
    }
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('添加联系人'),
        actions: [
          TextButton(
            onPressed: _isSaving ? null : _saveContact,
            child: const Text('保存'),
          ),
        ],
      ),
      body: Form(
        key: _formKey,
        child: ListView(
          padding: const EdgeInsets.all(16),
          children: [
            _buildSectionHeader('姓名'),
            Row(
              children: [
                Expanded(
                  child: TextFormField(
                    controller: _firstNameController,
                    decoration: const InputDecoration(
                      labelText: '姓',
                      border: OutlineInputBorder(),
                    ),
                    validator: (value) {
                      if (value == null || value.isEmpty) {
                        return '请输入姓';
                      }
                      return null;
                    },
                  ),
                ),
                const SizedBox(width: 16),
                Expanded(
                  child: TextFormField(
                    controller: _lastNameController,
                    decoration: const InputDecoration(
                      labelText: '名',
                      border: OutlineInputBorder(),
                    ),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 24),
            _buildSectionHeader('联系方式'),
            TextFormField(
              controller: _phoneController,
              decoration: const InputDecoration(
                labelText: '电话',
                prefixIcon: Icon(Icons.phone),
                border: OutlineInputBorder(),
              ),
              keyboardType: TextInputType.phone,
            ),
            const SizedBox(height: 16),
            TextFormField(
              controller: _emailController,
              decoration: const InputDecoration(
                labelText: '邮箱',
                prefixIcon: Icon(Icons.email),
                border: OutlineInputBorder(),
              ),
              keyboardType: TextInputType.emailAddress,
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildSectionHeader(String title) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 12),
      child: Text(
        title,
        style: const TextStyle(
          fontSize: 14,
          fontWeight: FontWeight.bold,
          color: Color(0xFF10B981),
        ),
      ),
    );
  }
}

// ============ 分组页面 ============

class GroupsPage extends StatelessWidget {
  const GroupsPage({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('分组'),
      ),
      body: ListView(
        children: [
          _buildGroupItem('家人', 5, Colors.red),
          _buildGroupItem('朋友', 12, Colors.blue),
          _buildGroupItem('同事', 8, Colors.green),
          _buildGroupItem('客户', 15, Colors.orange),
        ],
      ),
    );
  }

  Widget _buildGroupItem(String name, int count, Color color) {
    return ListTile(
      leading: CircleAvatar(
        backgroundColor: color.withOpacity(0.1),
        child: Icon(Icons.group, color: color),
      ),
      title: Text(name),
      trailing: Text('$count 人'),
      onTap: () {},
    );
  }
}

// ============ 设置页面 ============

class SettingsPage extends StatelessWidget {
  const SettingsPage({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('设置'),
      ),
      body: ListView(
        children: [
          ListTile(
            title: const Text('默认排序'),
            subtitle: const Text('按姓名排序'),
            trailing: const Icon(Icons.chevron_right),
          ),
          ListTile(
            title: const Text('显示选项'),
            subtitle: const Text('显示电话号码'),
            trailing: const Icon(Icons.chevron_right),
          ),
          const Divider(),
          ListTile(
            title: const Text('导入联系人'),
            trailing: const Icon(Icons.chevron_right),
          ),
          ListTile(
            title: const Text('导出联系人'),
            trailing: const Icon(Icons.chevron_right),
          ),
          const Divider(),
          ListTile(
            title: const Text('关于'),
            subtitle: const Text('版本 1.0.0'),
          ),
        ],
      ),
    );
  }
}

🏆 六、最佳实践与注意事项

⚠️ 6.1 权限处理最佳实践

提前请求:在使用通讯录功能前先请求权限。

友好提示:权限被拒绝时,告知用户功能受限的原因。

引导设置:权限被永久拒绝时,引导用户去设置页面。

🔐 6.2 OpenHarmony 平台特殊说明

权限等级:通讯录权限属于 system_basic 级别,需要修改签名模板。

签名配置:修改签名模板后必须在 DevEco Studio 中重新签名。

数据安全:处理联系人数据时注意用户隐私保护。

📱 6.3 常见问题处理

权限请求失败:检查签名模板是否正确配置。

联系人获取失败:确保权限已授予,检查设备通讯录是否为空。

保存失败:检查是否有写入权限,确保数据格式正确。


📌 七、总结

本文通过一个完整的智能通讯录管理系统案例,深入讲解了 flutter_contacts 第三方库的使用方法与最佳实践:

权限请求:使用 requestPermission 请求通讯录权限。

联系人读取:使用 getContactsgetContact 获取联系人列表和详情。

联系人创建:使用 insertContact 创建新联系人。

联系人更新:使用 updateContact 更新联系人信息。

联系人删除:使用 deleteContactdeleteContacts 删除联系人。

掌握这些技巧,你就能构建出专业级的通讯录管理功能,满足各种联系人管理需求。


参考资料

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐