web-dev-qa-db-ja.com

通知を作成/更新するためにRemoteServiceExceptionが発生するのはなぜですか?

バックグラウンド

私は数年間取り組んできた空き時間アプリを持っています( ここ )、そして私は処理しようとしますできるだけ多くのクラッシュが発生します(クラッシュレポートを見るのは嫌です!)。

問題

まったく新しいように見える最近のクラッシュの1つは、次のとおりです。

Android.app.RemoteServiceException: 
  at Android.app.ActivityThread$H.handleMessage (ActivityThread.Java:1768)
  at Android.os.Handler.dispatchMessage (Handler.Java:106)
  at Android.os.Looper.loop (Looper.Java:164)
  at Android.app.ActivityThread.main (ActivityThread.Java:6494)
  at Java.lang.reflect.Method.invoke (Method.Java)
  at com.Android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.Java:438)
  at com.Android.internal.os.ZygoteInit.main (ZygoteInit.Java:807)

そして、それは私が見るすべてです...

Android 8.1でのみ発生するようです。このアプリは非常に人気があるため、Android 8.1でも発生すると確信しています。 。

私が試したこと

インターネットを検索すると、同様のクラッシュが見つかりましたが、すべてのクラッシュで、より多くの手がかりがありました。

それで、私は最近行った変更を思い出そうとしました。唯一の変更は、サポートライブラリをAndroid-Xに移行することでした。残りの変更は非常にマイナーであり、それらが原因になる可能性はないと思います。

これ以上の手がかりがないので、Android-Xの部分について報告することにしました ここ (詳細はこちら、必要に応じて)、問題を修正しようとしているためだとは思わないので、非常に具体的なもののように見えます。

後でFirebaseCrashlyticsを統合し、そのような各ログの上にこの小さな追加の手がかりを取得しました。

Fatal Exception: Android.app.RemoteServiceException
Bad notification for startForeground: Java.lang.RuntimeException: invalid channel for service notification: Notification(channel=channel_id__app_monitor pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x40 color=0x00000000 category=service vis=SECRET)

私はサービスを正しく開いているので、これは奇妙です。そうでなければ、まったく機能しませんでした。これは、Android 8.1でのみ発生し、たとえば8.0では発生しないという点で特に奇妙です。 、フォアグラウンドサービスを開始する方法と同じ要件があります。

この問題のある通知は、アプリ関連のイベントをグローバルに監視するために使用するフォアグラウンドサービスに関するものです(Android O、BroadcastReceiversの制限があります)からのみ)。2つのケースで更新されます。

  1. ロケールの変更
  2. ある時点で表示されるダイアログのチェックボックスをオンにします(ダイアログをクリックしたとき)。

これらの両方をテストしたところ、Android 8.0と8.1の両方で正常に動作します。

通知を作成/更新するコードは次のとおりです。

    @JvmStatic
    fun getUpdatedAppMonitorNotification(context: Context): Notification {
        val builder = Builder(context, context.getString(R.string.channel_id__app_monitor)).setSmallIcon(R.drawable.ic_stat_app_icon)//
                .setPriority(Notification.PRIORITY_DEFAULT).setCategory(Notification.CATEGORY_SERVICE)
        builder.setVisibility(NotificationCompat.VISIBILITY_SECRET)
        builder.setShowWhen(false)
        if (!PreferenceUtil.getBooleanPref(context, R.string.pref__avoid_showing_app_monitor_notification_dialog, false))
            builder.setContentTitle(context.getString(R.string.app_monitor__notification_title))
        if (VERSION.SDK_INT < VERSION_CODES.P) {
            val mainIntent = Intent(context, MainActivity::class.Java)
                    .putExtra(MainActivity.EXTRA_OPENED_FROM_NOTIFICATION, true)
            builder.setContentIntent(PendingIntent.getActivity(context, 0, mainIntent, PendingIntent.FLAG_UPDATE_CURRENT))
        } else {
            val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
                    .putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName)
                    .putExtra(Settings.EXTRA_CHANNEL_ID, context.getString(R.string.channel_id__app_monitor))
            val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
            builder.setContentIntent(pendingIntent)
        }
        return builder.build()
    }

そして、私がサービスで使用するコード:

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    NotificationId.initNotificationsChannels(this)
    val notification = getUpdatedAppMonitorNotification(this)
    startForeground(NotificationId.APP_MONITOR, notification)
    ...
    return super.onStartCommand(intent, flags, startId)
}

そして、これは私が通知を更新するために他の場所から呼び出すコードです:

    @JvmStatic
    fun updateAppMonitorNotification(context: Context) {
        if (VERSION.SDK_INT < VERSION_CODES.O)
            return
        val notification = AppMonitorService.getUpdatedAppMonitorNotification(context)
        val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.notify(NotificationId.APP_MONITOR, notification)
    }

質問

  1. なぜそれが起こるのですか? Android X?または通知の作成に問題がありますか?

  2. Android 8.1でのみ発生するのはなぜですか?

8

OK、なぜこれが発生するのかはまだわかりませんが、私が見つけた回避策は、context.startForegroundService関数を介して安全に呼び出すことにより、サービスに通知のすべての更新を行わせることです。 。

これまでのところ、代わりにこれを使用することで、この種のクラッシュはまだ見られません。

0

これが問題だと思います:

.putExtra(Settings.EXTRA_CHANNEL_ID, context.getString(R.string.channel_id__app_monitor))

ローカライズされたチャネル名ではなく、(変更されない)チャネルIDを入力する必要があります

これを再現できる場合は、バグレポートでAppSettings。* [your app]を調べて、使用しようとしているIDと一致するIDを持つチャネルがあるかどうかを確認することもできます。

0
Prags