鸿蒙联系人管理开发指南

2025-06-28 22:50:59
110次阅读
0个评论

概述

本指南将详细介绍如何在鸿蒙应用中实现联系人管理功能,包括添加、查询、更新、删除联系人等核心操作,以及权限申请、UI界面选择等高级功能。

1. 联系人管理简介

鸿蒙系统通过 @ohos.contact 模块提供了完整的联系人管理能力,这个模块就像是一个功能强大的联系人管理工具包,为开发者提供了丰富的接口和功能。开发者可以轻松实现:

  • 基础操作:增加、删除、更新、查询联系人信息,满足应用的基本需求
  • 高级查询:通过电话号码、邮箱地址等关键信息快速搜索和定位联系人
  • UI交互:调用系统原生的联系人选择界面,提供统一的用户体验
  • 特殊功能:管理"我的名片"信息、判断联系人类型和状态等高级特性

就像管理一个智能化的电子通讯录,系统提供了完整的API工具箱,让你的应用能够与用户的联系人数据进行安全、高效、便捷的交互。无论是简单的通讯录应用,还是复杂的客户关系管理系统,都可以基于这些接口构建出功能丰富的联系人管理功能。

1.1 模块特点

  • 安全性:严格的权限控制机制,保护用户隐私数据
  • 完整性:覆盖联系人管理的全生命周期操作
  • 易用性:简洁明了的API设计,降低开发难度
  • 兼容性:与系统原生联系人应用完美集成

2. 权限申请

联系人数据是用户的重要隐私信息,鸿蒙系统对此实施了严格的权限管控。在开发联系人相关功能时,必须遵循权限最小化原则,只申请应用确实需要的权限。

2.1 权限类型说明

鸿蒙联系人管理主要涉及两个核心权限:

  • READ_CONTACTS(读取联系人权限):允许应用读取用户的联系人信息,包括姓名、电话号码、邮箱等
  • WRITE_CONTACTS(写入联系人权限):允许应用添加、修改、删除联系人信息

这两个权限都属于 system_basic 级别的敏感权限,需要用户明确授权才能使用。

2.2 必需权限配置

在使用联系人功能前,必须在应用的 module.json5 配置文件中声明相应权限。这是权限申请的第一步,也是必不可少的步骤:

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

2.3 动态权限申请

仅在配置文件中声明权限是不够的,应用还需要在运行时动态向用户申请权限。这是鸿蒙系统保护用户隐私的重要机制,确保用户对权限授予有充分的知情权和控制权。

import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
import { BusinessError } from '@ohos.base';

/**
 * 动态申请联系人相关权限
 * 这个函数会弹出系统权限对话框,用户可以选择允许或拒绝
 * @returns Promise<boolean> 返回权限申请结果
 */
async function requestContactsPermissions(): Promise<boolean> {
  // 创建权限管理器实例
  const atManager = abilityAccessCtrl.createAtManager();
  
  // 定义需要申请的权限列表
  const permissions: Array<string> = [
    'ohos.permission.READ_CONTACTS',    // 读取联系人权限
    'ohos.permission.WRITE_CONTACTS'    // 写入联系人权限
  ];
  
  try {
    // 向用户申请权限,会弹出系统权限对话框
    const result = await atManager.requestPermissionsFromUser(
      getContext(this) as common.UIAbilityContext, 
      permissions
    );
    
    // 检查权限授予结果
    // authResults数组中,0表示授权成功,-1表示用户拒绝
    const allGranted = result.authResults.every(result => result === 0);
    if (allGranted) {
      console.log('联系人权限申请成功,可以使用联系人功能');
      return true;
    } else {
      console.log('用户拒绝了部分或全部权限,某些功能将无法使用');
      return false;
    }
  } catch (err) {
    console.error(`权限申请过程中发生错误: ${err.message}`);
    return false;
  }
}

/**
 * 检查权限状态
 * 在执行敏感操作前,建议先检查权限状态
 */
