更新记录

1.0.0(2026-10-13)

  • 新版发布

平台兼容性

uni-app(5.01)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
√ √ × × √ √ √ √ √
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
× × × × × × × × × × × ×

uni-app x(5.01)

Chrome Safari Android iOS 鸿蒙 微信小程序
× × √ √ √ ×

其他

多语言 暗黑模式 宽屏模式 蒸汽模式
× × × √

yt-contacts

yt-contacts 是一个用于读写手机系统通讯录的 UTS 原生插件,可在 uni-app 和 uni-app x 的 App 项目中使用。

插件支持 Android、iOS、HarmonyOS 联系人的查询、新增、修改和删除,联系人查询支持 按姓名或电话号码进行包含式模糊匹配。Android 端额外支持读取、筛选系统历史通话记录。

插件直接访问设备系统通讯录或 Android 系统通话记录,不会主动把数据上传到服务器。

特别提醒

  • 购买本插件前,请先试用,请先试用,请先试用,确认满足需求之后再行购买。虚拟物品一旦购买之后无法退款。
  • 如有使用上的疑问、bug,可以进交流群联系作者;
  • 请在合法范围内使用,若使用本插件做非法开发,本方概不负责;
  • 插件需先引入再打自定义基座后运行测试
  • 可下载插件提供的示例项目测试、试用,uniappx示例工程在uniapp项目的static/ContactsDemo.zip。

方法一览

插件共导出 5 个异步方法。所有方法调用后立即返回 void,实际结果通过 success / fail / complete 回调返回。

方法 功能 Android iOS HarmonyOS
getContacts(options) 查询联系人、模糊查询、分页 支持 支持 支持
addContact(options) 新增系统联系人 支持 支持 支持
updateContact(options) 修改指定联系人 支持 支持 支持
deleteContact(options) 删除指定联系人 支持 支持 支持
getCallLogs(options) 查询、筛选系统历史通话记录 支持 不支持 不支持

iOS 和 HarmonyOS 受系统权限及公开 API 限制,不提供系统历史通话记录读取能力。 在这两个平台调用 getCallLogs 会进入 fail 回调并返回 9201008。

快速接入

安装

将插件目录放到项目的 uni_modules/yt-contacts。首次集成插件、升级插件或者修改原生 权限配置后,需要重新制作并安装自定义调试基座,或重新打包应用。旧基座不会自动包含 新增的原生插件和权限。

本插件只支持 App 原生平台,不支持 Web 和小程序。

普通 uni-app .vue 页面导入

JavaScript 页面只需导入运行时方法,不需要导入 UTS 类型:

import {
  addContact,
  deleteContact,
  getCallLogs,
  getContacts,
  updateContact
} from '@/uni_modules/yt-contacts'

uni-app x .uvue 页面导入类型

在 UTS 页面中如需为参数和回调添加类型,可额外导入:

import {
  AddContactOptions,
  AddContactResult,
  CallLogInfo,
  CallLogListResult,
  CallLogType,
  ContactEmail,
  ContactInfo,
  ContactInput,
  ContactListResult,
  ContactPhone,
  ContactsFail,
  DeleteContactOptions,
  DeleteContactResult,
  GetCallLogsOptions,
  GetContactsOptions,
  UpdateContactOptions,
  UpdateContactResult
} from '@/uni_modules/yt-contacts/utssdk/interface.uts'

回调规则

每个方法的 options 都遵循相同的回调规则:

回调 触发条件 参数
success 操作成功 对应方法的成功结果对象
fail 参数、权限或系统操作失败 ContactsFail 错误对象
complete 成功或失败后都会执行一次 成功结果对象或 ContactsFail
  • success 和 fail 只会触发其中一个。
  • complete 在 success 或 fail 之后执行,并且只执行一次。
  • 回调字段在类型定义中均为可选,但业务代码建议至少实现 success 和 fail。
  • 所有方法的同步返回值都是 void,不要使用 const result = getContacts(...) 获取数据。

权限说明

插件会在调用方法时检查并申请该方法所需的运行时权限,业务页面无需另外编写权限申请 代码。用户拒绝权限后,对应方法会进入 fail 回调。

