获取Android手机联系人的跨设备唯一ID

6
我需要查询 Android 设备中的联系人,以便在我的项目中使用,并且需要以一种可以在应用程序实例和电话簿联系人之间建立关联的方式保存它们。

我发现每个联系人的 CONTACT_ID(引用了_ID)可能会在设备之间更改,因此如果我切换到其他 Android 设备,该 ID 将无效。一个临时解决方案是使用联系人的SOURCE_ID,它是一个字符串,可唯一地标识该行与其源帐户的联系。该解决方案非常好,因为如果联系人来自(例如)Google 帐户,则每个设备上都将保持完全相同的 ID。问题是 - 并非所有联系人都有 SOURCE_ID。

还可以使用其数据作为过滤器查询特定联系人,这可能起到唯一的 ID 作用,例如他的电话号码等...但是每个数据都有缺陷。例如:一个联系人可能有多个电话号码(这仍然可以接受),而且号码可能会有所不同(例如:202-555-0105 相当于 +1-202-555-0105,也相当于 (202) 555-0105 和 2025550105)。

编辑:并非所有联系人都有电话号码,那该怎么办呢?

因此,面临这个问题 -
如何获取 Android 电话簿中联系人的唯一标识符,以便它们在跨设备时保持相同?

注意:IOS 默认情况下可以实现(参见 文档)-

表示同一人的不同帐户中的联系人可能会自动链接在一起。链接的联系人显示为统一的联系人,显示在 OS X 和 iOS 应用程序中。统一的联系人是合并到一个联系人中的一组链接联系人的内存中的临时视图。

默认情况下,Contacts 框架返回统一的联系人。每个获取到的统一联系人(CNContact)对象都有自己的唯一标识符,与集合中任何单个联系人的标识符都不同。应使用其标识符重新获取统一联系人。

1个回答

3
您要查找的是LOOKUP_KEY
一个不透明的值,其中包含有关如何查找联系人的提示,如果由于同步或聚合而更改其行ID,则可以使用该值。
要获取联系人LOOKUP_KEY,请遍历您的联系人,这是一个示例:
注意:<uses-permission android:name="android.permission.READ_CONTACTS" />是必需的。
val contentUri = ContactsContract.Contacts.CONTENT_URI
val cursor = context?.contentResolver?.query(contentUri, null, null, null, null)
if (cursor != null) {
    while (cursor.moveToNext()) {
        val id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID))
        val name =
            cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY))
        val lookupKey =
            cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)) 
    }
}
cursor?.close()

以下是如何检索具有LOOKUP_KEY联系人的方法:

val lookupKey = "0r1-3C263544104632"
val lookupUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey)
val uri = ContactsContract.Contacts.lookupContact(contentResolver, lookupUri)
val cursor = context?.contentResolver?.query(uri, null, null, null, null)
if (cursor != null) {
    while (cursor.moveToNext()) {
        val id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID))
        val name =
            cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY))
    }
}
cursor?.close()
}

请注意,联系人必须进行同步才能避免重新生成LOOKUP_KEYLOOKUP_KEY将为每个联系人生成,但是,如果未设置帐户并且未进行同步,则每当联系人被修改时,LOOKUP_KEY将被重新生成。
因此,如果设备已同步,则始终会有一个唯一的LOOKUP_KEYLOOKUP_KEY依赖于Google Cloud,这可能是Apple使用的相同解决方案。
由于大多数Android用户依赖Google服务,因此Android设备很少没有Google帐户。
很遗憾,这是获得唯一标识符的最佳方法,但是,如果您愿意,可以将用户电话号码与其他联系人详细信息组合哈希处理,但无法保证此方法有效,因为联系人可能会更改。 如果您的用户已注册并且您拥有他们的信息,则可以在后端检查哪些哈希值与您的期望匹配,然后根据自己的同步工作。

如果您想尝试一下,我已经创建了一个示例应用程序,其中包含实现,您可以浏览您的联系人并找到查找键,以及使用查找键检索联系人。

我还建议您查看SyncAdapter


谢谢您的回答,但这不是我要找的。您的答案是在联系人ID更改后获取正确联系人ID的正确方式。但我的问题是当我使用多个Android设备(或切换到新设备)时。我希望用户能够在不破坏应用程序在联系人部分的功能的情况下切换设备。 - lior_13
如果Android设备与Google帐户同步,那么当你切换设备并重新同步时,你将能够在跨设备中使用相同的LOOKUP_KEY搜索联系人。只要帐户和设备同步即可。 - Rodrigo Queiroz
好的,我明白你的意思。所以,如果同步关闭或新设备尚未与帐户同步,并且联系人详细信息已更改,则新设备上的LOOKUP_KEY将无法链接到正确的联系人?如果是这样,那么无论如何,我该怎么做才能100%确定我正在谈论同一个联系人? - lior_13
是的,LOOKUP_KEY 保证为每个联系人生成,但是如果该账户未同步,则在每次联系人被修改时 LOOKUP_KEY 将会更改。考虑到这一点,如果设备已同步,您将始终拥有唯一的 LOOKUP_KEYLOOKUP_KEY 依赖于 Google Cloud,这可能是 Apple 使用的相同解决方案。一个 Android 设备没有谷歌帐户并不同步的情况非常罕见。我已更新了答案,提供了更多信息。 - Rodrigo Queiroz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接