Android中重复请求位置与存储权限的实现方案咨询
Android权限请求问题
我正在开发最低API Level 23的Android应用,需要获取存储(READ/WRITE)和当前位置权限。当用户两次拒绝权限后,权限请求弹窗不再弹出,我希望能持续弹出该弹窗,而非引导用户手动前往应用信息页授权,请问是否可行?
我当前的存储权限代码
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE != PackageManager.PERMISSION_GRANTED) { this.requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 2); } if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { this.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 2); } @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case 2: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { Toast.makeText(this, "Permission granted!", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "Permission denied!", Toast.LENGTH_SHORT).show(); } break; } } }
我当前的位置权限代码
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.INTERNET"/> if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { this.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 1){ if (grantResults[0] == PackageManager.PERMISSION_GRANTED){ Toast.makeText(this, "Permission granted!", Toast.LENGTH_SHORT).show(); }else { Toast.makeText(this, "Permission denied!", Toast.LENGTH_SHORT).show(); } } }
解答
答案是不可行。Android从API 23开始的权限机制里,当用户两次拒绝权限并且勾选了「不再询问」选项后,系统会直接阻止应用再次弹出系统权限请求弹窗——这是系统层面的硬性限制,目的是防止应用频繁骚扰用户。
代码优化建议
既然没法强制弹窗,不如优化权限请求逻辑,提升用户授权意愿:
- 合并权限请求:存储的READ和WRITE权限可以一次性发起请求,不用分开申请,减少弹窗次数;位置权限单独请求即可。
- 处理「不再询问」状态:通过
shouldShowRequestPermissionRationale()方法判断是否还能发起系统弹窗——如果返回false,说明用户已经勾选了不再询问,这时只能引导用户去应用设置页开启权限(这是合规的唯一途径)。
优化后的存储权限代码
// Manifest中权限声明保持不变 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> private static final int REQUEST_STORAGE_PERMISSION = 2; private void requestStoragePermissions() { // 检查是否已获取存储权限 if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { // 判断是否需要向用户解释权限用途 if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE) || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { // 弹出自定义对话框说明权限用途,再发起请求 new AlertDialog.Builder(this) .setTitle("需要存储权限") .setMessage("应用需要存储权限来读写文件,请允许授权") .setPositiveButton("确定", (dialog, which) -> { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_STORAGE_PERMISSION); }) .setNegativeButton("取消", null) .show(); } else { // 直接发起系统权限请求 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_STORAGE_PERMISSION); } } } @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_STORAGE_PERMISSION) { 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 permission : permissions) { if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) { canRequestAgain = true; break; } } if (canRequestAgain) { Toast.makeText(this, "权限被拒绝!", Toast.LENGTH_SHORT).show(); // 可以再次发起请求 requestStoragePermissions(); } else { Toast.makeText(this, "权限被拒绝且不再询问,请前往设置开启!", Toast.LENGTH_SHORT).show(); // 引导用户前往应用设置页 Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); Uri uri = Uri.fromParts("package", getPackageName(), null); intent.setData(uri); startActivity(intent); } } } }
优化后的位置权限代码
// Manifest中权限声明保持不变 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.INTERNET"/> private static final int REQUEST_LOCATION_PERMISSION = 1; private void requestLocationPermission() { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) { // 弹窗解释权限用途 new AlertDialog.Builder(this) .setTitle("需要位置权限") .setMessage("应用需要位置权限来获取当前位置,请允许授权") .setPositiveButton("确定", (dialog, which) -> { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION); }) .setNegativeButton("取消", null) .show(); } else { // 直接发起权限请求 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION); } } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_LOCATION_PERMISSION) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { Toast.makeText(this, "权限已授予!", Toast.LENGTH_SHORT).show(); } else { if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) { Toast.makeText(this, "权限被拒绝!", Toast.LENGTH_SHORT).show(); // 可以再次发起请求 requestLocationPermission(); } else { Toast.makeText(this, "权限被拒绝且不再询问,请前往设置开启!", Toast.LENGTH_SHORT).show(); // 引导到设置页 Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); Uri uri = Uri.fromParts("package", getPackageName(), null); intent.setData(uri); startActivity(intent); } } } }
另外需要注意:如果强行绕过系统限制(比如通过非官方API),不仅可能导致应用崩溃,还会违反Google Play的应用政策,最终导致应用被下架。建议通过清晰的权限用途说明,提升用户的授权意愿。
内容的提问来源于stack exchange,提问作者coderror
相关产品推荐
相关产品推荐