async function checkContactsPermissions(): Promise<boolean> {
  const atManager = abilityAccessCtrl.createAtManager();
  
  try {
    // 获取应用的访问令牌ID
    const bundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
    const tokenId = bundleInfo.appInfo.accessTokenId;
    
    // 检查读取权限
    const readPermission = await atManager.checkAccessToken(tokenId, 'ohos.permission.READ_CONTACTS');
    // 检查写入权限  
    const writePermission = await atManager.checkAccessToken(tokenId, 'ohos.permission.WRITE_CONTACTS');
    
    return readPermission === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED && 
           writePermission === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
  } catch (err) {
    console.error(`检查权限状态失败: ${err.message}`);
    return false;
  }
}

3. 导入模块

在开始使用联系人管理功能之前,需要导入相关的系统模块。这些模块为我们提供了联系人操作、错误处理和上下文管理的能力。

// 导入联系人管理核心模块,提供所有联系人相关的API
import contact from '@ohos.contact';

// 导入业务错误处理模块,用于捕获和处理API调用过程中的异常
import { BusinessError } from '@ohos.base';

// 导入应用能力通用模块,提供应用上下文等基础功能
import common from '@ohos.app.ability.common';

// 导入权限管理模块,用于动态申请和检查权限
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';

// 导入包管理模块,用于获取应用信息
import bundleManager from '@ohos.bundle.bundleManager';

3.1 模块说明

  • **@ohos.contact**:联系人管理的核心模块,包含所有联系人操作的API
  • **@ohos.base**:基础服务模块,提供错误处理等通用功能
  • **@ohos.app.ability.common**:应用能力通用模块,提供上下文管理
  • **@ohos.abilityAccessCtrl**:权限访问控制模块,用于权限管理
  • **@ohos.bundle.bundleManager**:包管理模块,用于获取应用包信息

4. 核心功能实现

联系人管理的核心功能包括增加、删除、更新、查询等基本操作。每个操作都需要合适的权限支持,并且要妥善处理可能出现的异常情况。

4.1 添加联系人

添加联系人是联系人管理中最基础也是最重要的功能之一。系统支持添加包含多种信息的联系人,如姓名、电话、邮箱、地址等。

4.1.1 基础添加功能

最简单的联系人添加操作,只需要提供姓名和电话号码等基本信息:

/**
 * 添加基础联系人信息
 * @param name 联系人姓名
 * @param phoneNumber 联系人电话号码
 * @returns Promise<number | null> 返回新添加联系人的ID,失败时返回null
 */
async function addContact(name: string, phoneNumber: string): Promise<number | null> {
  // 获取应用上下文,这是调用系统API的必要参数
  const context = getContext(this) as common.UIAbilityContext;
  
  // 构建联系人对象,包含基本的姓名和电话信息
  const newContact: contact.Contact = {
    name: { fullName: name },                    // 联系人全名
    phoneNumbers: [{ phoneNumber: phoneNumber }] // 电话号码数组,支持多个号码
  };
  
  try {
    // 调用系统API添加联系人,返回新联系人的唯一ID
    const contactId = await contact.addContact(context, newContact);
    console.log(`联系人添加成功,系统分配的ID: ${contactId}`);
    return contactId;
  } catch (err) {
    // 捕获并处理可能出现的错误
    const error = err as BusinessError;
    console.error(`添加联系人失败,错误信息: ${error.message}`);
    return null;
  }
}

4.1.2 添加完整联系人信息

对于需要保存详细信息的联系人,可以添加包括多个电话号码、邮箱地址、工作信息、网站等完整信息:

/**
 * 添加包含详细信息的联系人
 * 演示如何创建一个包含全部信息字段的联系人记录
 * @returns Promise<void>
 */
