Android 13更新后多权限请求弹窗仅显示一个的问题求助
Android 多权限请求问题解决
问题背景
我申请CAMERA、READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE三个权限时,系统只弹出一个请求弹窗,用户操作后其他权限不再弹窗,但onRequestPermissionsResult会被多次调用,Toast消息按逻辑显示。以下是我的代码片段:
private String[] PERMISSIONS; PERMISSIONS = new String[] { Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE }; if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) +ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) +ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { mCameraView.start(); } else if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA) || ActivityCompat.shouldShowRequestPermissionRationale (this, Manifest.permission.READ_EXTERNAL_STORAGE) || ActivityCompat.shouldShowRequestPermissionRationale (this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { ConfirmationDialogFragment .newInstance(R.string.camera_permission_confirmation, new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSIONS_MULTIPLE_REQUEST, R.string.camera_permission_not_granted) .show(getSupportFragmentManager(), FRAGMENT_DIALOG); } else { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!hasPermissions(MainActivity.this,PERMISSIONS)) { ActivityCompat.requestPermissions(MainActivity.this,PERMISSIONS,PERMISSIONS_MULTIPLE_REQUEST); } } } private boolean hasPermissions(Context context, String... PERMISSIONS) { if (context != null && PERMISSIONS != null) { for (String permission: PERMISSIONS){ if (ActivityCompat.checkSelfPermission(context,permission) != PackageManager.PERMISSION_GRANTED) { return false; } } } return true; } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case PERMISSIONS_MULTIPLE_REQUEST: if (grantResults.length > 0) { boolean cameraPermission = grantResults[1] == PackageManager.PERMISSION_GRANTED; boolean readExternalFile = grantResults[0] == PackageManager.PERMISSION_GRANTED; if (cameraPermission && readExternalFile) { // write your logic here } else { Toast.makeText(this, R.string.camera_permission_not_granted, Toast.LENGTH_SHORT).show(); Toast.makeText(this, R.string.gallary_permission_not_grated, Toast.LENGTH_SHORT).show(); } } break; } }
问题解析
- 单弹窗显示:这是Android系统的正常行为。从API 23开始,同权限组的权限会被合并到一个弹窗中请求。READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE属于存储权限组,加上CAMERA权限,系统会将这三个权限合并展示为一个弹窗,用户一次操作即可处理所有权限请求。
- 多次回调
onRequestPermissionsResult:大概率是权限请求逻辑被重复触发,比如代码中存在多次调用requestPermissions的情况,或者自定义弹窗逻辑有误导致重复发起请求。 - 权限结果判断错误:原代码中
cameraPermission使用了grantResults[1],但你的PERMISSIONS数组里CAMERA是第一个元素(索引0),这会导致权限判断逻辑完全错误。
修复方案
以下是优化后的完整代码,解决上述所有问题:
private String[] PERMISSIONS = { Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE }; private static final int PERMISSIONS_MULTIPLE_REQUEST = 101; // 定义常量避免魔法值 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); checkAndRequestPermissions(); } private void checkAndRequestPermissions() { // 检查所有权限是否已授予 if (hasAllPermissionsGranted()) { mCameraView.start(); return; } // 判断是否需要显示权限申请说明弹窗 boolean shouldShowRationale = false; for (String permission : PERMISSIONS) { if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) { shouldShowRationale = true; break; } } if (shouldShowRationale) { // 显示自定义权限说明弹窗 ConfirmationDialogFragment .newInstance(R.string.camera_permission_confirmation, PERMISSIONS, PERMISSIONS_MULTIPLE_REQUEST, R.string.camera_permission_not_granted) .show(getSupportFragmentManager(), "PERMISSION_RATIONALE_DIALOG"); } else { // 直接发起权限请求 ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSIONS_MULTIPLE_REQUEST); } } private boolean hasAllPermissionsGranted() { for (String permission : PERMISSIONS) { if (ActivityCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) { return false; } } return true; } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode != PERMISSIONS_MULTIPLE_REQUEST) { return; } // 验证结果完整性 if (grantResults.length != permissions.length) { Toast.makeText(this, "权限请求异常", Toast.LENGTH_SHORT).show(); return; } boolean cameraGranted = false; boolean storageGranted = false; // 遍历权限结果,精准判断每个权限状态 for (int i = 0; i < permissions.length; i++) { String permission = permissions[i]; boolean isGranted = grantResults[i] == PackageManager.PERMISSION_GRANTED; if (permission.equals(Manifest.permission.CAMERA)) { cameraGranted = isGranted; } else if (permission.equals(Manifest.permission.READ_EXTERNAL_STORAGE) || permission.equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { // 存储权限同组,一个授予则另一个自动生效 storageGranted = storageGranted || isGranted; } } // 根据权限状态执行对应逻辑 if (cameraGranted && storageGranted) { mCameraView.start(); } else { if (!cameraGranted) { Toast.makeText(this, R.string.camera_permission_not_granted, Toast.LENGTH_SHORT).show(); } if (!storageGranted) { Toast.makeText(this, R.string.gallary_permission_not_grated, Toast.LENGTH_SHORT).show(); } } }
优化要点
- 修正权限索引错误:通过遍历权限数组匹配权限名称,避免依赖数组索引导致的判断错误。
- 避免重复请求:简化权限检查逻辑,确保
requestPermissions只被调用一次,解决多次回调问题。 - 利用权限组特性:存储权限属于同一组,只要其中一个被授予,另一个自动生效,无需单独判断。
- 代码可读性提升:拆分逻辑方法,使用常量替代魔法值,使代码更易维护。
内容的提问来源于stack exchange,提问作者Dishita Shah
相关产品推荐
相关产品推荐

