【发布时间】: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