use*_*924 84 android android-service android-12
我注意到 Pixel 5 和 Pixel 4a(均在 Android 12 上)有一个例外(Firebase Crashlytics),没有其他设备,仅发生两次,每个设备一次。
这是什么意思?Android 11 和 12 对于前台服务的使用规则相同,但 Android 11 没有问题。这是 Pixel 的错误吗?
来自 Firebase Crashlytics:
Fatal Exception: android.app.ForegroundServiceStartNotAllowedException
startForegroundService() not allowed due to mAllowStartForeground false: service com.*.*/.service.RecorderService
android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel (ForegroundServiceStartNotAllowedException.java:54)
androidx.core.content.ContextCompat.startForegroundService (ContextCompat.java:6)
MyAppPackageHidden.service.RecorderService$Companion.startService (RecorderService.java:2)
MyAppPackageHidden.ui.rec.RecActivity$getConnectionRecorderService$1.onServiceConnected (RecActivity.java:4)
android.app.LoadedApk$ServiceDispatcher.doConnected (LoadedApk.java:2077)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1003)
Fatal Exception: android.app.ForegroundServiceStartNotAllowedException: startForegroundService() not allowed due to mAllowStartForeground false: service MyAppPackageHidden/.service.RecorderService
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 androidx.core.content.ContextCompat$Api26Impl.startForegroundService(ContextCompat.java)
at androidx.core.content.ContextCompat.startForegroundService(ContextCompat.java:6)
at MyAppPackageHidden.service.RecorderService$Companion.startService(RecorderService.java:2)
at MyAppPackageHidden.ui.rec.RecActivity$getConnectionRecorderService$1.onServiceConnected(RecActivity.java:4)
at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:2077)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:2110)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7838)
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)
Caused by android.os.RemoteException: Remote stack trace:
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)
Him*_*kur 46
除少数特殊情况外,面向 Android 12(API 级别 31)或更高版本的应用无法在后台运行时启动前台服务。如果应用程序在后台运行时尝试启动前台服务,并且前台服务不满足其中一种异常情况,系统将抛出 ForegroundServiceStartNotAllowedException。
后台启动限制的豁免
在以下情况下,即使您的应用程序在后台运行,您的应用程序也可以启动前台服务:
nir*_*997 26
之前我们用来Service运行后台任务,例如备份数据、设置提醒通知等。之前调用该服务的代码如下
Intent serviceIntent = new Intent ( context, BackupService.class );
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService ( serviceIntent );
} else {
context.startService ( serviceIntent );
}
Run Code Online (Sandbox Code Playgroud)
但是,由于Android 12 - Foreground service launch restrictions,我们将无法调用 Service 来执行后台任务。要了解有关此限制的更多信息,请参阅Android 12 行为更改。
因此,从现在开始,(即)从 targetSdk 31 / Android 12+ 开始,Service只能在应用程序位于前台时调用。当应用程序关闭或应用程序转到后台时,调用ServiceusingstartForegroundService将导致ForegroundServiceStartNotAllowedException. 因此,要在Android 12及更高版本中执行后台任务,我们需要使用Worker而不是Service. 要了解更多信息Worker,请参阅工作请求。
因此,对于面向 SDK 31 / Android 12+ 的应用程序,调用后台任务的代码如下:
Intent serviceIntent = new Intent ( context, BackupService.class );
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
OneTimeWorkRequest request = new OneTimeWorkRequest.Builder ( BackupWorker.class ).addTag ( "BACKUP_WORKER_TAG" ).build ();
WorkManager.getInstance ( context ).enqueue ( request );
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService ( serviceIntent );
} else {
context.startService ( serviceIntent );
}
Run Code Online (Sandbox Code Playgroud)
BackupService(现有)的示例代码。
public class BackupService extends Service {
private static final String TAG = "BackupService";
@Nullable
@Override
public IBinder onBind ( Intent intent ) {
return null;
}
@Override
public int onStartCommand ( Intent intent, int flags, int startId ) {
Log.d ( TAG, "onStartCommand" );
startForeground ( BACKUP_SERVICE_NOTIFICATION_ID, createServiceNotification () );
//call methods to perform background task
return super.onStartCommand ( intent, flags, startId );
}
}
Run Code Online (Sandbox Code Playgroud)
BackupWorker(新增)的示例代码。
public class BackupWorker extends Worker {
private static final String TAG = "BackupWorker";
public BackupWorker ( @NonNull Context context, @NonNull WorkerParameters workerParams ) {
super ( context, workerParams );
}
@NonNull
@Override
public Result doWork () {
//call methods to perform background task
return Result.success ();
}
}
Run Code Online (Sandbox Code Playgroud)
确保在模块级gradle文件中添加以下依赖项
implementation 'androidx.work:work-runtime:2.7.1'
implementation 'com.google.guava:guava:27.0.1-android'
Run Code Online (Sandbox Code Playgroud)
我已经测试了上述代码在 Android 5、Android 8、Android 11 和 Android 12 上的工作情况。在我的情况下,工作按预期进行。
希望这个解决方案可以帮助那些将应用程序定位为 SDK 31 / Android 12+ 的人。
最多Android 12使用android:foregroundServiceType="yourType"服务属性即可AndroidManifest从后台启动您的服务(我假设如果您没有找到合适的服务类型,您需要跳过此步骤。不幸的是,我还没有在文档中找不到有关此内容的信息)。在 Android 12 及更高版本中 - 如果您的任务允许您使用WorkManager,那么您应该将您的服务替换为Worker,例如下载/上传文件或定期同步。如果您的任务比较广泛,需要服务不断在后台运行,例如播放音频,那么这里您仍然需要使用前台服务,但使用AlarmManager. 如果您的服务应该立即启动,那么您需要使用精确的警报来启动您的服务。为此,您必须确保用户已授予SCHEDULE_EXACT_ALARM权限。它由系统自动授予,但可以随时由用户或系统撤销。
假设我们用来PlaybackService播放音频。那么我的解决方案是:
android:foregroundServiceType="mediaPlayback"到您的AndroidManifest.xml文件:<service
android:name=".data.playback.PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="false"
/>
Run Code Online (Sandbox Code Playgroud)
private suspend fun startPlaybackService(state: PlaybackState) {
withContext(Dispatchers.Main) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val operation = PendingIntent.getForegroundService(
context,
REQUEST_CODE,
Intent(context, PlaybackService::class.java),
FLAG_UPDATE_CURRENT_COMPAT
)
val alarmManager = context.getSystemService<AlarmManager>()
if (state in PlaybackStateSets.ACTIVE) {
logi { "Starting playback service with exact alarm" }
startPlaybackServiceWithAlarm(alarmManager, operation)
} else {
logi { "Cancelling exact alarm operation" }
alarmManager.cancel(operation)
}
} else {
if (state in PlaybackStateSets.ACTIVE) {
logi { "Starting playback service" }
ContextCompat.startForegroundService(
context,
Intent(context, PlaybackService::class.java)
)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
Alarms & reminders:fun navigateToAlarmSettings(context: Context) {
context.startActivity(
Intent().apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
action = Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM
} else {
loge { "Attempt to create Alarm settings section intent on Android sdk version < 31" }
}
}
)
}
Run Code Online (Sandbox Code Playgroud)
SCHEDULE_EXACT_ALARM您的应用程序获得权限后,系统会向其发送广播ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED。您可以实现广播接收器来处理此更改。链接:
| 归档时间: |
|
| 查看次数: |
67838 次 |
| 最近记录: |