async function addDetailedContact(): Promise<void> {
  // 获取应用上下文
  const context = getContext(this) as common.UIAbilityContext;
  
  // 构建包含完整信息的联系人对象
  const detailedContact: contact.Contact = {
    // 姓名信息,支持分别设置姓氏、名字和全名
    name: { 
      fullName: '张三',      // 完整姓名
      familyName: '张',      // 姓氏
      givenName: '三'        // 名字
    },
    
    // 电话号码信息,支持多个号码并为每个号码添加标签
    phoneNumbers: [
      { phoneNumber: 'xxxxxxx', labelName: '手机' },    // 个人手机
      { phoneNumber: 'xxxxxxxx', labelName: '工作' }    // 工作电话
    ],
    
    // 邮箱地址信息,支持多个邮箱
    emails: [
      { email: 'xxxx', labelName: '个人' }  // 个人邮箱
    ],
    
    // 地址信息,支持详细的地址结构
    addresses: [
      { 
        locality: '北京市',           // 城市
        region: '朝阳区',             // 区域/省份
        street: 'xxxxxx',       // 街道地址
        labelName: '家庭'             // 地址标签
      }
    ],
    
    // 工作组织信息
    organization: {
      name: '某某公司',              // 公司名称
      title: '软件工程师'            // 职位
    },
    
    // 网站信息
    websites: [
      { website: 'xxxxx' }  // 个人或工作网站
    ]
  };
  
  try {
    // 添加详细联系人信息
    const contactId = await contact.addContact(context, detailedContact);
    console.log(`详细联系人添加成功,系统分配的ID: ${contactId}`);
    console.log(`联系人信息包含: 姓名、${detailedContact.phoneNumbers?.length}个电话、${detailedContact.emails?.length}个邮箱、地址、工作信息`);
  } catch (err) {
    console.error(`添加详细联系人失败,错误信息: ${(err as BusinessError).message}`);
  }
}

4.2 查询联系人

查询功能是联系人管理中使用频率最高的操作之一。鸿蒙系统提供了多种查询方式,可以满足不同场景的需求。

4.2.1 查询所有联系人

获取设备中存储的所有联系人信息,这是最基础的查询操作:

/**
 * 查询设备中的所有联系人
 * 注意:如果联系人数量很多,这个操作可能比较耗时
 * @returns Promise<contact.Contact[]> 返回联系人数组
 */
async function getAllContacts(): Promise<contact.Contact[]> {
  // 获取应用上下文
  const context = getContext(this) as common.UIAbilityContext;
  
  try {
    // 调用系统API查询所有联系人
    const contacts = await contact.queryContacts(context);
    console.log(`成功查询到 ${contacts.length} 个联系人`);
    
    // 输出一些统计信息
    const contactsWithPhone = contacts.filter(c => c.phoneNumbers && c.phoneNumbers.length > 0);
    const contactsWithEmail = contacts.filter(c => c.emails && c.emails.length > 0);
    console.log(`其中 ${contactsWithPhone.length} 个联系人有电话号码`);
    console.log(`其中 ${contactsWithEmail.length} 个联系人有邮箱地址`);
    
    return contacts;
  } catch (err) {
    console.error(`查询联系人失败,错误信息: ${(err as BusinessError).message}`);
    return [];
  }
}

4.2.2 根据ID查询特定联系人

当我们知道联系人的唯一标识符(key)时,可以直接查询该联系人的详细信息:

/**
 * 根据联系人的唯一标识符查询特定联系人
 * @param contactKey 联系人的唯一标识符
 * @returns Promise<contact.Contact | null> 返回联系人信息,失败时返回null
 */
async function getContactById(contactKey: string): Promise<contact.Contact | null> {
  // 获取应用上下文
  const context = getContext(this) as common.UIAbilityContext;
  
  try {
    // 根据key查询特定联系人的详细信息
    const contactInfo = await contact.queryContact(context, contactKey);
    console.log(`查询联系人成功: ${contactInfo.name?.fullName}`);
    
    // 输出联系人的详细信息
    if (contactInfo.phoneNumbers && contactInfo.phoneNumbers.length > 0) {
      console.log(`电话号码: ${contactInfo.phoneNumbers.map(p => p.phoneNumber).join(', ')}`);
    }
    if (contactInfo.emails && contactInfo.emails.length > 0) {
      console.log(`邮箱地址: ${contactInfo.emails.map(e => e.email).join(', ')}`);
    }
    
    return contactInfo;
  } catch (err) {
    console.error(`查询联系人失败,错误信息: ${(err as BusinessError).message}`);
    return null;
  }
}