各方法所需权限

方法 Android iOS HarmonyOS
getContacts READ_CONTACTS 通讯录权限 READ_CONTACTS + ACL
addContact READ_CONTACTS、WRITE_CONTACTS 通讯录权限 READ_CONTACTS、WRITE_CONTACTS + ACL
updateContact READ_CONTACTS、WRITE_CONTACTS 通讯录权限 READ_CONTACTS、WRITE_CONTACTS + ACL
deleteContact READ_CONTACTS、WRITE_CONTACTS 通讯录权限 READ_CONTACTS、WRITE_CONTACTS + ACL
getCallLogs READ_CALL_LOG 不支持 不支持

新增联系人也需要读取权限,因为插件需要在写入后查询系统生成的稳定联系人 ID。修改和 删除联系人需要先读取并定位目标联系人,因此同时需要读取和写入权限。

Android

插件的 utssdk/app-android/AndroidManifest.xml 已声明:

  • android.permission.READ_CONTACTS
  • android.permission.WRITE_CONTACTS
  • android.permission.READ_CALL_LOG

Android 厂商系统可能把通话记录归为高敏感权限。应用上架时,还需要按照目标应用市场 的政策说明读取通话记录的真实用途。

iOS

插件的 utssdk/app-ios/Info.plist 已配置 NSContactsUsageDescription。首次调用联系人 方法时,插件会通过系统 CNContactStore 申请通讯录权限。

  • iOS 18 的“有限访问”会按已授权处理,只能操作用户允许应用访问的联系人。
  • 用户拒绝后,需要前往系统设置重新开启通讯录权限。
  • iOS 公共 SDK 不提供系统历史通话记录,因此 getCallLogs 不可用。

HarmonyOS:必须申请 ACL 权限

HarmonyOS 使用以下受限开放权限,插件已在 utssdk/app-harmony/module.json5 中声明:

  • ohos.permission.READ_CONTACTS
  • ohos.permission.WRITE_CONTACTS

这两个权限属于 system_basic 受限权限。仅在插件中声明权限还不够,使用插件的应用 必须按照自己的 Bundle Name 在 AppGallery Connect 申请 ACL 权限。没有获得签名授权 时,运行或安装可能提示“运行所需的权限没有签名授权”,插件内部的运行时权限弹窗无法 解决签名 ACL 问题。

申请步骤:

  1. 登录 HarmonyOS 开发者中心/AppGallery Connect,进入需要使用插件的应用。
  2. 进入“开发与服务”或项目设置中的“ACL 权限申请”。
  3. 分别申请 ohos.permission.READ_CONTACTS 和 ohos.permission.WRITE_CONTACTS。
  4. 按真实业务选择联系人克隆、备份或同步等使用场景,并提交对应证明材料。
  5. 调试时按照 AGC 页面提示启用 ACL 试用,生成临时调试 Profile,并在项目签名配置中 换用该 Profile 后重新编译安装。
  6. 正式审批通过后,重新生成调试或发布 Profile,勾选“受限 ACL 权限(HarmonyOS API 9 及以上)”,再重新签名打包。

华为目前提供 5 天 ACL 试用权限。提交 ACL 申请后无需等待审批,即可使用临时调试 Profile。无论本次 ACL 最终审批成功还是未通过,都可以先使用这 5 天完成调试。试用不 代表正式审批通过,试用到期且未获得正式 ACL 时,联系人读写能力将无法继续使用,发布 包也不能依赖试用权限。

取得 ACL 或试用 Profile 后,应用首次访问通讯录时仍需取得用户的运行时授权。

官方说明:

数据类型

ContactPhone

联系人电话号码,一个联系人可包含多个电话号码。

字段 类型 必填 默认值 说明
number string 是 - 电话号码,保留系统中的空格、区号等格式
type number 否 2 0=自定义、1=家庭、2=手机、3=工作
label string 否 '' type=0 时使用的自定义标签

写入时,number 去除首尾空格后如果为空,该条电话号码会被忽略。

ContactEmail

