如果你需要 Capacitor 社区联系人插件的替代方案,最完整的直接替换方案是 @capgo/capacitor-contacts。它涵盖了 @capacitor-community/contacts 的所有功能(读取、创建、删除和选择联系人),并增加了在不更改 ID 的情况下更新联系人、分页、分组、账户、原生联系人界面以及 Android 上的免权限选择功能,这对 Google Play 2027 年联系人政策至关重要。本指南对比了两者并映射了每个调用,让你可以在一个下午内完成迁移。
为什么要寻找替代方案
@capacitor-community/contacts 该插件仍在维护,并发布了 Capacitor 8 版本。对于简单的读取和创建流程,它是一个不错的选择。但团队通常会因为以下原因而弃用它:
- 没有更新方法。 你可以创建和删除联系人,但无法编辑。删除后重新创建会生成新的 ID,这会破坏你存储的任何引用,并可能丢失插件未读取的数据。
- 没有分页。
getContacts一次调用返回整个通讯录。在拥有 5,000 个联系人和照片的设备上,这会非常缓慢且占用大量内存。 - 在 Android 上选择联系人需要权限。 Android
pickContact在打开选择器之前请求联系人权限组,然后从通讯录中读取联系人。在 Google Play 的联系人权限政策下,目标为 Android 17 的应用只能保留READ_CONTACTS用于核心功能。 - 没有分组、账户或原生界面。 无法列出群组、选择新联系人保存到的账户,或打开系统“新建联系人”表单。
功能对比
| 功能 | @capacitor-community/contacts 8.0 | @capgo/capacitor-contacts 8.1 |
|---|---|---|
| 读取单个 / 所有联系人 | getContact, getContacts |
getContactById, getContacts |
| 字段选择 | projection 对象 |
fields 数组 |
| 分页 | 否 | limit, offset |
| 统计联系人数量 | 否 | countContacts |
| 创建 | createContact |
createContact |
| 就地更新 | 否 | updateContactById |
| 删除 | deleteContact |
deleteContactById |
| 选择一个联系人 | pickContact |
pickContact |
| 选择多个联系人 | 否 | pickContacts({ multiple: true }) |
| 无需权限即可选择一个电话/邮箱/地址 | 否 | pickContacts({ property }) |
| 分组 | 否 | getGroups, getGroupById, createGroup, deleteGroupById |
| 账户 | 否 | getAccounts |
| 原生创建 / 查看 / 编辑界面 | 否 | displayCreateContact, displayContactById, displayUpdateContactById |
| 读写权限状态分离 | 否(单一别名) | readContacts, writeContacts |
| iOS 受限访问状态 | limited |
limited |
| 打开设置 | 否 | openSettings |
安装
bun add @capgo/capacitor-contacts
bunx cap sync
该插件不会向 Android 清单文件添加权限。请仅添加实际使用的权限:
<!-- Needed for getContacts, getContactById, countContacts, groups, accounts -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
<!-- Needed for createContact, updateContactById, deleteContactById, groups writes -->
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
在 iOS 上,添加 NSContactsUsageDescription 改为 Info.plist 如果你需要读取或写入通讯录。仅选择联系人则不需要此权限。
迁移指南:逐个调用
权限
// Before
import { Contacts } from '@capacitor-community/contacts';
const perm = await Contacts.requestPermissions();
if (perm.contacts !== 'granted') return;
// After
import { CapacitorContacts } from '@capgo/capacitor-contacts';
const status = await CapacitorContacts.requestPermissions({ permissions: ['readContacts'] });
if (status.readContacts !== 'granted' && status.readContacts !== 'limited') {
await CapacitorContacts.openSettings();
return;
}
在 iOS 18 及更高版本中,用户可以授权访问部分联系人。插件会将此报告为 limited。请将其视为已授权,并仅预期获取共享的联系人。
读取所有联系人
// Before: whole address book, projection object
const { contacts } = await Contacts.getContacts({
projection: { name: true, phones: true, emails: true },
});
const first = contacts[0];
console.log(first.name?.display, first.phones?.[0]?.number);
// After: fields array, paginated
const pageSize = 200;
let offset = 0;
for (;;) {
const { contacts } = await CapacitorContacts.getContacts({
fields: ['displayName', 'givenName', 'familyName', 'phoneNumbers', 'emailAddresses'],
limit: pageSize,
offset,
});
render(contacts);
if (contacts.length < pageSize) break;
offset += pageSize;
}
declare function render(list: unknown[]): void;
使用 countContacts() 如果你希望显示进度条,请先执行此操作。
读取单个联系人
// Before
const { contact } = await Contacts.getContact({
contactId: id,
projection: { name: true, phones: true },
});
// After
const { contact } = await CapacitorContacts.getContactById({
id,
fields: ['displayName', 'phoneNumbers'],
});
if (!contact) console.log('Not found');
创建联系人
// Before
const { contactId } = await Contacts.createContact({
contact: {
name: { given: 'Ada', family: 'Lovelace' },
phones: [{ type: PhoneType.Mobile, number: '+44 20 7946 0000' }],
emails: [{ type: EmailType.Work, address: 'ada@example.com' }],
},
});
// After
const { id } = await CapacitorContacts.createContact({
contact: {
givenName: 'Ada',
familyName: 'Lovelace',
phoneNumbers: [{ type: 'MOBILE', value: '+44 20 7946 0000' }],
emailAddresses: [{ type: 'WORK', value: 'ada@example.com' }],
},
});
displayName 在 Capgo 插件中是只读的。写入 givenName 以及 familyName,设备会格式化显示名称。
更新联系人(新建)
await CapacitorContacts.updateContactById({
id,
contact: {
givenName: 'Ada',
familyName: 'King',
jobTitle: 'Analyst',
phoneNumbers: [{ type: 'MOBILE', value: '+44 20 7946 0000' }],
},
});
ID 保持不变,因此你保存的任何引用仍然有效。先读取联系人,然后返回你想保留的字段,以免意外清除某些内容。
如果你希望让用户自行编辑,请打开系统编辑器:
await CapacitorContacts.displayUpdateContactById({ id });
删除联系人
// Before
await Contacts.deleteContact({ contactId: id });
// After
await CapacitorContacts.deleteContactById({ id });
选择联系人
// Before: requests the contacts permission on Android first
const { contact } = await Contacts.pickContact({
projection: { name: true, phones: true },
});
// After: one phone number, no permission on Android or iOS
import { ContactProperty } from '@capgo/capacitor-contacts';
const { contacts } = await CapacitorContacts.pickContacts({
property: ContactProperty.PhoneNumber,
});
const phone = contacts[0]?.phoneNumbers?.[0]?.value;
如果你需要从选择器中获取完整的联系人记录,请调用 pickContact() 无需 property。在 Android 上,仅当 READ_CONTACTS 被授予权限时,才会返回完整联系人。
字段映射
| 社区载荷 | Capgo Contact |
|---|---|
contactId |
id |
name.display |
displayName (只读) |
name.given / middle / family |
givenName / middleName / familyName |
name.prefix / suffix |
namePrefix / nameSuffix |
organization.company |
organizationName |
organization.jobTitle |
jobTitle |
birthday { day, month, year } |
birthday { day, month, year } |
note |
note |
phones[].number |
phoneNumbers[].value |
emails[].address |
emailAddresses[].value |
urls[] (字符串) |
urlAddresses[].value |
postalAddresses[].region / postcode |
postalAddresses[].state / postalCode |
image.base64String |
photo (base64 字符串) |
类型值也会变:Capgo 插件使用大写字符串,例如 'MOBILE', 'HOME', 'WORK' 用于手机号和邮箱。
逐屏迁移
这两个插件使用不同的原生名称注册(Contacts 以及 CapacitorContacts), 这样你可以在迁移调用点的同时把两者一起安装。一个小适配器可让应用其余部分保持不变:
import { CapacitorContacts } from '@capgo/capacitor-contacts';
export interface AppContact {
id: string;
name: string;
phones: string[];
}
export async function listContacts(limit = 200, offset = 0): Promise<AppContact[]> {
const { contacts } = await CapacitorContacts.getContacts({
fields: ['displayName', 'phoneNumbers'],
limit,
offset,
});
return contacts.map((c) => ({
id: c.id ?? '',
name: c.displayName ?? '',
phones: (c.phoneNumbers ?? []).map((p) => p.value),
}));
}
当最后一个调用点迁移完成后,移除社区插件,运行 bunx cap sync,并检查合并后的 Android manifest,确认只保留你需要的权限。
故障排除
getContacts 在 iOS 上返回空列表。 用户授予了有限访问权限且未共享任何联系人,或拒绝了访问。检查 readContacts 并提供 openSettings().
在 Android 上,创建的联系人未显示在特定账户中。 传入一个 account (来自 getAccounts()),在创建联系人时使用。
照片会让列表变慢。 请勿请求 photo 在列表视图中。请使用 getContactById 当用户打开联系人时。
Play Console 标记 READ_CONTACTS. 将邀请和分享流程移至 pickContacts({ property }) 如果其他功能不需要,请移除该权限。
发布
更换插件属于原生变更,因此需要商店构建。 Capgo 构建 可以在云端生成 iOS 和 Android 构建。之后,对联系人界面的修复属于 JavaScript,可以通过 Capgo 实时更新发布。完整的 API 位于 contacts 插件文档.