4.2.3 按属性查询联系人

有时我们只需要联系人的特定信息,比如只要姓名和电话号码,这时可以使用属性过滤查询来提高性能:

/**
 * 按指定属性查询联系人
 * 只返回包含指定属性的联系人信息,可以提高查询性能和减少内存使用
 * @returns Promise<contact.Contact[]> 返回包含指定属性的联系人数组
 */
async function getContactsWithAttributes(): Promise<contact.Contact[]> {
  // 获取应用上下文
  const context = getContext(this) as common.UIAbilityContext;
  
  // 定义需要查询的属性列表
  const attrs: contact.ContactAttributes = {
    attributes: [
      contact.Attribute.ATTR_NAME,    // 姓名属性
      contact.Attribute.ATTR_PHONE,   // 电话属性
      contact.Attribute.ATTR_EMAIL    // 邮箱属性
    ]
  };
  
  try {
    // 按指定属性查询联系人
    const contacts = await contact.queryContacts(context, attrs);
    console.log(`查询到包含指定属性的联系人: ${contacts.length} 个`);
    
    // 验证返回的联系人确实包含我们需要的属性
    contacts.forEach((contact, index) => {
      const hasName = contact.name && contact.name.fullName;
      const hasPhone = contact.phoneNumbers && contact.phoneNumbers.length > 0;
      const hasEmail = contact.emails && contact.emails.length > 0;
      console.log(`联系人 ${index + 1}: 姓名${hasName ? '✓' : '✗'} 电话${hasPhone ? '✓' : '✗'} 邮箱${hasEmail ? '✓' : '✗'}`);
    });
    
    return contacts;
  } catch (err) {
    console.error(`按属性查询联系人失败,错误信息: ${(err as BusinessError).message}`);
    return [];
  }
}

4.3 更新联系人

更新联系人信息是维护通讯录数据准确性的重要功能。可以修改联系人的任何信息,包括姓名、电话、邮箱等。

/**
 * 更新联系人信息
 * @param contactId 要更新的联系人ID
 * @param newName 新的姓名
 * @param newPhone 新的电话号码
 * @returns Promise<boolean> 返回更新是否成功
 */
async function updateContact(contactId: number, newName: string, newPhone: string): Promise<boolean> {
  // 获取应用上下文
  const context = getContext(this) as common.UIAbilityContext;
  
  // 构建要更新的联系人信息
  // 注意:更新时必须包含联系人的ID,系统根据ID来确定要更新哪个联系人
  const updatedContact: contact.Contact = {
    id: contactId,                          // 联系人的唯一标识
    name: { fullName: newName },            // 新的姓名信息
    phoneNumbers: [{ phoneNumber: newPhone }] // 新的电话号码
  };
  
  try {
    // 执行更新操作
    await contact.updateContact(context, updatedContact);
    console.log(`联系人更新成功,ID: ${contactId}`);
    console.log(`新姓名: ${newName}, 新电话: ${newPhone}`);
    return true;
  } catch (err) {
    console.error(`更新联系人失败,错误信息: ${(err as BusinessError).message}`);
    
    // 根据错误类型提供更详细的错误信息
    const error = err as BusinessError;
    if (error.code === 401) {
      console.error('参数错误:请检查联系人ID和更新的信息是否正确');
    } else if (error.code === 201) {
      console.error('权限错误:缺少写入联系人的权限');
    }
    
    return false;
  }
}

/**
 * 更新联系人的完整信息
 * 演示如何更新联系人的多个字段
 */
