Android 11后台定位权限重复弹窗问题求助(附代码)
Android 11 后台定位权限重复弹窗问题解决
问题根源
在Android 11中,用户选择「仅允许本次」临时授权后台定位后,应用重启时权限状态会重置为未授权。原代码仅通过checkSelfPermission判断权限状态,未区分用户是否已做出过权限选择,导致每次启动都会触发权限申请,甚至直接跳转至设置页面,造成重复弹窗困扰。
解决方案
通过以下调整优化权限申请逻辑,避免无意义的重复弹窗:
- 记录用户权限操作状态:用SharedPreferences记录用户是否已处理过权限请求,避免每次启动都触发申请流程。
- 精准判断权限申请时机:结合
shouldShowRequestPermissionRationale和权限状态,仅当用户未明确拒绝权限(需引导说明)时,才弹出权限申请弹窗;若用户已做出过选择(包括临时授权后重启),则不再主动触发申请,除非后续功能需要时再提示。 - 优化权限申请流程:确保前台定位权限为永久授权(「仅在使用应用时允许」)后,再请求后台定位权限,避免临时授权状态下的无效申请。
修改后的代码
private SharedPreferences permissionPrefs; private static final String PREF_KEY_LOCATION_PERMISSION_HANDLED = "location_permission_handled"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); permissionPrefs = getSharedPreferences("app_permissions", MODE_PRIVATE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { checkLocationPermissions(); } } private void checkLocationPermissions() { boolean hasFineLocation = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED; boolean hasBackgroundLocation = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED; if (!hasFineLocation) { boolean needRequest = ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION) || !permissionPrefs.getBoolean(PREF_KEY_LOCATION_PERMISSION_HANDLED, false); if (needRequest) { askForLocationPermission(); } } else if (!hasBackgroundLocation) { boolean needRequest = ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) || !permissionPrefs.getBoolean(PREF_KEY_LOCATION_PERMISSION_HANDLED, false); if (needRequest) { askPermissionForBackgroundUsage(); } } } private void askForLocationPermission() { if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) { new AlertDialog.Builder(this) .setTitle("需要权限") .setMessage("应用需要定位权限以提供相关功能") .setPositiveButton("确定", (dialog, which) -> { ActivityCompat.requestPermissions(LoginActivity.this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 101); }) .setNegativeButton("取消", (dialog, which) -> { permissionPrefs.edit().putBoolean(PREF_KEY_LOCATION_PERMISSION_HANDLED, true).apply(); }) .create().show(); } else { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 101); } } private void askPermissionForBackgroundUsage() { if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION)) { new AlertDialog.Builder(this) .setTitle("需要后台定位权限") .setMessage("应用需要后台定位权限以持续提供服务,请在下一步选择「允许所有时间」") .setPositiveButton("确定", (dialog, which) -> { ActivityCompat.requestPermissions(LoginActivity.this, new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION}, 101); }) .setNegativeButton("取消", (dialog, which) -> { permissionPrefs.edit().putBoolean(PREF_KEY_LOCATION_PERMISSION_HANDLED, true).apply(); }) .create().show(); } else { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION}, 101); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 101) { permissionPrefs.edit().putBoolean(PREF_KEY_LOCATION_PERMISSION_HANDLED, true).apply(); if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { checkLocationPermissions(); } } } }
关键说明
- 状态记录:通过SharedPreferences标记用户是否已处理过权限请求,避免重启后重复触发申请。
- 申请时机控制:仅当
shouldShowRequestPermissionRationale返回true(用户未彻底拒绝,需引导)或用户从未处理过权限时,才弹出申请弹窗。 - 权限流程衔接:在权限申请结果回调中更新状态,并继续检查后续权限,确保流程完整。
内容的提问来源于stack exchange,提问作者serlok17
相关产品推荐
相关产品推荐

