【问题标题】:checkSelfPermission returning PERMISSION_GRANTED for revoked permission with targetSdkVersion <= 22checkSelfPermission 返回 PERMISSION_GRANTED 以撤销 targetSdkVersion <= 22 的权限
【发布时间】:2017-07-17 18:16:34
【问题描述】:

我正在研究 Android Marshmallow 的新权限模型,但遇到了一个我觉得很奇怪的问题。

targetSdkVersion 22 的应用(因此尚未使用 Android Marshmallow 的新权限模型)在清单中声明 READ_CONTACTS 权限:

<uses-permission android:name="android.permission.READ_CONTACTS" />

并尝试通过Intent.ACTION_PICK读取联系人的电话号码:

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

在使用 Marshmallow MRA58K 的设备上运行时,我通过 ADB 安装应用程序后撤销权限后,ContextCompat.checkSelfPermission() 方法仍然返回PERMISSION_GRANTED,但稍后访问联系人时操作失败,因为游标没有记录被退回。据我了解,这是避免旧版应用崩溃的默认“回溯兼容性”策略。

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == PICK_CONTACT_REQUEST && resultCode == Activity.RESULT_OK) {
        Log.i("", "Permission granted: " + (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED));
        Uri contactUri = data.getData();
        Cursor c = null;
        try {
            c = getContentResolver().query(contactUri, new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER}, null, null, null);
            if (c != null && c.moveToFirst()) {
                Log.i("", "got phone number: " + c.getString(0));
            } else {
                Log.w("", "No data received");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (c != null) {
                c.close();
            }
        }
    } else {
        super.onActivityResult(requestCode, resultCode, data);
    }
}

如何在尝试操作之前安全地检测用户是否在权限之前明确?

我还尝试了https://github.com/googlesamples/android-RuntimePermissions 的官方 Google 示例,将 targetSdkVersion 设置为 22,结果相同:即使用户撤销了权限,它也会记录授予权限,然后操作失败。

谢谢 ;)

【问题讨论】:

  • “ContextCompat.checkSelfPermission() 方法仍然返回 PERMISSION_GRANTED”——正确。对于 targetSdkVersion 为 22 或更低的应用程序,checkSelfPermission() 将在 100% 的时间内返回 PERMISSION_GRANTED。 “在尝试操作之前,如何安全地检测用户是否在权限之前明确检测?” ——一般情况下你不能。在您的情况下,您可以尝试 query() 查找已知存在的内容(例如姓名),如果您得到零结果,则说明您无权访问联系人数据。
  • 请记住,如果您所做的只是在选择联系人时直接使用所选择的联系人,那么对于任何版本的 Android,您根本不需要 READ_CONTACTS,因为您自动仅授予所选联系人的访问权限。您可以尝试完全删除该权限,因为这会阻止用户撤销它。你的案例带来了一些有趣的效果;下周我会尝试进行一些相关的实验。
  • 嗯,这对我来说似乎是一个糟糕的 API 设计选择。那么在尝试操作之前没有其他方法可以检测到撤销的权限吗?也许使用 AppOps?
  • "那么在尝试操作之前是否没有其他方法可以检测到已撤销的权限?" - 当然。将您的 targetSdkVersion 提高到 23 并添加运行时权限支持。通过将 targetSdkVersion 设为 22 或更低,您明确表示您不想想要处理运行时权限。
  • FWIW,我为此写了a blog post,并就回归提交了an issue

标签: android android-6.0-marshmallow


【解决方案1】:

【讨论】:

  • 像魅力一样工作!谢谢
  • 我的用例有点不同(相机),但这是我发现的:用PermissionsChecker.checkSelfPermission 替换ContextCompat.checkSelfPermission 有助于检查您是否真的拥有权限。问题是,如果您基于此检查触发 requestPermissions 并且用户单击 DenyonRequestPermissionsResult 仍将在 grantResults 数组中收到 PERMISSION_GRANTED
  • @TWiStErRob 在这种情况下,理论上,您可以使用PermissionChecker 再次检查是否授予了请求的权限。但是,如果您使用targetSDK 22(或更低),如果用户授予权限,它将杀死应用程序进程并且不会调用您的回调。因此,正确处理此问题的唯一方法是升级到targetSDK 23
  • 谁能告诉我,哪个版本的支持库PermissionChecker类引入了?
  • @AkhileshKumar 23 人
【解决方案2】:

为了使用新的权限模型(并检查您的应用是否有权限),您需要将目标 SDK 更新到 23。保持目标 22 没有任何意义。

【讨论】:

  • 实际上在某些情况下确实有意义。
猜你喜欢
  • 2016-01-29
  • 2021-03-03
  • 1970-01-01
  • 1970-01-01
  • 2016-06-05
  • 2016-02-02
  • 1970-01-01
  • 1970-01-01
  • 2011-10-14
相关资源
最近更新 更多