Android M设备出现READ_PHONE_STATE权限异常问题求助
看了你的问题和代码,核心问题出在权限请求的时机不对,加上你的权限处理代码有冗余逻辑,导致AirWatch的AirWatchSDKContextService这个IntentService在权限还没被授予时就启动运行,进而触发了SecurityException。下面一步步给你解决:
第一步:确认Manifest已声明权限
虽然你没贴Manifest代码,但必须确保已经添加这个权限声明,否则运行时请求也无效:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
第二步:修复运行时权限处理代码
你的代码存在重复请求权限的问题(checkAndRequestForPermission已经包含READ_PHONE_STATE的请求,却又调用getReadPhoneAccess再次请求),而且onRequestPermissionsResult里的递归调用会导致无限循环。这里给你优化成简洁可靠的版本:
优化后的权限检查与请求代码
private static final int MY_PERMISSIONS_REQUEST_ALL = 1001; private void checkAndRequestForPermission() { // 整理所有需要的权限数组 String[] requiredPermissions = { Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CALL_PHONE, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.READ_PHONE_STATE }; // 收集未授予的权限 List<String> permissionsToRequest = new ArrayList<>(); for (String perm : requiredPermissions) { if (ContextCompat.checkSelfPermission(this, perm) != PackageManager.PERMISSION_GRANTED) { permissionsToRequest.add(perm); } } if (!permissionsToRequest.isEmpty()) { // 只请求未授予的权限 ActivityCompat.requestPermissions(this, permissionsToRequest.toArray(new String[0]), MY_PERMISSIONS_REQUEST_ALL); } else { // 所有权限都已授予,现在初始化AirWatch SDK/启动对应服务 startAirWatchService(); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == MY_PERMISSIONS_REQUEST_ALL) { boolean allGranted = true; for (int result : grantResults) { if (result != PackageManager.PERMISSION_GRANTED) { allGranted = false; break; } } if (allGranted) { // 权限全部授予,启动AirWatch服务 startAirWatchService(); } else { // 有权限被拒绝,提示用户去设置开启权限 Toast.makeText(this, "需要开启必要权限才能使用应用", Toast.LENGTH_LONG).show(); // 可选:引导用户到应用设置页面 // Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + getPackageName())); // startActivity(intent); } } } // 封装启动AirWatch服务的方法,确保仅在权限授予后调用 private void startAirWatchService() { Intent serviceIntent = new Intent(this, AirWatchSDKContextService.class); startService(serviceIntent); // 若是AirWatch SDK初始化逻辑,也放在这里执行 }
第三步:确保权限授予后再启动AirWatch服务
这是关键:AirWatchSDKContextService是IntentService,它无法弹出权限请求对话框(只有Activity能弹出),所以绝对不能在权限未确认授予前启动这个服务。
把原来直接启动AirWatch服务的代码,全部移到startAirWatchService方法中,仅当checkAndRequestForPermission确认所有权限都授予后,才调用这个方法。比如原来在onCreate里直接启动服务,现在改成:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 先检查权限,而非直接启动服务 checkAndRequestForPermission(); }
第四步:处理用户拒绝权限的情况
如果用户拒绝了READ_PHONE_STATE这类核心权限,应用无法正常使用AirWatch SDK,需要友好提示用户,引导他们到应用设置页面手动开启权限。
原代码出错的原因
- 重复请求权限:两次请求READ_PHONE_STATE导致权限流程混乱;
- 服务启动时机过早:AirWatch服务在权限未被用户授予时就运行,调用
getDeviceId()触发异常; - 递归调用的问题:
onRequestPermissionsResult里的递归会导致无限弹出权限对话框,既解决不了问题还影响体验。
按照上面的步骤修改后,就能确保只有当所有必要权限都被授予后,AirWatch服务才会启动,也就不会再触发这个权限错误了。
内容的提问来源于stack exchange,提问作者Ajay Kulkarni

