在 Android 12 中获取 android.app.ForegroundServiceStartNotAllowedException(SDK 31)
Getting android.app.ForegroundServiceStartNotAllowedException in Android 12 (SDK 31)
我将我的应用程序 targetSdkVersion
和 compileSdkVersion
升级到 SDK 31,并开始在后台更新小部件的服务中收到以下应用程序崩溃。
java.lang.RuntimeException:
at android.app.ActivityThread.handleReceiver (ActivityThread.java:4321)
at android.app.ActivityThread.access00 (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.createFromParcel (ForegroundServiceStartNotAllowedException.java:54)
at android.app.ForegroundServiceStartNotAllowedException.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.access00 (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.createFromParcel(ForegroundServiceStartNotAllowedException.java:54)
at android.app.ForegroundServiceStartNotAllowedException.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.access00(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)
我正在添加重现此问题的方法,并修复此问题,因为我在 Whosebug 上搜索时没有找到有关此问题的任何文档。
如何重现崩溃
第 1 步。将您的 targetSdkVersion
和 compileSdkVersion
更新为 SDK 31。
第 2 步。当您的应用处于后台时,尝试 运行 任何前台服务。在我的例子中,是小部件的 onUpdate
方法在 updatePeriodMillis
时间后被调用,这将启动一个前台服务,该服务通过从互联网获取适当的信息来更新数据。
记住: Android 8.0 中添加的后台执行限制与此问题无关。此 limitation/exception 已添加到 Android 12/SDK 31 - Source.
这个例外是什么,为什么添加它?
针对 Android 12(API 级别 31)或更高级别的应用无法在 运行 处于后台时启动前台服务,少数特殊情况除外。如果应用程序在后台 运行ning 时尝试启动前台服务,并且前台服务不满足其中一种异常情况,系统会抛出 ForegroundServiceStartNotAllowedException
.
这些special cases是:
您的应用从用户可见状态转换,例如 activity。
您的应用可以从后台启动 activity,但应用在现有任务的后台堆栈中有 activity 的情况除外。
您的应用使用 Firebase 云消息传递接收高优先级消息。
用户对与您的应用相关的 UI 元素执行了操作。例如,他们可能会与气泡、通知、小部件或 activity.
进行交互
您的应用调用确切的警报来完成用户请求的操作。
您的应用是设备当前的输入法。
您的应用收到与地理围栏或 activity 识别转换相关的事件。
设备重新启动并在广播接收器中接收到 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,将您的 compileSdkVersion
& targetSdkVersion
降级到 API 级别 30 应该可以解决问题(至少暂时)。
解决方案 2
对于时间紧迫的工作
如果您使用前台服务来完成对时间敏感的工作,请在确切的警报内启动前台服务。从此处的文档中查看更多相关信息 -> Set an exact alarm.
为了 time-insensitive/expedited 工作
这是我最终用于我的应用程序的解决方案。使用 WorkManager
安排并启动后台工作。从此处的文档中查看更多相关信息 -> Schedule expedited work.
您可以在此处了解有关 WorkManager 的更多信息 -> WorkManager
Github WorkManager 示例的回购 -> WorkManager Samples
我特别添加了这个答案,因为搜索此异常不会调出任何资源来了解服务在 Android 12 上表现不同的原因。所有这些都存在于 Google 的文档中,并始终记得检查文档中的行为更改。
与此更改相关的所有内容都可以在此处找到 -> Android 12 Behavior Changes, specifically within the Foreground Service launch restrictions。
如果您的应用程序是 MediaPlayer(即使用 MediaBrowseService
)并且您遇到 ForegroundServiceStartNotAllowedException
崩溃,那么您可能需要:
更新您的清单以在 Service
声明
中使用 android:foregroundServiceType="mediaPlayback"
指定您的服务用于媒体播放
在调用 Serivce.startForeground
方法时包含 ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
参数
使用 .setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE)
创建通知以及 NotificationManager.IMPORTANCE_MAX
。
我将我的应用程序 targetSdkVersion
和 compileSdkVersion
升级到 SDK 31,并开始在后台更新小部件的服务中收到以下应用程序崩溃。
java.lang.RuntimeException:
at android.app.ActivityThread.handleReceiver (ActivityThread.java:4321)
at android.app.ActivityThread.access00 (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.createFromParcel (ForegroundServiceStartNotAllowedException.java:54)
at android.app.ForegroundServiceStartNotAllowedException.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.access00 (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.createFromParcel(ForegroundServiceStartNotAllowedException.java:54)
at android.app.ForegroundServiceStartNotAllowedException.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.access00(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)
我正在添加重现此问题的方法,并修复此问题,因为我在 Whosebug 上搜索时没有找到有关此问题的任何文档。
如何重现崩溃
第 1 步。将您的 targetSdkVersion
和 compileSdkVersion
更新为 SDK 31。
第 2 步。当您的应用处于后台时,尝试 运行 任何前台服务。在我的例子中,是小部件的 onUpdate
方法在 updatePeriodMillis
时间后被调用,这将启动一个前台服务,该服务通过从互联网获取适当的信息来更新数据。
记住: Android 8.0 中添加的后台执行限制与此问题无关。此 limitation/exception 已添加到 Android 12/SDK 31 - Source.
这个例外是什么,为什么添加它?
针对 Android 12(API 级别 31)或更高级别的应用无法在 运行 处于后台时启动前台服务,少数特殊情况除外。如果应用程序在后台 运行ning 时尝试启动前台服务,并且前台服务不满足其中一种异常情况,系统会抛出 ForegroundServiceStartNotAllowedException
.
这些special cases是:
您的应用从用户可见状态转换,例如 activity。
您的应用可以从后台启动 activity,但应用在现有任务的后台堆栈中有 activity 的情况除外。
您的应用使用 Firebase 云消息传递接收高优先级消息。
用户对与您的应用相关的 UI 元素执行了操作。例如,他们可能会与气泡、通知、小部件或 activity.
进行交互您的应用调用确切的警报来完成用户请求的操作。
您的应用是设备当前的输入法。
您的应用收到与地理围栏或 activity 识别转换相关的事件。
设备重新启动并在广播接收器中接收到 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,将您的 compileSdkVersion
& targetSdkVersion
降级到 API 级别 30 应该可以解决问题(至少暂时)。
解决方案 2
对于时间紧迫的工作
如果您使用前台服务来完成对时间敏感的工作,请在确切的警报内启动前台服务。从此处的文档中查看更多相关信息 -> Set an exact alarm.
为了 time-insensitive/expedited 工作
这是我最终用于我的应用程序的解决方案。使用 WorkManager
安排并启动后台工作。从此处的文档中查看更多相关信息 -> Schedule expedited work.
您可以在此处了解有关 WorkManager 的更多信息 -> WorkManager
Github WorkManager 示例的回购 -> WorkManager Samples
我特别添加了这个答案,因为搜索此异常不会调出任何资源来了解服务在 Android 12 上表现不同的原因。所有这些都存在于 Google 的文档中,并始终记得检查文档中的行为更改。
与此更改相关的所有内容都可以在此处找到 -> Android 12 Behavior Changes, specifically within the Foreground Service launch restrictions。
如果您的应用程序是 MediaPlayer(即使用 MediaBrowseService
)并且您遇到 ForegroundServiceStartNotAllowedException
崩溃,那么您可能需要:
更新您的清单以在
中使用Service
声明android:foregroundServiceType="mediaPlayback"
指定您的服务用于媒体播放在调用
Serivce.startForeground
方法时包含ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
参数
使用 .setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE)
创建通知以及 NotificationManager.IMPORTANCE_MAX
。