You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android外部存储权限请求:用户拒绝后如何重新发起询问

解决Android权限拒绝后无法再次请求的问题

我来帮你搞定这个权限请求的问题!其实核心原因是Android的权限机制:当用户第一次拒绝权限后,再次请求时系统会弹出「不再询问」的选项,如果用户勾选了它,直接调用requestPermissions()就不会再触发系统权限对话框了。我们需要分场景处理,确保每次点击按钮都能有合理的响应。

第一步:完善权限检查方法

先确保你的checkPermission()能正确检查外部存储权限:

private boolean checkPermission() {
    // 针对Android 6.0+,检查读写外部存储权限
    int readPerm = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);
    int writePerm = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    return readPerm == PackageManager.PERMISSION_GRANTED && writePerm == PackageManager.PERMISSION_GRANTED;
}

第二步:修改权限请求逻辑,加入解释与引导

修改你的requestPermission()方法,增加权限解释对话框,以及处理「不再询问」的情况:

private void requestPermission() {
    // 判断是否需要向用户解释权限用途(用户之前拒绝过但没勾选不再询问)
    boolean needRationale = ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE)
            || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);

    if (needRationale) {
        // 先弹对话框说明权限用途,再发起请求
        new AlertDialog.Builder(this)
                .setTitle("需要存储权限")
                .setMessage("我们需要存储权限来保存或读取您的文件,请允许这个权限")
                .setPositiveButton("好的", (dialog, which) -> {
                    // 发起权限请求
                    ActivityCompat.requestPermissions(this,
                            new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE},
                            100); // 100是自定义的请求码
                })
                .setNegativeButton("取消", null)
                .show();
    } else {
        // 直接请求权限(首次请求,或用户已勾选不再询问)
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE},
                100);
    }
}

第三步:处理权限请求回调

重写onRequestPermissionsResult方法,根据用户的选择做出不同处理:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == 100) {
        boolean allGranted = true;
        for (int result : grantResults) {
            if (result != PackageManager.PERMISSION_GRANTED) {
                allGranted = false;
                break;
            }
        }

        if (allGranted) {
            // 权限全部授予,执行你的业务逻辑
            Toast.makeText(this, "权限已授予,可正常操作", Toast.LENGTH_SHORT).show();
            // 这里写你需要执行的代码
        } else {
            // 判断用户是否勾选了「不再询问」
            boolean canRequestAgain = false;
            for (String perm : permissions) {
                if (ActivityCompat.shouldShowRequestPermissionRationale(this, perm)) {
                    canRequestAgain = true;
                    break;
                }
            }

            if (!canRequestAgain) {
                // 用户勾选了不再询问,引导去应用设置开启权限
                new AlertDialog.Builder(this)
                        .setTitle("权限被拒绝")
                        .setMessage("您已拒绝存储权限并勾选了不再询问,请前往应用设置手动开启")
                        .setPositiveButton("去设置", (dialog, which) -> {
                            // 跳转到当前应用的设置页面
                            Intent settingsIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                            Uri uri = Uri.fromParts("package", getPackageName(), null);
                            settingsIntent.setData(uri);
                            startActivity(settingsIntent);
                        })
                        .setNegativeButton("取消", null)
                        .show();
            } else {
                // 用户只是拒绝,没勾选不再询问,提示可再次尝试
                Toast.makeText(this, "权限被拒绝,您可以再次点击按钮请求", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

第四步:按钮点击事件的处理

确保你的按钮点击逻辑调用上述方法:

// 假设按钮id是btn_request_storage
Button requestBtn = findViewById(R.id.btn_request_storage);
requestBtn.setOnClickListener(v -> {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if (checkPermission()) {
            // 权限已存在,直接执行逻辑
            Toast.makeText(this, "权限已拥有", Toast.LENGTH_SHORT).show();
        } else {
            // 发起权限请求
            requestPermission();
        }
    } else {
        // Android 6.0以下无需动态请求,直接执行逻辑
        Toast.makeText(this, "无需请求权限,可直接操作", Toast.LENGTH_SHORT).show();
    }
});

关键逻辑说明

  • shouldShowRequestPermissionRationale:这个方法返回true时,表示用户之前拒绝过权限但没勾选「不再询问」,此时我们可以先解释权限用途再请求;返回false时,要么是首次请求,要么是用户已经勾选了「不再询问」。
  • 当用户勾选「不再询问」后,系统不会再弹出权限对话框,这时候我们需要引导用户去应用设置页面手动开启权限,这是唯一能让用户重新授予权限的方式。

这样修改后,不管用户是第一次拒绝、多次拒绝,还是勾选了不再询问,点击按钮都能得到对应的响应,不会出现点击后毫无反应的情况。

内容的提问来源于stack exchange,提问作者DomingoMG

火山引擎 最新活动