联系人邮箱,一个联系人可包含多个邮箱。

字段 类型 必填 默认值 说明
address string 是 - 邮箱地址
type number 否 3 0=自定义、1=家庭、2=工作、3=其他
label string 否 '' type=0 时使用的自定义标签

写入时,address 去除首尾空格后如果为空,该条邮箱会被忽略。

ContactInput

新增或修改联系人时提交的数据。

字段 类型 必填 默认值 说明
displayName string 是 - 联系人显示名称,去除首尾空格后不能为空
phones Array<ContactPhone> 否 [] 电话号码列表,支持多项
emails Array<ContactEmail> 否 [] 邮箱列表,支持多项
organization string 否 '' 公司或组织名称
note string 否 '' 联系人备注;iOS 忽略该字段

修改联系人时,phones、emails、organization 和 note 是替换语义:传空数组、空 字符串或省略字段会清空对应的公共字段。iOS 不读取也不写入 note。

ContactInfo

getContacts 返回的联系人对象。

字段 类型 说明
id string 稳定联系人 ID,调用修改或删除时作为 contactId 传回
rawContactId string Android RawContact ID;iOS/HarmonyOS 返回平台原生辅助 ID
displayName string 联系人显示名称
phones Array<ContactPhone> 全部电话号码
emails Array<ContactEmail> 全部邮箱
organization string 公司或组织名称,没有时为空字符串
note string 备注;iOS 固定返回空字符串
photoUri string 系统头像 URI;没有头像或平台不提供 URI 时为空字符串

不要自行拼接、缓存到其他设备或猜测 id。修改和删除应使用当前设备本次 getContacts 查询返回的 ContactInfo.id。

CallLogType

通话类型字符串:

值 含义
INCOMING 呼入
OUTGOING 呼出
MISSED 未接
REJECTED 拒接
BLOCKED 拦截
VOICEMAIL 语音信箱
ANSWERED_EXTERNALLY 在其他设备接听
UNKNOWN 当前插件无法映射的系统类型

CallLogInfo

Android 通话记录对象。

字段 类型 说明
id string 系统通话记录 ID
number string 电话号码,系统未提供时可能为空
name string 通话记录缓存的联系人名称,未匹配时为空字符串
type CallLogType 插件统一后的通话类型
typeCode number Android CallLog.Calls.TYPE 原始整数值
timestamp number 通话开始时间,Unix 毫秒时间戳
duration number 通话时长,单位为秒
formattedNumber string 系统格式化后的号码,可能为空字符串
geocodedLocation string 系统记录的号码归属地,可能为空字符串

API 参考

1. getContacts(options)

查询系统通讯录,支持模糊查询和分页。

getContacts(options: GetContactsOptions): void

平台与权限:

  • Android:支持,需要 READ_CONTACTS。
  • iOS:支持,需要系统通讯录权限。
  • HarmonyOS:支持,需要 ohos.permission.READ_CONTACTS ACL 和用户授权。

参数 GetContactsOptions

参数 类型 必填 默认值 说明
keyword string 否 '' 同时匹配显示名称和任意电话号码;包含式、不区分英文大小写;不匹配邮箱或公司
limit number 否 50 当前页最多返回几条;小于 1 按 1,大于 500 按 500
offset number 否 0 从全部匹配结果中跳过的条数;负数按 0
success (res: ContactListResult) => void 否 - 查询成功回调
fail (err: ContactsFail) => void 否 - 查询失败回调
complete (res: any) => void 否 - 查询结束回调,成功或失败都会执行

keyword 会先去除首尾空格。为空时查询全部联系人,例如 张 可匹配名称中包含“张”的 联系人,138 可匹配任意电话号码中包含“138”的联系人。

成功返回 ContactListResult

字段 类型 说明
contacts Array<ContactInfo> 当前页联系人数组,可能为空数组
total number 符合 keyword 的总数,不受 limit/offset 影响
hasMore boolean 当前页后是否还有匹配数据

下一页 offset 推荐使用“当前 offset + 本次 contacts.length”。

普通 uni-app 调用示例

