Contacts 通讯录管理¶
Contacts 模块提供了通讯录管理功能。你可以使用它来读取、搜索、创建和删除联系人。
守护进程支持: 有限支持。requestAccess 需要 UI 交互,其他操作需要预先获得权限。
快速开始¶
// 请求通讯录权限
const result = contacts.requestAccess();
if (!result.granted) {
console.error('权限被拒绝:', result.error);
}
// 检查权限
if (contacts.isAuthorized()) {
// 获取所有联系人
const all = contacts.getAll();
console.log(`共有 ${all.length} 个联系人`);
// 搜索联系人
const results = contacts.search('张三');
console.log('搜索结果:', results);
// 按电话搜索
const byPhone = contacts.searchByPhone('138');
console.log('电话匹配:', byPhone);
}
API 参考¶
权限管理¶
contacts.requestAccess()¶
请求通讯录访问权限。返回: { granted: boolean, error?: string }
const result = contacts.requestAccess();
if (result.granted) {
console.log('权限已授予');
} else {
console.error('权限被拒绝:', result.error);
}
contacts.getAccessStatus()¶
获取权限状态。返回: 'authorized' | 'denied' | 'restricted' | 'notDetermined'
const status = contacts.getAccessStatus();
console.log('权限状态:', status);
contacts.isAuthorized()¶
检查是否已授权。返回: boolean
if (contacts.isAuthorized()) {
console.log('已授权访问通讯录');
}
获取联系人¶
contacts.getAll(offset?, limit?)¶
获取所有联系人。参数: offset (number, 可选), limit (number, 可选) 返回: Contact[]
Contact 对象结构:
{
id: string, // 联系人 ID
name: string, // 姓名
givenName: string, // 名
familyName: string, // 姓
nickname: string, // 昵称
organizationName: string,// 公司
departmentName: string, // 部门
jobTitle: string, // 职位
phones: [ // 电话列表
{ label: string, value: string }
],
emails: [ // 邮箱列表
{ label: string, value: string }
],
birthday: { // 生日
year: number,
month: number,
day: number
},
note: string // 备注
}
// 获取所有联系人
const all = contacts.getAll();
console.log(`共有 ${all.length} 个联系人`);
// 分页获取
const page1 = contacts.getAll(0, 20); // 前 20 个
const page2 = contacts.getAll(20, 20); // 第 21-40 个
contacts.getCount()¶
获取联系人总数。返回: number
const count = contacts.getCount();
console.log(`通讯录中有 ${count} 个联系人`);
contacts.getById(id)¶
根据 ID 获取联系人。参数: id (string) 返回: Contact | null
const contact = contacts.getById('ABC123');
if (contact) {
console.log('联系人:', contact.name);
}
搜索联系人¶
contacts.search(query)¶
按姓名搜索联系人。参数: query (string) 返回: Contact[]
// 搜索包含"张"的联系人
const results = contacts.search('张');
console.log(`找到 ${results.length} 个结果`);
contacts.searchByPhone(phone)¶
按电话号码搜索联系人。参数: phone (string) 返回: Contact[]
// 搜索包含"138"的电话
const results = contacts.searchByPhone('138');
results.forEach(contact => {
console.log(`${contact.name}: ${contact.phones[0].value}`);
});
创建和删除¶
contacts.create(data)¶
创建新联系人。参数: data (object) 返回: { success: boolean, id?: string, error?: string }
contact 参数结构:
{
givenName: string, // 名(必填)
familyName?: string, // 姓
nickname?: string, // 昵称
organizationName?: string,// 公司
departmentName?: string, // 部门
jobTitle?: string, // 职位
phones?: [ // 电话列表
{ label: string, value: string }
],
emails?: [ // 邮箱列表
{ label: string, value: string }
],
birthday?: { // 生日
year: number,
month: number,
day: number
},
note?: string // 备注
}
const result = contacts.create({
givenName: '三',
familyName: '张',
organizationName: 'ABC 公司',
phones: [
{ label: '手机', value: '13800138000' },
{ label: '工作', value: '010-12345678' }
],
emails: [
{ label: '工作', value: 'zhangsan@abc.com' }
],
birthday: { year: 1990, month: 1, day: 1 },
note: '重要客户'
});
if (result.success) {
console.log('联系人创建成功,ID:', result.id);
} else {
console.error('创建失败:', result.error);
}
contacts.delete(id)¶
删除联系人。参数: id (string) 返回: { success: boolean, error?: string }
const result = contacts.delete('ABC123');
if (result.success) {
console.log('联系人已删除');
} else {
console.error('删除失败:', result.error);
}
分组管理¶
contacts.getGroups()¶
获取所有联系人分组。返回: [{ id, name }]
const groups = contacts.getGroups();
groups.forEach(group => {
console.log(`分组: ${group.name} (${group.id})`);
});
完整示例¶
示例 1: 导出通讯录¶
function exportContacts() {
if (!contacts.isAuthorized()) {
console.log('请先授权访问通讯录');
const result = contacts.requestAccess();
if (!result.granted) {
console.error('权限被拒绝:', result.error);
return;
}
}
const all = contacts.getAll();
const data = all.map(c => ({
姓名: c.name,
电话: c.phones.map(p => p.value).join(', '),
邮箱: c.emails.map(e => e.value).join(', '),
公司: c.organizationName,
职位: c.jobTitle
}));
const json = JSON.stringify(data, null, 2);
const path = file.documentsPath() + '/contacts_export.json';
file.write(path, json);
console.log(`已导出 ${all.length} 个联系人到 ${path}`);
}
exportContacts();
示例 2: 查找重复联系人¶
function findDuplicates() {
const all = contacts.getAll();
const phoneMap = {};
const duplicates = [];
all.forEach(contact => {
contact.phones.forEach(phone => {
const number = phone.value.replace(/\D/g, '');
if (phoneMap[number]) {
duplicates.push({
phone: number,
contacts: [phoneMap[number], contact.name]
});
} else {
phoneMap[number] = contact.name;
}
});
});
console.log(`找到 ${duplicates.length} 个重复电话:`);
duplicates.forEach(d => {
console.log(`${d.phone}: ${d.contacts.join(', ')}`);
});
}
findDuplicates();
示例 3: 批量导入联系人¶
function importContacts(data) {
let success = 0;
let failed = 0;
data.forEach(item => {
const contact = {
givenName: item.name,
phones: [{ label: '手机', value: item.phone }],
emails: item.email ? [{ label: '工作', value: item.email }] : [],
organizationName: item.company || ''
};
const result = contacts.create(contact);
if (result.success) {
success++;
} else {
failed++;
console.error(`创建失败 (${item.name}):`, result.error);
}
});
console.log(`导入完成: 成功 ${success}, 失败 ${failed}`);
}
const data = [
{ name: '张三', phone: '13800138000', email: 'zhangsan@example.com', company: 'ABC' },
{ name: '李四', phone: '13900139000', email: 'lisi@example.com', company: 'XYZ' }
];
importContacts(data);
示例 4: 生日提醒¶
function checkBirthdays() {
const all = contacts.getAll();
const today = new Date();
const month = today.getMonth() + 1;
const day = today.getDate();
const birthdays = all.filter(c => {
return c.birthday &&
c.birthday.month === month &&
c.birthday.day === day;
});
if (birthdays.length > 0) {
const names = birthdays.map(c => c.name).join(', ');
notification.send('生日提醒', `今天是 ${names} 的生日!`);
console.log(`今天有 ${birthdays.length} 个生日`);
} else {
console.log('今天没有生日');
}
}
checkBirthdays();
示例 5: 联系人统计¶
function analyzeContacts() {
const all = contacts.getAll();
// 统计
const stats = {
total: all.length,
withPhone: 0,
withEmail: 0,
withCompany: 0,
withBirthday: 0
};
all.forEach(c => {
if (c.phones.length > 0) stats.withPhone++;
if (c.emails.length > 0) stats.withEmail++;
if (c.organizationName) stats.withCompany++;
if (c.birthday) stats.withBirthday++;
});
console.log('=== 通讯录统计 ===');
console.log(`总数: ${stats.total}`);
console.log(`有电话: ${stats.withPhone} (${(stats.withPhone/stats.total*100).toFixed(1)}%)`);
console.log(`有邮箱: ${stats.withEmail} (${(stats.withEmail/stats.total*100).toFixed(1)}%)`);
console.log(`有公司: ${stats.withCompany} (${(stats.withCompany/stats.total*100).toFixed(1)}%)`);
console.log(`有生日: ${stats.withBirthday} (${(stats.withBirthday/stats.total*100).toFixed(1)}%)`);
}
analyzeContacts();
最佳实践¶
1. 检查权限¶
// ✅ 正确
if (contacts.isAuthorized()) {
const all = contacts.getAll();
}
// ❌ 错误 - 不检查权限
const all = contacts.getAll(); // 可能返回空数组
2. 使用分页¶
// ✅ 正确 - 大量联系人时使用分页
const pageSize = 50;
for (let i = 0; i < contacts.getCount(); i += pageSize) {
const page = contacts.getAll(i, pageSize);
processContacts(page);
}
// ❌ 错误 - 一次性加载所有联系人
const all = contacts.getAll(); // 可能很慢
3. 处理空值¶
// ✅ 正确
const contact = contacts.getById(id);
if (contact) {
console.log(contact.name);
}
// ❌ 错误 - 不检查空值
const contact = contacts.getById(id);
console.log(contact.name); // 可能报错
4. 验证必填字段¶
// ✅ 正确
if (name && name.trim()) {
contacts.create({ givenName: name });
}
// ❌ 错误 - 不验证
contacts.create({ givenName: '' }); // 会失败
注意事项¶
- 权限要求: 首次使用需要请求通讯录权限
- 必填字段: 创建联系人时
givenName是必填的 - ID 唯一性: 联系人 ID 由系统生成,不可自定义
- 分页性能: 大量联系人时建议使用分页加载
- 搜索匹配: 搜索是模糊匹配,不区分大小写
- 电话格式: 电话号码保留原始格式,包含空格和符号
- 生日格式: 生日的 month 范围是 1-12,day 范围是 1-31
- 线程安全: 所有操作都是线程安全的