能力 · API
Contact Picker API
发布于
Contact Picker API 即 navigator.contacts,在浏览器自己绘制的选择器中请用户从设备通讯录挑选条目,只把用户同意分享的联系人及属性(name、email、tel、address、icon)交给页面。没有批量读取,也没有持久授权:每次调用都会再次显示选择器。
Android 上的 Chrome 80(Android 6 及以上)是唯一的稳定实现;address 与 icon 在 Chrome 84 加入。桌面 Chrome、Edge 与 Firefox 不暴露 navigator.contacts。iOS 14.5 的 Safari 把它放在「设置 > Safari 浏览器 > 高级」下名为「Contact Picker API」的实验性功能开关之后(默认关闭);Samsung Internet 14.0 至 21 暴露了接口,但打开选择器时失败(BCD api.ContactsManager)。MDN 将该 API 标记为实验性且不属于 Baseline。
navigator.contacts.select(properties)navigator.contacts.select(properties, options)navigator.contacts.getProperties()select() 返回 Promise<sequence<ContactInfo>>,用户取消时以空数组兑现。getProperties() 返回 Promise<sequence<ContactProperty>>,列出设备能提供的属性。两者都在只暴露于 Window 的 [SecureContext] 接口上;select() 还要求顶层浏览上下文与瞬时用户激活,getProperties() 两者都不要求。
select() 接受要请求的属性列表和一个选项;getProperties() 不接受参数。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
properties |
sequence<ContactProperty> |
是 | "name"、"email"、"tel"、"address"、"icon" 中的一个或多个。空列表会拒绝;浏览器不支持的值会拒绝。 |
options.multiple |
boolean |
否 | 默认 false:选择器只允许选一个联系人。true 允许多选。 |
兑现的每个 ContactInfo 只携带被请求的成员,且每个成员都是序列,因为一个联系人可能有多个值:
| 成员 | 类型 | 出现条件 |
|---|---|---|
name |
sequence<DOMString> |
请求了 "name" |
email |
sequence<DOMString> |
请求了 "email" |
tel |
sequence<DOMString> |
请求了 "tel" |
address |
sequence<ContactAddress> |
请求了 "address";ContactAddress 与 PaymentAddress 同形(country、addressLine、region、city、postalCode 等) |
icon |
sequence<Blob> |
请求了 "icon" |
用户在选择器里选择不分享的成员,与联系人本来就没有的成员无法区分:两者都返回空序列。
select() 以三个名称之一拒绝;getProperties() 不会拒绝。
| 异常 | 条件 |
|---|---|
InvalidStateError |
调用方不是顶层 traversable(例如在 iframe 中);该 navigable 已有选择器在显示;或呈现选择器、读取联系人源失败。 |
SecurityError |
调用时没有瞬时用户激活。 |
TypeError |
properties 为空,或包含联系人源支持集合之外的属性(Chrome 80 至 83 中的 "address" 与 "icon")。 |
Chromium 在最后一种 InvalidStateError 情形上有偏差:Android 选择器无法启动时,它以 TypeError: Unable to open a contact selector 拒绝。
两个示例都用 Chrome 文档给出的 'contacts' in navigator && 'ContactsManager' in window 做特性检测,并回退到普通表单字段,因为该 API 在所有桌面浏览器以及未开启功能开关的 iOS Safari 上都不存在。
选一个收件人邮箱,缺少支持时改为手动输入
Section titled “选一个收件人邮箱,缺少支持时改为手动输入”在 click 处理函数内调用 select(),把空结果当作取消而非错误。API 缺失时显示 <input type="email">,而不是隐藏整个功能。
const pickButton = document.querySelector('#pick-recipient');const manualField = document.querySelector('#recipient-email');
const supported = 'contacts' in navigator && 'ContactsManager' in window;pickButton.hidden = !supported;manualField.hidden = supported;
pickButton.addEventListener('click', async () => { try { const [contact] = await navigator.contacts.select(['name', 'email']); if (!contact) return; // 用户取消 const email = contact.email[0]; if (!email) { manualField.hidden = false; // 该联系人没有邮箱 return; } manualField.value = email; } catch (err) { console.error(`${err.name}: ${err.message}`); manualField.hidden = false; }});即使选择成功,读取 contact.email[0] 也可能得到 undefined,所以手动输入框作为最后手段保留在 DOM 中,而不是被移除。
按设备能返回的属性裁剪请求
Section titled “按设备能返回的属性裁剪请求”getProperties() 在你请求之前告诉你 address 或 icon 是否可用;请求不受支持的属性会让整个调用以 TypeError 拒绝。先过滤期望列表,再打开多选选择器。
async function pickAttendees(wanted = ['name', 'tel', 'icon']) { if (!('contacts' in navigator && 'ContactsManager' in window)) { return null; // 调用方显示自己的参会人表单 } const available = await navigator.contacts.getProperties(); const props = wanted.filter((p) => available.includes(p)); if (props.length === 0) return null;
const contacts = await navigator.contacts.select(props, { multiple: true }); return contacts.map((c) => ({ name: c.name?.[0] ?? '', tel: c.tel?.[0] ?? '', avatar: c.icon?.[0] ? URL.createObjectURL(c.icon[0]) : null, }));}getProperties() 不需要用户手势,可以在页面加载时运行并决定渲染哪些按钮;只有 select() 调用必须等待点击。
- Web Share API,PWA 能从手势中打开的另一个系统面板
- Payment Request API,
ContactAddress复用了它的PaymentAddress结构 - Contact Picker API: select() method(w3.org)
- A contact picker for the web(developer.chrome.com)
- Chrome Platform Status: Contacts API(chromestatus.com)
规范
| 规范 | 状态 |
|---|---|
| Contact Picker(联系人选择器) | WICG 草案 |
| Contact Picker API: select() method | W3C 草案 |
- 图例
- 支持
- 部分支持
- 需开启标志
- 不支持
- 未知
| 浏览器 / 平台 | 支持 | 版本 | 置信度 | 来源 | 备注 |
|---|---|---|---|---|---|
| Chrome (Desktop) | 不支持 | — | 高 | 来源 | 1 |
| Chrome (Android) | 支持 | 80 | 高 | 来源 | — |
| Edge (Desktop) | 不支持 | — | 高 | 来源 | 23 |
| Firefox (Desktop) | 不支持 | — | 高 | 来源 | 4 |
| Firefox (Android) | 不支持 | — | 高 | 来源 | 56 |
| Safari (macOS) | 不支持 | — | 高 | 来源 | 7 |
| Safari (iOS) | 需开启标志 | 14.5 | 高 | 来源 | 8 |
| Samsung Internet | 不支持 | removed in 22.0 | 高 | 来源 | 910 |
| WebView (Android) | 支持 | 80 | 高 | 来源 | 11 |
- browser-compat-data 未记录 Chrome 的支持。
- browser-compat-data 未记录 Edge 的支持。
- 由 browser-compat-data 镜像自 Chrome 的数据推导。
- 实现跟踪:https://bugzil.la/1756767。
- 实现跟踪:https://bugzil.la/1756767。
- 由 browser-compat-data 镜像自 Firefox 的数据推导。
- browser-compat-data 未记录 Safari 的支持。
- 需开启 `Contact Picker API` 偏好设置。
- Samsung Internet 自 14.0 起支持,22.0 中移除。
- 该 API 虽已暴露,但打开联系人选择器时会失败。
- 由 browser-compat-data 镜像自 Chrome Android 的数据推导。