首页 > 解决方案 > 在 Android 12 (SDK 31) 中获取 android.app.ForegroundServiceStartNotAllowedException

问题描述

我将我的应用程序升级到 SDK 31,targetSdkVersioncompileSdkVersion开始在后台更新小部件的服务中的应用程序中收到以下崩溃。

java.lang.RuntimeException: 
  at android.app.ActivityThread.handleReceiver (ActivityThread.java:4321)
  at android.app.ActivityThread.access$1600 (ActivityThread.java:247)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2068)
  at android.os.Handler.dispatchMessage (Handler.java:106)
  at android.os.Looper.loopOnce (Looper.java:201)
  at android.os.Looper.loop (Looper.java:288)
  at android.app.ActivityThread.main (ActivityThread.java:7842)
  at java.lang.reflect.Method.invoke (Native Method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:548)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1003)
Caused by: android.app.ForegroundServiceStartNotAllowedException: 
  at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel (ForegroundServiceStartNotAllowedException.java:54)
  at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel (ForegroundServiceStartNotAllowedException.java:50)
  at android.os.Parcel.readParcelable (Parcel.java:3333)
  at android.os.Parcel.createExceptionOrNull (Parcel.java:2420)
  at android.os.Parcel.createException (Parcel.java:2409)
  at android.os.Parcel.readException (Parcel.java:2392)
  at android.os.Parcel.readException (Parcel.java:2334)
  at android.app.IActivityManager$Stub$Proxy.startService (IActivityManager.java:5971)
  at android.app.ContextImpl.startServiceCommon (ContextImpl.java:1847)
  at android.app.ContextImpl.startForegroundService (ContextImpl.java:1823)
  at android.content.ContextWrapper.startForegroundService (ContextWrapper.java:779)
  at android.content.ContextWrapper.startForegroundService (ContextWrapper.java:779)
  at com.mypackage.appname.ui.widget.widget_package.WidgetClassName.onUpdate (WidgetClassName.java:48)
  at android.appwidget.AppWidgetProvider.onReceive (AppWidgetProvider.java:66)
  at com.mypackage.appname.ui.widget.widget_package.WidgetClassName.onReceive (WidgetClassName.java)
  at android.app.ActivityThread.handleReceiver (ActivityThread.java:4312)
  at android.app.ActivityThread.access$1600 (ActivityThread.java:247)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2068)
  at android.os.Handler.dispatchMessage (Handler.java:106)
  at android.os.Looper.loopOnce (Looper.java:201)
  at android.os.Looper.loop (Looper.java:288)
  at android.app.ActivityThread.main (ActivityThread.java:7842)
  at java.lang.reflect.Method.invoke (Native Method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:548)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1003)
Caused by: android.os.RemoteException: 
  at com.android.server.am.ActiveServices.startServiceLocked (ActiveServices.java:691)
  at com.android.server.am.ActiveServices.startServiceLocked (ActiveServices.java:616)
  at com.android.server.am.ActivityManagerService.startService (ActivityManagerService.java:11839)
  at android.app.IActivityManager$Stub.onTransact (IActivityManager.java:2519)
  at com.android.server.am.ActivityManagerService.onTransact (ActivityManagerService.java:2498)

此外,如果您使用 Firebase Crashlytics 之类的东西,您的堆栈跟踪必须是这样的 ->

Caused by android.app.ForegroundServiceStartNotAllowedException: startForegroundService() not allowed due to mAllowStartForeground false: service com.mypackage.appname/.ui.widget.widget_package.MyForegroundServiceName
       at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel(ForegroundServiceStartNotAllowedException.java:54)
       at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel(ForegroundServiceStartNotAllowedException.java:50)
       at android.os.Parcel.readParcelable(Parcel.java:3333)
       at android.os.Parcel.createExceptionOrNull(Parcel.java:2420)
       at android.os.Parcel.createException(Parcel.java:2409)
       at android.os.Parcel.readException(Parcel.java:2392)
       at android.os.Parcel.readException(Parcel.java:2334)
       at android.app.IActivityManager$Stub$Proxy.startService(IActivityManager.java:5971)
       at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1847)
       at android.app.ContextImpl.startForegroundService(ContextImpl.java:1823)
       at android.content.ContextWrapper.startForegroundService(ContextWrapper.java:779)
       at android.content.ContextWrapper.startForegroundService(ContextWrapper.java:779)
       at com.mypackage.appname.ui.widget.widget_package.WidgetClassName.onUpdate(WidgetClassName.java:48)
       at android.appwidget.AppWidgetProvider.onReceive(AppWidgetProvider.java:66)
       at com.mypackage.appname.ui.widget.widget_package.WidgetClassName.onReceive(WidgetClassName.java)
       at android.app.ActivityThread.handleReceiver(ActivityThread.java:4312)
       at android.app.ActivityThread.access$1600(ActivityThread.java:247)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2068)
       at android.os.Handler.dispatchMessage(Handler.java:106)
       at android.os.Looper.loopOnce(Looper.java:201)
       at android.os.Looper.loop(Looper.java:288)
       at android.app.ActivityThread.main(ActivityThread.java:7842)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)

