React Native 0.59安卓API29申请带始终允许的定位权限不生效怎么办
解决方案
问题根因
- API 29(安卓10)对后台定位权限申请做了限制:必须先成功申请前台定位权限(ACCESS_FINE_LOCATION/ACCESS_COARSE_LOCATION),才能单独申请后台定位权限,两个权限同时申请会被系统直接拦截后台权限的申请请求,不会弹出带「始终允许」的弹窗。
- 你当前代码报错的直接原因是
ActivityCompat.requestPermissions的第一个参数要求传入Activity实例,你传入了自定义原生模块的实例this,类型不匹配导致崩溃。
修复步骤
第一步:调整AndroidManifest.xml权限配置
<!-- 基础定位权限 所有版本都需要 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- 后台定位权限 仅API29及以上需要 --> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" android:minSdkVersion="29" /> <!-- 若需要后台持续定位,需补充前台服务权限 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" android:minSdkVersion="26" />
第二步:修改自定义原生模块逻辑
无需修改MainActivity代码,直接通过RN自带的权限监听接口即可实现回调,修改后的Geolocation.java代码如下:
首先导入依赖包:
import android.os.Build; import android.content.Context; import android.content.pm.PackageManager; import android.Manifest; import com.facebook.react.modules.core.PermissionAwareActivity; import com.facebook.react.modules.core.PermissionListener;
然后补充常量定义和方法实现:
// 权限请求码常量 private static final int MY_PERMISSIONS_REQUEST_LOCATION = 1001; private static final int MY_PERMISSIONS_REQUEST_BACKGROUND_LOCATION = 1002; @ReactMethod public void requestForLocationPermission(Promise promise) { Context context = getReactApplicationContext(); // 适配不同系统版本的权限逻辑 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { // API28及以下,申请前台定位权限默认包含后台权限 int permissionCheck = ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION); if (permissionCheck == PackageManager.PERMISSION_GRANTED) { promise.resolve("granted"); return; } PermissionAwareActivity activity = (PermissionAwareActivity) getCurrentActivity(); if (activity == null) { promise.reject("ACTIVITY_NULL", "当前Activity不存在"); return; } activity.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_LOCATION, new PermissionListener() { @Override public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == MY_PERMISSIONS_REQUEST_LOCATION) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { promise.resolve("granted"); } else { promise.reject("PERMISSION_DENIED", "定位权限被拒绝"); } return true; } return false; } }); } else { // API29及以上,分两步申请权限 int fineLocationCheck = ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION); if (fineLocationCheck != PackageManager.PERMISSION_GRANTED) { // 先申请前台定位权限 PermissionAwareActivity activity = (PermissionAwareActivity) getCurrentActivity(); if (activity == null) { promise.reject("ACTIVITY_NULL", "当前Activity不存在"); return; } activity.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_LOCATION, new PermissionListener() { @Override public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == MY_PERMISSIONS_REQUEST_LOCATION) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 前台权限申请成功后再申请后台权限 requestBackgroundLocationPermission(promise); } else { promise.reject("PERMISSION_DENIED", "前台定位权限被拒绝"); } return true; } return false; } }); } else { // 已有前台权限,直接申请后台权限 requestBackgroundLocationPermission(promise); } } } // 单独封装后台定位权限申请逻辑 private void requestBackgroundLocationPermission(Promise promise) { Context context = getReactApplicationContext(); int backgroundCheck = ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_BACKGROUND_LOCATION); if (backgroundCheck == PackageManager.PERMISSION_GRANTED) { promise.resolve("granted"); return; } PermissionAwareActivity activity = (PermissionAwareActivity) getCurrentActivity(); if (activity == null) { promise.reject("ACTIVITY_NULL", "当前Activity不存在"); return; } activity.requestPermissions(new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION}, MY_PERMISSIONS_REQUEST_BACKGROUND_LOCATION, new PermissionListener() { @Override public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == MY_PERMISSIONS_REQUEST_BACKGROUND_LOCATION) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { promise.resolve("granted"); } else { promise.reject("PERMISSION_DENIED", "后台定位权限被拒绝"); } return true; } return false; } }); }
第三步:补充交互提示(可选但推荐)
申请后台定位权限之前,可先弹出自定义提示框说明权限用途,若用户首次拒绝后台权限,后续系统会直接拦截权限申请弹窗,需引导用户手动到应用设置页开启「始终允许」定位权限。
其他注意点
RN 0.59版本自带的PermissionsAndroid接口不支持ACCESS_BACKGROUND_LOCATION权限的申请,不要直接用系统自带接口申请后台定位权限。
内容的提问来源于stack exchange,提问作者Riku
相关产品推荐
相关产品推荐