getContacts({
  keyword: '138',
  limit: 50,
  offset: 0,
  success: (result) => {
    console.log('当前页联系人', result.contacts)
    console.log('匹配总数', result.total)
    console.log('是否还有下一页', result.hasMore)
  },
  fail: (error) => {
    console.log('查询失败', error.errCode, error.errMsg)
  },
  complete: (resultOrError) => {
    console.log('查询结束', resultOrError)
  }
})

可能出现的主要错误码:9201001、9201002、9201007。

2. addContact(options)

向系统通讯录新增一个联系人。

addContact(options: AddContactOptions): void

平台与权限:

  • Android:支持,需要 READ_CONTACTS 和 WRITE_CONTACTS。
  • iOS:支持,需要系统通讯录权限。
  • HarmonyOS:支持,需要 READ_CONTACTS、WRITE_CONTACTS ACL 和用户授权。

参数 AddContactOptions

参数 类型 必填 说明
contact ContactInput 是 需要新增的联系人数据,displayName 必填
success (res: AddContactResult) => void 否 新增成功回调
fail (err: ContactsFail) => void 否 新增失败回调
complete (res: any) => void 否 操作结束回调,成功或失败都会执行

成功返回 AddContactResult

字段 类型 说明
success boolean 成功时固定为 true
contactId string 新联系人稳定 ID,可用于后续修改或删除
rawContactId string Android RawContact ID;其他平台为原生辅助 ID
message string 成功说明,当前为“联系人新增成功”

调用示例

addContact({
  contact: {
    displayName: '张三',
    phones: [
      { number: '***', type: 2 },
      { number: '010-12345678', type: 3 }
    ],
    emails: [
      { address: 'zhangsan@example.com', type: 2 }
    ],
    organization: '示例公司',
    note: '由 yt-contacts 创建'
  },
  success: (result) => {
    console.log('新增成功,联系人 ID:', result.contactId)
  },
  fail: (error) => {
    console.log('新增失败', error.errCode, error.errMsg)
  }
})

注意:iOS 会忽略 note。可能出现的主要错误码:9201001、9201003、9201005、 9201007。

3. updateContact(options)

修改一个已存在的系统联系人。

updateContact(options: UpdateContactOptions): void

必须先通过 getContacts 获得目标联系人的 id,再作为 contactId 传入。

平台与权限:

  • Android:支持,需要 READ_CONTACTS 和 WRITE_CONTACTS。
  • iOS:支持,需要系统通讯录权限。
  • HarmonyOS:支持,需要 READ_CONTACTS、WRITE_CONTACTS ACL 和用户授权。

参数 UpdateContactOptions

参数 类型 必填 说明
contactId string 是 getContacts 返回的 ContactInfo.id,不能为空
contact ContactInput 是 修改后的完整公共联系人字段,displayName 不能为空
success (res: UpdateContactResult) => void 否 修改成功回调
fail (err: ContactsFail) => void 否 修改失败回调
complete (res: any) => void 否 操作结束回调,成功或失败都会执行

成功返回 UpdateContactResult

字段 类型 说明
success boolean 成功时固定为 true
contactId string 本次修改的联系人 ID
affectedRows number 成功时为 1
message string 成功说明,当前为“联系人修改成功”

更新规则

  • displayName、phones、emails、organization 和 note 按传入值替换。
  • phones 或 emails 传空数组/省略,会清空原有电话或邮箱。
  • organization 或 note 传空字符串/省略,会清空原值。
  • iOS 不读取或写入 note,原生备注不会由本插件修改。
  • 头像、地址、生日等不在 ContactInput 中的原生字段会保留。
  • Android 只修改联系人中的可写 RawContact;只读联系人会失败。

调用示例

function updateSelectedContact(contactId) {
  updateContact({
    contactId,
    contact: {
      displayName: '张三(已修改)',
      phones: [{ number: '***', type: 2 }],
      emails: [{ address: 'new@example.com', type: 2 }],
      organization: '新公司',
      note: '修改后的备注'
    },
    success: (result) => {
      console.log('修改成功', result.contactId, result.affectedRows)
    },
    fail: (error) => {
      console.log('修改失败', error.errCode, error.errMsg)
    }
  })
}

