如何再次申请权限?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+可以用
MediaStoreAPI写入文件,无需申请WRITE_EXTERNAL_STORAGE;Android 11+则可以考虑申请MANAGE_EXTERNAL_STORAGE权限,但这个权限需要在Google Play上说明用途,审核较严格。
如果不是必须存到公共目录,优先考虑应用专属外部存储,能省去很多权限申请的麻烦。
内容的提问来源于stack exchange,提问作者user9329083