我正在添加重现此问题的方法,并修复此问题,因为我在 StackOverflow 上搜索它时没有找到任何关于此的文档。

标签: javaandroidandroid-studiokotlinservice

解决方案


如何重现崩溃

步骤 1. 将您的targetSdkVersion和更新compileSdkVersion到 SDK 31。

第 2 步。尝试在您的应用程序处于后台时运行任何前台服务。就我而言,这是在一段时间onUpdate后调用的小部件方法updatePeriodMillis,它将启动一个前台服务,该服务通过从互联网获取适当的信息来更新数据。

请记住:Android 8.0 中添加的后台执行限制与此问题无关。此限制/例外是在 Android 12/SDK 31 - Source中添加的。


这个例外是什么,为什么要添加它?

以 Android 12(API 级别 31)或更高版本为目标的应用程序在后台运行时无法启动前台服务,少数特殊情况除外。如果应用程序在后台运行时尝试启动前台服务,并且前台服务不满足其中一种异常情况,则系统会抛出ForegroundServiceStartNotAllowedException.

这些特殊情况是:

  • 您的应用程序从用户可见状态(例如活动)转换。

  • 您的应用程序可以从后台启动一个活动,除非应用程序在现有任务的后台堆栈中有活动。

  • 您的应用使用 Firebase 云消息传递接收高优先级消息。

  • 用户对与您的应用相关的 UI 元素执行操作。例如,它们可能与气泡、通知、小部件或活动交互。

  • 您的应用会调用准确的警报来完成用户请求的操作。

  • 您的应用是设备当前的输入法。

  • 您的应用收到与地理围栏或活动识别转换相关的事件。

  • 在设备重新启动并在广播接收器中接收到 ACTION_BOOT_COMPLETED、ACTION_LOCKED_BOOT_COMPLETED 或 ACTION_MY_PACKAGE_REPLACED 意图操作后。

  • 您的应用在广播接收器中接收 ACTION_TIMEZONE_CHANGED、ACTION_TIME_CHANGED 或 ACTION_LOCALE_CHANGED 意图操作。

  • 您的应用接收需要 BLUETOOTH_CONNECT 或 BLUETOOTH_SCAN 权限的蓝牙广播。

  • 具有特定系统角色或权限的应用,例如设备所有者和个人资料所有者。

  • 您的应用使用配套设备管理器并声明 REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND 权限或 REQUEST_COMPANION_RUN_IN_BACKGROUND 权限。尽可能使用 REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND。

  • 用户为您的应用关闭电池优化。您可以通过将用户发送到系统设置中的应用程序信息页面来帮助用户找到此选项。为此,请调用包含 ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS 意图操作的意图。


可能的解决方案

解决方案 1

这将在 Play Store 中运行一段时间,直到 Google 强制升级到 API 级别 31。

目前,从 2021 年 11 月开始,所有应用都必须面向 API 级别 30 及以上。因此,如果您的应用程序使用 API 级别 31,则将compileSdkVersion&降级targetSdkVersion到 API 级别 30 应该可以解决问题(至少在一段时间内)。

解决方案 2

对于时间敏感的工作

如果您使用前台服务执行对时间敏感的工作,请在准确的警报内启动前台服务。从此处的文档中查看有关此内容的更多信息 ->设置确切的警报

对于时间不敏感/加急工作

这是我最终用于我的应用程序的解决方案。用于WorkManager安排和启动后台工作。从此处的文档中查看更多相关信息 ->安排加急工作

您可以在此处了解有关 WorkManager 的更多信息 -> WorkManager

WorkManager 示例的 Github 存储库 -> WorkManager 示例

我专门添加了此答案,因为搜索此异常不会提供任何资源来了解服务在 Android 12 上的行为为何不同。所有这些都存在于 Google 的文档中,并且始终记得检查文档中的行为更改。

与此更改相关的所有内容都可以在此处找到 -> Android 12 行为更改,特别是在前台服务启动限制内。


推荐阅读