Getting android.app.ForegroundServiceStartNotAllowedException in Android 12 (SDK 31)如何重现崩溃这个例外是什么,为什么添加它?可能的解决方案

2022-09-02 03:43:30

我已将我的应用程序升级到 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时没有找到有关此问题的任何文档。


答案 1

如何重现崩溃

步骤 1.更新您的 和 SDK 31。targetSdkVersioncompileSdkVersion

步骤2.尝试在应用处于后台时运行任何前台服务。在我的情况下,它是小部件的方法在时间之后被调用,它将启动一个Foreground服务,该服务通过从Internet获取适当的信息来更新数据。onUpdateupdatePeriodMillis

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


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

以 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商店中工作一段时间,直到Google强制升级到API级别31。

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

解决方案 2

适用于时间敏感型工作

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

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

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

你可以在这里了解更多关于WorkManager的信息-> WorkManager

Github Repo for WorkManager 示例 -> WorkManager 示例

我之所以特别添加这个答案,是因为搜索此异常不会带来任何资源来了解为什么该服务在Android 12上的行为不同。所有这些都存在于Google的文档中,并且始终记得检查文档中的行为更改。

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


答案 2

如果您的应用程序是MediaPlayer(即使用a),并且您正在经历崩溃,那么您可能需要:MediaBrowseServiceForegroundServiceStartNotAllowedException

  1. 更新清单以指定服务用于声明中的媒体播放android:foregroundServiceType="mediaPlayback"Service

  2. 在对方法的调用中包含参数ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACKSerivce.startForeground


推荐