有没有办法从 Google 通讯录联系人 ID 中获取 Google People API 资源 ID? 答案:代码示例:

问题描述

我们将用户的 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

这个 contactIdPerson 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 脚本,您可以检索 contactIdresourceName 的映射,如下所示:

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()));
        }
    }
});