[英]Start foreground service after notification permission was disabled causes crash (Android 13)
所以,我一直在試驗新的 Android 模擬器(即 Android 13 或 Android Tiramisu,API 33),在一個應用程序上,我需要一個前台服務。
該應用的目標 SDK 目前是 33。
由於通知要求,我已將android.permission.POST_NOTIFICATIONS
添加到清單中。 而且,因為它也是一個運行時權限,所以我在打開應用程序后詢問權限。
如果用戶拒絕該權限,但在使用startForegroundService
啟動它后嘗試執行涉及前台服務的任務,則在從我的服務調用startForeground
時,我會崩潰:
android.app.RemoteServiceException$CannotPostForegroundServiceNotificationException: Bad notification for startForeground
at android.app.ActivityThread.throwRemoteServiceException(ActivityThread.java:1983)
at android.app.ActivityThread.-$$Nest$mthrowRemoteServiceException(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2242)
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:7898)
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:936)
注意異常名稱: CannotPostForegroundServiceNotificationException 。 顯然,系統有效地阻止了我發布前台服務通知。 這發生在使用有效通知的startForeground
調用之后(無論如何,直到 API 32,我沒有看到 API 32 和 API 33 之間用於構建通知本身的變化,除了我已經在做的setOngoing(true)
之外) .
因此,我檢查了是否可以使用NotificationManager.areNotificationsEnabled()
發布通知。 如果用戶按預期拒絕權限,則返回 false。 代碼現在看起來像這樣:
if (mNotificationManager.areNotificationsEnabled())
startForeground(123, mNotificationBuilder.build())
而且,正如預期的那樣, startForeground
不會被調用。 但是,需要執行的任務可能很長(可能大約 2 分鍾)並且必須在后台執行,不能在作業中或通過WorkManager
執行,並且如果不調用startForeground
,應用程序會在大約20 秒,包含以下內容:
android.app.RemoteServiceException$ForegroundServiceDidNotStartInTimeException: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{ecbbdfb u0 com.example.android/.service.FgService}
at android.app.ActivityThread.generateForegroundServiceDidNotStartInTimeException(ActivityThread.java:2006)
at android.app.ActivityThread.throwRemoteServiceException(ActivityThread.java:1977)
at android.app.ActivityThread.-$$Nest$mthrowRemoteServiceException(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2242)
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:7898)
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:936)
Caused by: android.app.StackTrace: Last startServiceCommon() call for this service was made here
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1915)
at android.app.ContextImpl.startForegroundService(ContextImpl.java:1870)
at android.content.ContextWrapper.startForegroundService(ContextWrapper.java:822)
at com.example.android.MainActivity.startTaskWithFgService(MainActivity.kt:30)
at com.example.kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:749)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
我應該注意,如果用戶接受通知權限,通知就會正常可見,所以這看起來像是一個權限問題,並且沒有觀察到崩潰。
編輯:創建的通知頻道應該發布靜默通知。 因此,這就是創建通知通道的方式(並且在嘗試發布通知時也包括在內):
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
withNotificationManager {
if (notificationChannels?.map { it.id }?.contains(SILENT_NOTIF_CHANNEL_ID) == true)
return@withNotificationManager
val channel = NotificationChannel(
SILENT_NOTIF_CHANNEL_ID,
getString(R.string.silent_notif_channel_name),
NotificationManager.IMPORTANCE_MIN).apply {
enableLights(false)
setShowBadge(false)
setSound(null, null)
description = getString(R.string.silent_notif_channel_desc)
vibrationPattern = null
lockscreenVisibility = Notification.VISIBILITY_SECRET
}
createNotificationChannel(channel)
}
}
據我了解,發生了兩件事:
這兩個條件有效地刪除了前台服務功能。 這對我來說似乎是一個疏忽。
引用 Android 13 行為更改通知權限( 鏈接):
"應用程序不需要請求 POST_NOTIFICATIONS 權限來啟動前台服務。但是,應用程序必須在啟動前台服務時包含通知,就像在以前的 Android 版本上一樣。 "
所以,我的問題是:
如果用戶拒絕權限,我應該怎么做才能在沒有前台服務的情況下在后台執行長時間任務?
感謝您閱讀這個問題,我感謝任何幫助、回答或討論。
好的,我找到了問題所在。
顯然,這是由於創建通知通道時的事實。 到目前為止,根據我的觀察,在發布通知之前創建一個頻道很好,我們沒有觀察到崩潰/錯誤。 在這種情況下,通道也是在通知發布之前創建的,也就是在服務啟動之后和調用startForeground
之前。
如果用戶事先拒絕該權限,則嘗試靜默創建通知通道會失敗,而不會崩潰。 然后,在嘗試使用startForeground
發布通知后,它會因問題中發布的異常而失敗,並導致無法解決的問題。
由於我們不希望用戶在第一個應用程序啟動時拒絕通知權限,因此我將創建通知通道任務移至Application.onCreate()
並解決了問題。 前台服務工作,它出現在 FGS(前台服務管理器)中。
盡管據我所知,文檔中沒有提到這一點。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.