Android权限识别异常:如何区分权限授予与拒绝状态?
看起来你遇到的问题是因为Android 10(API 29)及以上版本对READ_PHONE_STATE权限的行为做了重大调整,导致只通过grantResults数组判断权限状态会出现偏差。我来给你拆解原因和解决方案:
为什么grantResults[0]总是返回0?
从Android 10开始,Google限制了普通应用获取设备标识符(比如IMEI、序列号)的能力。当你的应用targetSdkVersion >=29时,即使用户拒绝了READ_PHONE_STATE权限,系统可能仍然会授予该权限的基础部分(比如获取网络状态、设备类型等非敏感信息),所以回调里grantResults[0]会返回PackageManager.PERMISSION_GRANTED(也就是0),但你真正需要的敏感权限(比如读取IMEI)其实并没有被授予。
如果你的应用targetSdkVersion <29,在Android 10+设备上,系统会自动拒绝READ_PHONE_STATE的敏感权限请求,但同样可能在回调里返回0,这是系统权限机制的兼容性问题。
正确的权限判断方式
不要只依赖grantResults数组,应该结合ContextCompat.checkSelfPermission()方法来确认实际的权限状态。这个方法会返回当前应用是否真正拥有该权限的有效状态。
修改你的onRequestPermissionsResult代码如下:
@Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case 100: { // 先判断结果数组是否有效 if (grantResults == null || grantResults.length == 0) { Toast.makeText(getApplicationContext(), "权限请求被取消", Toast.LENGTH_SHORT).show(); return; } // 用checkSelfPermission确认实际权限状态 int actualPermissionState = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE); if (actualPermissionState == PackageManager.PERMISSION_GRANTED) { Toast.makeText(getApplicationContext(), "权限已授予", Toast.LENGTH_SHORT).show(); // 注意:Android 10+ 这里无法获取IMEI/序列号,需要用替代方案 } else { Toast.makeText(getApplicationContext(), "权限已拒绝", Toast.LENGTH_SHORT).show(); } break; } } }
针对Android 10+的额外提示
如果你请求READ_PHONE_STATE是为了获取设备唯一标识符,那么在Android 10及以上版本,这个权限已经无法满足需求了。你可以改用以下替代方案:
- 使用
Settings.Secure.ANDROID_ID:这是一个设备级的唯一标识符,除非恢复出厂设置否则不会改变。 - 自己生成UUID并存储到SharedPreferences或本地文件中,作为应用内的唯一标识。
额外检查点
- 确认你的
AndroidManifest.xml里的权限声明没有拼写错误,确保是<uses-permission android:name="android.permission.READ_PHONE_STATE"/> - 检查应用的
targetSdkVersion设置,不同版本的权限逻辑差异很大,建议保持targetSdkVersion为最新稳定版本。
内容的提问来源于stack exchange,提问作者Majid Ahmadi Jebeli