可能出现的主要错误码:9201001、9201003、9201005、9201006、9201007。

4. deleteContact(options)

从系统通讯录删除指定联系人。删除不可撤销,建议调用前由业务页面二次确认。

deleteContact(options: DeleteContactOptions): void

平台与权限:

  • Android:支持,需要 READ_CONTACTS 和 WRITE_CONTACTS。
  • iOS:支持,需要系统通讯录权限。
  • HarmonyOS:支持,需要 READ_CONTACTS、WRITE_CONTACTS ACL 和用户授权。

参数 DeleteContactOptions

参数 类型 必填 说明
contactId string 是 getContacts 返回的 ContactInfo.id,不能为空
success (res: DeleteContactResult) => void 否 删除成功回调
fail (err: ContactsFail) => void 否 删除失败回调
complete (res: any) => void 否 操作结束回调,成功或失败都会执行

成功返回 DeleteContactResult

字段 类型 说明
success boolean 成功时固定为 true
contactId string 本次删除的联系人 ID
affectedRows number 成功时为 1
message string 成功说明,当前为“联系人删除成功”

调用示例

function removeSelectedContact(contactId) {
  uni.showModal({
    title: '删除联系人',
    content: '删除后无法恢复,确定继续吗?',
    success: (modalResult) => {
      if (!modalResult.confirm) return

      deleteContact({
        contactId,
        success: (result) => {
          console.log('删除成功', result.contactId)
        },
        fail: (error) => {
          console.log('删除失败', error.errCode, error.errMsg)
        }
      })
    }
  })
}

Android 的一个聚合联系人可能包含多个 RawContact,插件会删除该联系人下全部可写的 RawContact。联系人不存在、已删除或只读时返回 9201006。

可能出现的主要错误码:9201001、9201003、9201005、9201006、9201007。

5. getCallLogs(options)

查询 Android 系统历史通话记录,支持关键字、通话类型、时间范围和分页筛选。结果按 通话开始时间倒序排列,最新通话在前。

getCallLogs(options: GetCallLogsOptions): void

平台与权限:

  • Android:支持,需要 READ_CALL_LOG。
  • iOS:不支持,调用后返回 9201008。
  • HarmonyOS:不支持,调用后返回 9201008。

参数 GetCallLogsOptions

参数 类型 必填 默认值 说明
keyword string 否 '' 按电话号码或通话记录中的联系人名称进行包含式模糊匹配
types Array<CallLogType> 否 全部 仅返回指定通话类型;传空数组等同于不限制类型
startTime number 否 无限制 起始 Unix 毫秒时间戳,包含该时刻
endTime number 否 无限制 结束 Unix 毫秒时间戳,包含该时刻
limit number 否 50 当前页最多返回几条;小于 1 按 1,大于 500 按 500
offset number 否 0 从全部匹配记录中跳过的条数;负数按 0
success (res: CallLogListResult) => void 否 - 查询成功回调
fail (err: ContactsFail) => void 否 - 查询失败或平台不支持回调
complete (res: any) => void 否 - 查询结束回调,成功或失败都会执行

如果同时传入多个筛选条件,记录必须同时符合关键字、类型和时间范围才会返回。

成功返回 CallLogListResult

字段 类型 说明
records Array<CallLogInfo> 当前页通话记录数组,可能为空数组
total number 符合全部筛选条件的记录总数,不受分页影响
hasMore boolean 当前页后是否还有匹配记录

调用示例

getCallLogs({
  keyword: '',
  types: ['INCOMING', 'OUTGOING', 'MISSED'],
  startTime: new Date('2026-01-01 00:00:00').getTime(),
  endTime: Date.now(),
  limit: 100,
  offset: 0,
  success: (result) => {
    console.log('通话记录总数', result.total)
    result.records.forEach((record) => {
      console.log(
        record.number,
        record.name,
        record.type,
        record.timestamp,
        record.duration
      )
    })
  },
  fail: (error) => {
    console.log('读取失败', error.errCode, error.errMsg)
  }
})

