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

如何再次申请权限?Android SQLite数据库备份至外部存储权限疑问

解决Android中WRITE_EXTERNAL_STORAGE权限再次申请的问题

为什么shouldShowRequestPermissionRationale会被跳过?

你遇到的这个情况,大概率是两种场景导致的:要么是用户第一次请求权限(此时系统还没记录用户的拒绝行为,该方法直接返回false),要么是用户之前拒绝权限时勾选了「不再询问」——这时候系统会直接跳过权限申请弹窗,不再触发常规的权限请求流程。

完整的权限申请逻辑实现

我们需要区分这两种场景,针对性处理才能实现再次申请的需求:

1. 权限检查与申请入口

先写一个统一的方法来封装权限逻辑:

private val REQUEST_CODE_STORAGE = 1001
private val PREF_FIRST_REQUEST_STORAGE = "first_request_storage"

fun requestStoragePermission() {
    when {
        // 权限已授予,直接执行数据库备份
        ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED -> {
            copyDatabaseToExternalStorage()
        }
        // 用户之前拒绝过但没勾选不再询问,先解释权限用途
        shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE) -> {
            AlertDialog.Builder(this)
                .setTitle("需要存储权限")
                .setMessage("为了备份你的数据库文件,我们需要访问外部存储,请授予权限")
                .setPositiveButton("确定") { _, _ ->
                    ActivityCompat.requestPermissions(
                        this,
                        arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
                        REQUEST_CODE_STORAGE
                    )
                }
                .setNegativeButton("取消", null)
                .show()
        }
        else -> {
            // 用SharedPreferences记录是否是第一次请求权限
            val sharedPref = getSharedPreferences("app_prefs", MODE_PRIVATE)
            val isFirstRequest = sharedPref.getBoolean(PREF_FIRST_REQUEST_STORAGE, true)
            
            if (isFirstRequest) {
                // 第一次请求,直接弹出系统权限申请框
                sharedPref.edit().putBoolean(PREF_FIRST_REQUEST_STORAGE, false).apply()
                ActivityCompat.requestPermissions(
                    this,
                    arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
                    REQUEST_CODE_STORAGE
                )
            } else {
                // 用户已勾选不再询问,引导去应用设置页手动开启权限
                AlertDialog.Builder(this)
                    .setTitle("权限被拒绝")
                    .setMessage("你之前拒绝了存储权限并勾选了不再询问,请前往应用设置开启权限以完成备份")
                    .setPositiveButton("去设置") { _, _ ->
                        val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                        val uri = Uri.fromParts("package", packageName, null)
                        intent.data = uri
                        startActivity(intent)
                    }
                    .setNegativeButton("取消", null)
                    .show()
            }
        }
    }
}

2. 处理权限申请回调

在Activity或Fragment中重写回调方法,处理用户的权限选择:

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if (requestCode == REQUEST_CODE_STORAGE) {
        if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // 权限授予成功,执行数据库备份
            copyDatabaseToExternalStorage()
        } else {
            // 权限再次被拒绝,给出提示
            Toast.makeText(this, "存储权限被拒绝,无法完成备份", Toast.LENGTH_SHORT).show()
        }
    }
}

针对Android 10+的补充提示

从Android 10(API 29)开始,WRITE_EXTERNAL_STORAGE权限的作用被大幅限制:

  • 如果你的备份需求只需要将文件存到应用专属的外部存储目录(比如getExternalFilesDir(null)),完全不需要申请这个权限,直接读写即可。
  • 如果必须存到公共目录,Android 10+可以用MediaStore API写入文件,无需申请WRITE_EXTERNAL_STORAGE;Android 11+则可以考虑申请MANAGE_EXTERNAL_STORAGE权限,但这个权限需要在Google Play上说明用途,审核较严格。

如果不是必须存到公共目录,优先考虑应用专属外部存储,能省去很多权限申请的麻烦。


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

火山引擎 最新活动