问题描述
我们将用户的 contactId 存储在我们的数据库中,并在用户向我们的应用发出请求时使用它来获取/编辑/删除联系人。现在 Google Contacts API 即将停用,我们需要使用资源 ID 为这些操作调用 Google People API。
有没有办法从 Google 通讯录联系人 ID 中获取 Google People API 资源 ID?
我在 Stackoverflow 中找到了 following answer:
Contacts API 和 People API 是独立的 API,并不意味着 互操作。
也就是说,逆向工程的方法是采用 Contacts API 联系人 ID,解析该十六进制值,将其转换为 十进制,并为其添加一个“c”前缀,这将成为 People API 人员资源 ID。
例如如果 Contacts API 联系人 ID 为 100,则 People API 人员 ID 将是 c256。当您从 People API 获取联系人时 以这种方式,它将具有加入的个人资料信息,如果 存在。
我尝试了该解决方案并且它正在工作,但需要知道我们是否可以使用此转换无错误(即没有任何异常)将相应的资源 ID 填充到联系人 ID。
解决方法
答案:
虽然 this answer 中提供的解决方法似乎有效,但我认为有更多记录的方法可以根据 resourceName
查找 People API 的 contactId
。
这个 contactId
是 Person resource 的一部分,只要连接来自 CONTACTS
。
更具体地说,可以在以下资源中找到此信息:
{
"resourceName": "people/c...","metadata": {
"sources": [
{
"type": "CONTACT","id": "CONTACT_ID" // Converting to decimal and adding "people/c" results in resource name
}
]
}
}
因此,如果您有一个有效的 contactId
数组,您可以通过列出您的连接(参见 people.connections.list)并检查 resourceNames
是否匹配来找到相应的 contactId
嵌套字段中的 id
并检索该连接的 resourceName
(如果是这种情况)。
代码示例:
例如,使用 Apps 脚本,您可以检索 contactId
和 resourceName
的映射,如下所示:
function getResourceNamesFromContactIds(contactIds) { // contactIds: array with valid contactIds
const resourceName = "people/me";
const optionalArgs = {
personFields: "metadata",sources: "READ_SOURCE_TYPE_CONTACT"
}
const connections = People.People.Connections.list(resourceName,optionalArgs)["connections"];
const mapping = contactIds.map(contactId => {
const foundConnection = connections.find(connection => {
return contactId == connection["metadata"]["sources"][0]["id"];
});
if (foundConnection) {
return {
contactId: contactId,resourceName: foundConnection["resourceName"]
}
}
}).filter(el => el);
return mapping;
}
,
接受的答案不适用于没有电子邮件地址的联系人。
不需要从 person.emailAddresses
获取元数据对象,我们可以直接从 person 对象获取它,不需要任何其他字段出现在 person 的信息中。
此外,接受的答案假定第一个来源始终是“CONTACT”类型,但情况可能并非如此,在这种情况下,您可能会得到错误的联系人 ID
这是改进的版本(Java):
List<Person> people = getPeople();// fetch all pages of the user contacts,with "personFields" set to "metadata" only.
Map<String,String> mapping = new HashMap<>();
people.forEach(person -> {
PersonMetadata metadata = person.getMetadata();
if (metadata != null) {
List<Source> sources = metadata.getSources();
if (sources != null) {
sources.stream()
.filter(srcObj -> "CONTACT".equalsIgnoreCase(srcObj.getType()))
.findFirst()
.ifPresent(source ->
mapping.put(source.getId(),person.getResourceName()));
}
}
});