如何在没有 READ_CONTACTS 权限的情况下获取 Android 联系人详细信息

Posted

技术标签:

【中文标题】如何在没有 READ_CONTACTS 权限的情况下获取 Android 联系人详细信息【英文标题】:How to get Android Contact details without READ_CONTACTS permission 【发布时间】:2019-03-19 06:43:33 【问题描述】:

根据https://developer.android.com/guide/components/intents-common#Contacts的官方文档

您可以使用选择意图

public void selectContact() 
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType(ContactsContract.Contacts.CONTENT_TYPE);
if (intent.resolveActivity(getPackageManager()) != null) 
    startActivityForResult(intent, REQUEST_SELECT_CONTACT);

有关在获得联系人 URI 后如何检索联系人详细信息的信息,请参阅检索联系人的详细信息。请记住,当您使用上述意图检索联系人 URI 时,您不需要需要 READ_CONTACTS 权限来读取该联系人的详细信息。

它指向https://developer.android.com/training/contacts-provider/retrieve-details 以获取联系人的详细信息

当我按照上面链接中的说明操作时,我得到了

Caused by: java.lang.SecurityException: Permission Denial: reading com.android.providers.contacts.ContactsProvider2 uri content://com.android.contacts/data from pid=5313, uid=10087 requires android.permission.READ_CONTACTS, or grantUriPermission()

我已尝试通过

获取联系方式 加载器(如链接说明) getContentResolver().query() 尝试使用 lookupKey 和获取联系人 ID

每一种方式都会给出需要 android.permission.READ_CONTACTS 异常。 有没有按照文档所说的方式工作的示例?

最小、完整和可验证的示例,位于

https://github.com/aaronvargas/ContactsSSCCE

要使用和不使用 READ_CONTACTS 进行测试,您必须在系统应用设置中进行更改

-编辑

在https://issuetracker.google.com/issues/118400813https://issuetracker.google.com/issues/118400813Android 问题跟踪器上创建问题

【问题讨论】:

您的异常表明您没有使用从ACTION_PICK 返回的Uri。请提供minimal reproducible example,包括完整的堆栈跟踪以及生成堆栈跟踪的代码。 "tried both with lookupKey and getting the contact id" - 不是这样。您需要通过data.getData() 获取contactUri 并单独查询,无需任何选择 @CommonsWare,我添加了一个 SSCCE 以供参考。根据文档,我应该通过 lookupKey 获得对联系人行的临时权限。这就是文档指向获取联系方式的方式 @Bink,不,这个问题是“分配的”,所以也许会引起一些关注。如果您想在 Google 跟踪器(问题上方的网址)中为它投票,我们将不胜感激! 状态在跟踪器中被标记为固定。但是我在 Android 10/11 设备的更新版本中仍然面临这个问题。 【参考方案1】:

Android 的 ContactsContract API 数据存储在三个不同的表中:ContactsRawContactsData

您将获得通过contactUri 读取数据的临时权限,这意味着您只能从Contacts 表中读取详细信息,并且只能读取所选联系人。

这些是存储在Contacts表中可以获取的字段,其他字段如电话、电子邮件等存储在Data表中,需要READ_CONTACTS权限

_id
contact_chat_capability
contact_last_updated_timestamp
contact_presence
contact_status
contact_status_icon
contact_status_label
contact_status_res_package
contact_status_ts
custom_ringtone
dirty_contact
display_name
display_name_alt
display_name_reverse
display_name_source
has_email
has_phone_number
in_default_directory
in_visible_group
is_private
is_user_profile
last_time_contacted
link
link_count
link_type1
lookup
name_raw_contact_id
phonebook_bucket
phonebook_bucket_alt
phonebook_label
phonebook_label_alt
phonetic_name
phonetic_name_style
photo_file_id
photo_id
photo_thumb_uri
photo_uri
pinned
sec_custom_alert
sec_custom_vibration
sec_led
send_to_voicemail
sort_key
sort_key_alt
starred
times_contacted

你能做什么

如果您需要有关联系人的以下数据项之一:电话、电子邮件、地址,您可以切换到使用请求该特定类型的特定 ACTION_PICK 意图,然后您将可以访问有关的单个信息项选定的联系人。 例如,如果您的应用需要所选联系人的电话号码,请执行以下操作:

Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType(CommonDataKinds.Phone.CONTENT_TYPE);
startActivityForResult(intent, PICK_CONTACT_REQUEST);

然后,在onActivityResult中,你会得到选中的联系人+电话:

if (resultCode == RESULT_OK) 
       Uri phoneUri = data.getData();
       Cursor cursor = getContentResolver().query(phoneUri, null, null, null, null);
       DatabaseUtils.dumpCursor(cursor);

【讨论】:

你的回答很完整。那么您认为文档是错误的吗?它指出,从挑选意图中获取联系人 dataUri 后,您可以查询联系人详细信息。它指向通过lookupKey 显示查询的页面,这似乎不起作用。因此,要么 1)文档错误 2)Android 中存在一个错误,不允许通过选定的 lookupKey 查询行的权限,要么 3)我做错了。【参考方案2】:
    You need this permission in android Manifest 
    <uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>

   and need to grant the permission run something like this 

     private void requestContactPermission() 
        final String[] permissions = new String[]Manifest.permission.READ_CONTACTS;
        ActivityCompat.requestPermissions(this, permissions, REQUEST_CONTACT_PERM);
    

      private boolean isReadContactPermissionGranted() 
        return ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) 
          == PackageManager.PERMISSION_GRANTED;
       

  on Permission granted, you would get callback to your activity  

        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) 
        if (requestCode != REQUEST_CONTACT_PERM) 
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            return;
        
     if (grantResults.length != 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
            //call your contact pick method
              return;
        
      

所以最后在调用联系人选择器方法之前确保你有权限检查

            if (isReadContactPermissionGranted()) 
               //Start method
             else 
                requestContactPermission();
            

【讨论】:

根据文档,非常具体的是我不需要该权限“记住,当您使用上述意图检索联系人 URI 时,您 不需要读取该联系人详细信息的 READ_CONTACTS 权限。"

以上是关于如何在没有 READ_CONTACTS 权限的情况下获取 Android 联系人详细信息的主要内容,如果未能解决你的问题,请参考以下文章

Android 6.0 (Marshmallow) READ_CONTACTS 权限允许在权限被拒绝时读取联系人的姓名

在 MIUI 中检查权限 READ_CONTACTS

READ_CONTACTS 权限不起作用,除非我在 android SDK 23+ 上手动关闭和打开它

安卓手机如何开启联系人权限

如何在 Android 中自定义权限对话框?

如何在android中获取用户权限而不将其声明为清单