在 Android 12 (SDK 31) 中获取 android.app.ForegroundServiceStartNotAllowedException

Ved*_*agh 35 java service android kotlin android-studio

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

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)
Run Code Online (Sandbox Code Playgroud)

另外,如果您使用 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)
Run Code Online (Sandbox Code Playgroud)

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

Ved*_*agh 37

如何重现崩溃

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

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

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


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

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

这些特殊情况是:

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

  • 您的应用程序可以从后台启动活动,但应用程序在现有任务的返回堆栈中具有活动的情况除外。

  • 您的应用使用 Firebase Cloud Messaging 接收高优先级消息。

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

  • 您的应用程序调用精确的警报来完成用户请求的操作。

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

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

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

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

  • 您的应用程序收到需要 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 Intent 操作的 Intent。


可能的解决方案

解决方案1

这将在 Play 商店中运行一段时间,直到 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 行为更改,特别是在前台服务启动限制内。


Jad*_*ent 14

如果您的应用程序是 MediaPlayer(即使用 )MediaBrowseService并且您遇到ForegroundServiceStartNotAllowedException崩溃,那么您可能需要:

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

  2. 在方法ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK调用中包含参数Serivce.startForeground

另请注意,如果您使用 ExoPlayer,请参阅此处 Android 团队的建议,这可能有助于追踪因ForegroundServiceStartNotAllowedException抛出异常而导致崩溃的原因

https://github.com/androidx/media/issues/111#issuecomment-1406466363

此外,这里还有一些非常有用且最新的(API31)信息ForegroundServices: https: //www.hellsoft.se/your-guide-to-foreground-services-on-andorid/

  • 这根本没有帮助,至少在三星设备上没有帮助。当服务通过 KEYCODE_MEDIA_PLAY 之类的方式启动时,虽然应用程序完全处于后台,但它仍然会崩溃。 (3认同)