async function updateContactDetailed(contactId: number): Promise<boolean> {
  const context = getContext(this) as common.UIAbilityContext;
  
  const updatedContact: contact.Contact = {
    id: contactId,
    name: { 
      fullName: '李四',
      familyName: '李',
      givenName: '四'
    },
    phoneNumbers: [
      { phoneNumber: 'xxxxxx', labelName: '手机' },
      { phoneNumber: 'xxxxxxx', labelName: '工作' }
    ],
    emails: [
      { email: 'xxxxxx', labelName: '工作' }
    ],
    organization: {
      name: '新公司',
      title: '高级工程师'
    }
  };
  
  try {
    await contact.updateContact(context, updatedContact);
    console.log('联系人详细信息更新成功');
    return true;
  } catch (err) {
    console.error(`更新联系人详细信息失败: ${(err as BusinessError).message}`);
    return false;
  }
}

4.4 删除联系人

删除联系人是一个不可逆的操作,需要谨慎处理。建议在删除前向用户确认,并提供必要的提示信息。

/**
 * 删除指定的联系人
 * 注意:这是一个不可逆的操作,删除后无法恢复
 * @param contactKey 要删除的联系人的唯一标识符
 * @returns Promise<boolean> 返回删除是否成功
 */
async function deleteContact(contactKey: string): Promise<boolean> {
  // 获取应用上下文
  const context = getContext(this) as common.UIAbilityContext;
  
  try {
    // 在删除前,建议先查询联系人信息以确认删除的对象
    const contactToDelete = await contact.queryContact(context, contactKey);
    console.log(`准备删除联系人: ${contactToDelete.name?.fullName}`);
    
    // 执行删除操作
    await contact.deleteContact(context, contactKey);
    console.log(`联系人删除成功,已删除: ${contactToDelete.name?.fullName}`);
    return true;
  } catch (err) {
    console.error(`删除联系人失败,错误信息: ${(err as BusinessError).message}`);
    
    // 提供详细的错误处理
    const error = err as BusinessError;
    if (error.code === 401) {
      console.error('参数错误:联系人标识符无效或联系人不存在');
    } else if (error.code === 201) {
      console.error('权限错误:缺少写入联系人的权限');
    }
    
    return false;
  }
}

/**
 * 批量删除联系人
 * 删除多个联系人,适用于清理无效联系人等场景
 * @param contactKeys 要删除的联系人标识符数组
 * @returns Promise<{success: number, failed: number}> 返回删除结果统计
 */
async function deleteMultipleContacts(contactKeys: string[]): Promise<{success: number, failed: number}> {
  const context = getContext(this) as common.UIAbilityContext;
  let successCount = 0;
  let failedCount = 0;
  
  console.log(`开始批量删除 ${contactKeys.length} 个联系人`);
  
  // 逐个删除联系人
  for (const contactKey of contactKeys) {
    try {
      await contact.deleteContact(context, contactKey);
      successCount++;
      console.log(`联系人 ${contactKey} 删除成功`);
    } catch (err) {
      failedCount++;
      console.error(`联系人 ${contactKey} 删除失败: ${(err as BusinessError).message}`);
    }
  }
  
  console.log(`批量删除完成:成功 ${successCount} 个,失败 ${failedCount} 个`);
  return { success: successCount, failed: failedCount };
}

5. 高级功能

5.1 搜索功能

鸿蒙系统的联系人搜索功能主要通过查询所有联系人后进行本地过滤实现。系统没有提供直接按电话号码或邮箱搜索的API,但我们可以通过以下方式实现搜索功能:

本地搜索实现

/**
 * 通过电话号码搜索联系人
 * 先查询所有联系人,然后在本地进行过滤匹配
 * @param phoneNumber 要搜索的电话号码
 * @returns Promise<contact.Contact[]> 匹配的联系人数组
 */
