You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android 14拒绝位置权限时App崩溃问题解决方案咨询

升级Android 14(targetSdkVersion 34)后WorkManager位置权限拒绝导致崩溃的解决方案

问题场景

应用升级至targetSdkVersion 34后,当用户拒绝位置权限时会触发崩溃。该应用使用WorkManager每20秒向服务器更新位置,崩溃触发于:应用从后台切换至前台,且用户已在系统设置中拒绝位置权限。

崩溃堆栈信息

Fatal Exception: java.lang.SecurityException: Starting FGS with type location callerApp=ProcessRecord{7499c86 16252:com.prasko.ovdriver/u0a304} targetSDK=34 requires permissions: all of the permissions allOf=true [android.permission.FOREGROUND_SERVICE_LOCATION] any of the permissions allOf=false [android.permission.ACCESS_COARSE_LOCATION, android.permission.ACCESS_FINE_LOCATION] and the app must be in the eligible state/exemptions to access the foreground only permission
at android.os.Parcel.createExceptionOrNull(Parcel.java:3087)
at android.os.Parcel.createException(Parcel.java:3071)
at android.os.Parcel.readException(Parcel.java:3054)
at android.os.Parcel.readException(Parcel.java:2996)
at android.app.IActivityManager$Stub$Proxy.setServiceForeground(IActivityManager.java:6761)
at android.app.Service.startForeground(Service.java:862)
at androidx.work.impl.foreground.SystemForegroundService$Api31Impl.startForeground(SystemForegroundService.java:193)
at androidx.work.impl.foreground.SystemForegroundService$1.run(SystemForegroundService.java:129)
at android.os.Handler.handleCallback(Handler.java:958)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:257)
at android.os.Looper.loop(Looper.java:368)
at android.app.ActivityThread.main(ActivityThread.java:8839)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:572)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1049)

Manifest权限配置

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />

<service
    android:name="androidx.work.impl.foreground.SystemForegroundService"
    android:foregroundServiceType="location|dataSync"
    tools:ignore="Instantiatable"
    tools:node="merge" />

核心原因

Android 14对前台服务(FGS)的权限校验更严格:当前台服务类型包含location时,必须同时持有至少一个位置权限(ACCESS_FINE/COARSE_LOCATION),否则调用startForeground()会直接抛出SecurityException。仅在启动WorkManager前检查权限无法覆盖用户后续通过系统设置撤销权限的场景,导致WorkManager触发前台服务时权限缺失。

解决方案

1. Worker执行前动态校验权限

在Worker的doWork()方法开头再次检查位置权限,若权限缺失直接终止任务,避免触发前台服务:

public class LocationUpdateWorker extends Worker {
    public LocationUpdateWorker(@NonNull Context context, @NonNull WorkerParameters params) {
        super(context, params);
    }

    @NonNull
    @Override
    public Result doWork() {
        // 检查是否持有位置权限
        boolean hasLocationPerm = ContextCompat.checkSelfPermission(getApplicationContext(),
                Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(getApplicationContext(),
                Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED;

        if (!hasLocationPerm) {
            // 权限缺失,直接返回失败
            return Result.failure();
        }

        // 执行位置更新逻辑
        updateLocationToServer();
        return Result.success();
    }
}

2. 动态调整前台服务类型

根据当前权限状态,在构建ForegroundInfo时动态修改前台服务类型:

  • 有位置权限时,使用location|dataSync类型
  • 无位置权限时,仅使用dataSync类型
@Override
@NonNull
public ForegroundInfo getForegroundInfo() {
    boolean hasLocationPerm = ContextCompat.checkSelfPermission(getApplicationContext(),
            Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
            || ContextCompat.checkSelfPermission(getApplicationContext(),
            Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED;

    int foregroundType = hasLocationPerm 
        ? (ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION | ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC)
        : ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC;

    Notification notification = createLocationUpdateNotification(); // 自定义通知逻辑
    return new ForegroundInfo(LOCATION_NOTIFICATION_ID, notification, foregroundType);
}

3. 全局捕获SecurityException兜底

在Application中设置全局异常捕获,针对前台服务权限异常做兜底处理,避免App崩溃:

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
            if (throwable instanceof SecurityException) {
                String msg = throwable.getMessage();
                if (msg != null && msg.contains("FOREGROUND_SERVICE_LOCATION")) {
                    // 停止相关WorkManager任务
                    WorkManager.getInstance(this).cancelAllWorkByTag("LOCATION_UPDATE_TAG");
                    // 可选:引导用户开启权限
                    showPermissionGuide();
                    return;
                }
            }
            // 其他异常按原有逻辑处理
            handleOtherExceptions(throwable);
        });
    }
}

4. 优化Manifest配置

Android 14中FOREGROUND_SERVICE权限已废弃,移除该声明,保留细分的前台服务权限即可:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />

<service
    android:name="androidx.work.impl.foreground.SystemForegroundService"
    android:foregroundServiceType="location|dataSync"
    tools:ignore="Instantiatable"
    tools:node="merge" />

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 09:51:20