只查询未接来电:

getCallLogs({
  types: ['MISSED'],
  limit: 50,
  offset: 0,
  success: (result) => {
    console.log(result.records)
  },
  fail: (error) => {
    console.log(error.errCode, error.errMsg)
  }
})

Android 可能出现的主要错误码:9201001、9201004、9201007。iOS 和 HarmonyOS 固定返回 9201008。

错误对象与错误码

ContactsFail

失败回调返回统一的 ContactsFail,它继承自 IUniError。

字段 类型 说明
errSubject string 错误来源,固定为 yt-contacts
errCode ContactsErrorCode 插件错误码
errMsg string 中文错误说明,可能附带系统原生异常信息

错误码

错误码 含义 常见处理方式
9201001 当前页面 Activity/Context 不可用 确保在可见页面加载完成后调用,避免应用切到后台时调用
9201002 读取通讯录权限被拒绝 提示用户前往系统设置开启通讯录读取权限
9201003 写入通讯录权限被拒绝 提示用户前往系统设置开启通讯录写入权限
9201004 Android 读取通话记录权限被拒绝 提示用户开启通话记录权限;同时检查厂商权限管理
9201005 参数无效 检查 displayName、contactId 等必填参数
9201006 联系人不存在、已删除、只读或不可修改 重新查询联系人并使用最新 id,确认联系人可写
9201007 系统通讯录操作失败 记录完整 errMsg,检查系统返回的具体原因
9201008 当前平台或系统公共 API 不支持此能力 不要在 iOS/HarmonyOS 调用通话记录功能

失败处理示例:

function handleContactsError(error) {
  if (error.errCode === 9201002 || error.errCode === 9201003) {
    uni.showToast({ title: '请在系统设置中开启通讯录权限', icon: 'none' })
    return
  }

  if (error.errCode === 9201008) {
    uni.showToast({ title: '当前平台不支持此功能', icon: 'none' })
    return
  }

  uni.showToast({ title: error.errMsg || '操作失败', icon: 'none' })
}

平台字段差异

字段/能力 Android iOS HarmonyOS
displayName 读写 读写 读写
多个电话号码 读写 读写 读写
多个邮箱 读写 读写 读写
organization 读写 读写 读写
note 读写 不读写,返回空字符串 读写
photoUri 只读 返回空字符串 只读
系统历史通话记录 支持 不支持 不支持

iOS 的 CNContact.note 需要 Apple 单独批准的 com.apple.developer.contacts.notes entitlement。为了让普通应用无需额外 entitlement 即可使用联系人能力,插件的 iOS 实现不读取或写入备注。

完整页面示例

普通 uni-app Vue 3 选项式 API 的完整可运行示例位于:

pages/index/index.vue

页面中包含联系人查询、模糊查询、新增、修改、删除、Android 通话记录读取、错误展示和 平台判断,并在每个调用位置写有注释。

注意事项

  • 新增、修改和删除会直接改变系统通讯录,真机测试前请备份重要联系人。
  • 修改和删除前应重新查询联系人,使用最新的 ContactInfo.id。
  • 更新接口接收的是修改后的完整公共字段,不是只传变更字段的局部更新接口。
  • limit 最大按 500 处理,大量数据请使用 offset 分页加载。
  • Android 通话记录权限较敏感,应只在功能确实需要时调用,并在隐私政策中说明用途。
  • iOS 和 HarmonyOS 页面应隐藏或禁用通话记录入口。
  • HarmonyOS 必须同时满足 ACL/Profile 签名授权和用户运行时授权。
  • 用户永久拒绝权限后,系统可能不再弹出授权窗口,需要引导用户前往系统设置开启。

更多好用插件推荐

隐私、权限声明

1. 本插件需要申请的系统权限列表:

Android:READ_CONTACTS、WRITE_CONTACTS、READ_CALL_LOG;iOS:通讯录;HarmonyOS:READ_CONTACTS、WRITE_CONTACTS

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件仅读写设备系统通讯录;Android 可读取系统通话记录。数据不会上传。

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

无