async function searchByPhoneNumber(phoneNumber: string): Promise<contact.Contact[]> {
  const context = getContext(this) as common.UIAbilityContext;
  
  try {
    // 查询所有联系人
    const allContacts = await contact.queryContacts(context);
    
    // 在本地过滤包含指定电话号码的联系人
    const matchedContacts = allContacts.filter(contact => {
      if (!contact.phoneNumbers) return false;
      
      return contact.phoneNumbers.some(phone => 
        phone.phoneNumber && phone.phoneNumber.includes(phoneNumber)
      );
    });
    
    console.log(`通过电话号码 "${phoneNumber}" 找到 ${matchedContacts.length} 个联系人`);
    return matchedContacts;
  } catch (err) {
    console.error(`通过电话号码搜索失败,错误信息: ${(err as BusinessError).message}`);
    return [];
  }
}

/**
 * 通过邮箱地址搜索联系人
 * 先查询所有联系人,然后在本地进行过滤匹配
 * @param email 要搜索的邮箱地址
 * @returns Promise<contact.Contact[]> 匹配的联系人数组
 */
async function searchByEmail(email: string): Promise<contact.Contact[]> {
  const context = getContext(this) as common.UIAbilityContext;
  
  try {
    // 查询所有联系人
    const allContacts = await contact.queryContacts(context);
    
    // 在本地过滤包含指定邮箱的联系人
    const matchedContacts = allContacts.filter(contact => {
      if (!contact.emails) return false;
      
      return contact.emails.some(emailObj => 
        emailObj.email && emailObj.email.toLowerCase().includes(email.toLowerCase())
      );
    });
    
    console.log(`通过邮箱 "${email}" 找到 ${matchedContacts.length} 个联系人`);
    return matchedContacts;
  } catch (err) {
    console.error(`通过邮箱搜索失败,错误信息: ${(err as BusinessError).message}`);
    return [];
  }
}

/**
 * 通过姓名搜索联系人
 * 支持模糊匹配姓名
 * @param name 要搜索的姓名关键词
 * @returns Promise<contact.Contact[]> 匹配的联系人数组
 */
async function searchByName(name: string): Promise<contact.Contact[]> {
  const context = getContext(this) as common.UIAbilityContext;
  
  try {
    // 查询所有联系人
    const allContacts = await contact.queryContacts(context);
    
    // 在本地过滤包含指定姓名的联系人
    const matchedContacts = allContacts.filter(contact => {
      if (!contact.name) return false;
      
      const fullName = contact.name.fullName || '';
      const familyName = contact.name.familyName || '';
      const givenName = contact.name.givenName || '';
      
      return fullName.includes(name) || 
             familyName.includes(name) || 
             givenName.includes(name);
    });
    
    console.log(`通过姓名 "${name}" 找到 ${matchedContacts.length} 个联系人`);
    return matchedContacts;
  } catch (err) {
    console.error(`通过姓名搜索失败,错误信息: ${(err as BusinessError).message}`);
    return [];
  }
}

5.2 联系人选择器

单选联系人

async function selectSingleContact(): Promise<contact.Contact[]> {
  try {
    const selectedContacts = await contact.selectContacts({
      isMultiSelect: false
    });
    
    if (selectedContacts.length > 0) {
      console.log(`用户选择了联系人: ${selectedContacts[0].name?.fullName}`);
    }
    return selectedContacts;
  } catch (err) {
    console.error(`选择联系人失败: ${(err as BusinessError).message}`);
    return [];
  }
}

多选联系人

async function selectMultipleContacts(): Promise<contact.Contact[]> {
  try {
    const selectedContacts = await contact.selectContacts({
      isMultiSelect: true
    });
    
    console.log(`用户选择了 ${selectedContacts.length} 个联系人`);
    selectedContacts.forEach(contact => {
      console.log(`- ${contact.name?.fullName}`);
    });
    
    return selectedContacts;
  } catch (err) {
    console.error(`选择多个联系人失败: ${(err as BusinessError).message}`);
    return [];
  }
}

