簡體   English   中英

禁用通知權限后啟動前台服務導致崩潰(Android 13)

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM