跳转至正文

Capacitor Community Contacts 替代方案

@capacitor-community/contacts 插件的替代方案:支持更新联系人、群组,支持分页和免权限选择,并附完整迁移指南。

Capgo 插件插图,用于 Capacitor 联系人插件对比

如果你需要 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 插件文档.

为 Capacitor 应用提供 Live Updates

当 Web 层出现线上 Bug 时,通过 Capgo 发布修复,而不用等 App Store 审核好几天。用户会在后台收到更新,原生变更则仍走正常审核流程。

博客最新动态

Capgo 为你提供打造真正专业的移动应用所需的最有价值的洞察。