5.3 "我的名片"管理

查询我的名片

async function getMyCard(): Promise<contact.Contact | null> {
  const context = getContext(this) as common.UIAbilityContext;
  
  try {
    const myCard = await contact.queryMyCard(context);
    console.log(`我的名片: ${myCard.name?.fullName}`);
    return myCard;
  } catch (err) {
    console.error(`查询我的名片失败: ${(err as BusinessError).message}`);
    return null;
  }
}

判断是否为我的名片

async function checkIsMyCard(contactId: number): Promise<boolean> {
  const context = getContext(this) as common.UIAbilityContext;
  
  try {
    const isMyCard = await contact.isMyCard(context, contactId);
    console.log(`联系人ID ${contactId} 是否为我的名片: ${isMyCard}`);
    return isMyCard;
  } catch (err) {
    console.error(`判断我的名片失败: ${(err as BusinessError).message}`);
    return false;
  }
}

5.4 联系人验证

async function validateContact(contactId: number): Promise<boolean> {
  const context = getContext(this) as common.UIAbilityContext;
  
  try {
    const isLocal = await contact.isLocalContact(context, contactId);
    console.log(`联系人ID ${contactId} 是否在本地: ${isLocal}`);
    return isLocal;
  } catch (err) {
    console.error(`验证联系人失败: ${(err as BusinessError).message}`);
    return false;
  }
}

6. 实际应用示例

6.1 联系人管理组件

@Component
export struct ContactManager {
  @State contacts: contact.Contact[] = [];
  @State isLoading: boolean = false;
  @State searchKeyword: string = '';

  async aboutToAppear() {
    await this.loadContacts();
  }

  async loadContacts() {
    this.isLoading = true;
    try {
      this.contacts = await getAllContacts();
    } finally {
      this.isLoading = false;
    }
  }

  async onAddContact() {
    try {
      const selectedContacts = await selectSingleContact();
      if (selectedContacts.length > 0) {
        await this.loadContacts(); // 刷新列表
      }
    } catch (err) {
      console.error('添加联系人失败:', err);
    }
  }

  async onSearchContacts() {
    if (this.searchKeyword.trim() === '') {
      await this.loadContacts();
      return;
    }

    this.isLoading = true;
    try {
      // 尝试按姓名搜索
      let results = await searchByName(this.searchKeyword);
      
      // 如果没找到,尝试按电话号码搜索
      if (results.length === 0) {
        results = await searchByPhoneNumber(this.searchKeyword);
      }
      
      // 如果还没找到,尝试按邮箱搜索
      if (results.length === 0) {
        results = await searchByEmail(this.searchKeyword);
      }
      
      this.contacts = results;
    } finally {
      this.isLoading = false;
    }
  }

  build() {
    Column() {
      // 搜索框
      Row() {
        TextInput({ placeholder: '搜索联系人...' })
          .layoutWeight(1)
          .onChange((value: string) => {
            this.searchKeyword = value;
          })
        
        Button('搜索')
          .onClick(() => this.onSearchContacts())
      }
      .padding(16)

      // 操作按钮
      Row() {
        Button('添加联系人')
          .onClick(() => this.onAddContact())
        
        Button('刷新')
          .onClick(() => this.loadContacts())
      }
      .padding(16)

      // 联系人列表
      if (this.isLoading) {
        LoadingProgress()
          .width(50)
          .height(50)
      } else {
        List() {
          ForEach(this.contacts, (contactItem: contact.Contact, index: number) => {
            ListItem() {
              ContactItem({ contact: contactItem })
            }
          })
        }
        .layoutWeight(1)
      }
    }
    .width('100%')
    .height('100%')
  }
}

6.2 联系人列表项组件

@Component
struct ContactItem {
  private contact: contact.Contact;

