You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
    }
}

问题解析

  1. 单弹窗显示:这是Android系统的正常行为。从API 23开始,同权限组的权限会被合并到一个弹窗中请求。READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE属于存储权限组,加上CAMERA权限,系统会将这三个权限合并展示为一个弹窗,用户一次操作即可处理所有权限请求。
  2. 多次回调onRequestPermissionsResult:大概率是权限请求逻辑被重复触发,比如代码中存在多次调用requestPermissions的情况,或者自定义弹窗逻辑有误导致重复发起请求。
  3. 权限结果判断错误:原代码中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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 12:47:29