  build() {
    Row() {
      // 头像
      Image($r('app.media.default_avatar'))
        .width(50)
        .height(50)
        .borderRadius(25)

      Column() {
        // 姓名
        Text(this.contact.name?.fullName || '未知联系人')
          .fontSize(16)
          .fontWeight(FontWeight.Bold)

        // 电话号码
        if (this.contact.phoneNumbers && this.contact.phoneNumbers.length > 0) {
          Text(this.contact.phoneNumbers[0].phoneNumber)
            .fontSize(14)
            .fontColor(Color.Gray)
        }

        // 邮箱
        if (this.contact.emails && this.contact.emails.length > 0) {
          Text(this.contact.emails[0].email)
            .fontSize(12)
            .fontColor(Color.Gray)
        }
      }
      .alignItems(HorizontalAlign.Start)
      .layoutWeight(1)
      .margin({ left: 12 })

      // 操作按钮
      Row() {
        Button('编辑')
          .fontSize(12)
          .onClick(() => this.onEditContact())

        Button('删除')
          .fontSize(12)
          .backgroundColor(Color.Red)
          .onClick(() => this.onDeleteContact())
      }
    }
    .width('100%')
    .padding(12)
    .backgroundColor(Color.White)
    .borderRadius(8)
    .margin({ bottom: 8 })
  }

  onEditContact() {
    // 编辑联系人逻辑
    console.log('编辑联系人:', this.contact.name?.fullName);
  }

  async onDeleteContact() {
    if (this.contact.key) {
      const success = await deleteContact(this.contact.key);
      if (success) {
        // 通知父组件刷新列表
        console.log('联系人删除成功');
      }
    }
  }
}

7. 错误处理与最佳实践

7.1 错误处理

class ContactsManager {
  async safeContactOperation<T>(
    operation: () => Promise<T>,
    errorMessage: string
  ): Promise<T | null> {
    try {
      return await operation();
    } catch (err) {
      const error = err as BusinessError;
      console.error(`${errorMessage}: ${error.message}`);
      
      // 根据错误码进行不同处理
      switch (error.code) {
        case 201:
          console.error('权限被拒绝');
          break;
        case 401:
          console.error('参数错误');
          break;
        default:
          console.error('未知错误');
      }
      
      return null;
    }
  }

  async addContactSafely(contactData: contact.Contact): Promise<number | null> {
    return this.safeContactOperation(
      () => contact.addContact(getContext(this) as common.UIAbilityContext, contactData),
      '添加联系人失败'
    );
  }
}

7.2 性能优化

class ContactsCache {
  private contactsCache: Map<string, contact.Contact> = new Map();
  private lastUpdateTime: number = 0;
  private readonly CACHE_DURATION = 5 * 60 * 1000; // 5分钟缓存

  async getContacts(forceRefresh: boolean = false): Promise<contact.Contact[]> {
    const now = Date.now();
    
    if (!forceRefresh && 
        this.contactsCache.size > 0 && 
        now - this.lastUpdateTime < this.CACHE_DURATION) {
      return Array.from(this.contactsCache.values());
    }

    const contacts = await getAllContacts();
    this.contactsCache.clear();
    
    contacts.forEach(contact => {
      if (contact.key) {
        this.contactsCache.set(contact.key, contact);
      }
    });
    
    this.lastUpdateTime = now;
    return contacts;
  }

  clearCache() {
    this.contactsCache.clear();
    this.lastUpdateTime = 0;
  }
}

8. 总结

鸿蒙联系人管理功能为开发者提供了完整的联系人操作能力:

核心优势

  • 完整的CRUD操作:支持联系人的增删改查
  • 灵活的搜索功能:支持多种搜索方式
  • 系统UI集成:可调用系统联系人选择界面
  • 安全的权限管理:确保用户数据安全

开发要点

  • 正确申请和处理权限
  • 合理使用缓存提升性能
  • 完善的错误处理机制
  • 用户友好的交互设计

应用场景

  • 通讯录应用
  • 社交应用
  • 商务应用
  • 客户管理系统
收藏00

登录 后评论。没有帐号? 注册 一个。