首页 > 解决方案 > Android 11 MediaStyle 通知崩溃

问题描述

我在我的应用程序中使用了 MediaStyle 通知。在 Android 11 之前它一直运行良好。在 Android 11 上,它会导致 Android UI 崩溃(不仅仅是应用程序,它还会关闭 Android 的 UI)。

应用程序上的logcat没有错误,但Android本身有错误。

    fun buildNotificationAsync(sessionToken: MediaSessionCompat.Token): Deferred<Notification> = GlobalScope.async {
    if (shouldCreateNowPlayingChannel()) {
        createNowPlayingChannel()
    }

    val controller = MediaControllerCompat(context, sessionToken)
    val description = controller.metadata.description
    val playbackState = controller.playbackState

    val builder = NotificationCompat.Builder(context, NOW_PLAYING_CHANNEL)

    // Only add actions for skip back, play/pause, skip forward, based on what's enabled.
    var playPauseIndex = 0
    if (playbackState.isSkipToPreviousEnabled) {
        builder.addAction(skipToPreviousAction)
        ++playPauseIndex
    }
    if (playbackState.isRewindEnabled) {
        builder.addAction(rewindAction)
        ++playPauseIndex
    }

    if (playbackState.isPlaying) {
        builder.addAction(pauseAction)
    } else if (playbackState.isPlayEnabled) {
        builder.addAction(playAction)
    }
    if (playbackState.isFastForwardEnabled) {
        builder.addAction(fastForwardAction)
    }
    if (playbackState.isSkipToNextEnabled) {
        builder.addAction(skipToNextAction)
    }
    val isHuaweiLollipop = (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP_MR1 ||
        Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) &&
        Build.MANUFACTURER.toLowerCase(Locale.getDefault()).contains("huawei")

    if (!isHuaweiLollipop) {
        val mediaStyle = MediaStyle()
                .setCancelButtonIntent(stopPendingIntent)
                .setMediaSession(sessionToken)
                .setShowActionsInCompactView(playPauseIndex)
                .setShowCancelButton(true)

        builder.setStyle(mediaStyle)
    }

    description.iconUri?.let { uri ->
        val largeIcon = CoverCache.getInstance().fetchLargeIfNecessary(context, uri)
        largeIcon?.let { icon -> builder.setLargeIcon(icon) }
    }

    return@async builder.setContentIntent(controller.sessionActivity)
            .setContentText(description.subtitle)
            .setContentTitle(description.title)
            .setDeleteIntent(stopPendingIntent)
            .setOnlyAlertOnce(true)
            .setSmallIcon(R.drawable.ic_stat)
            .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
            .build()
}

我看到了这个我认为相关的异常:

         AndroidRuntime  E  FATAL EXCEPTION: SysUiBg
                     E  Process: com.android.systemui, PID: 26311
                     E  java.lang.SecurityException: Permission Denial: opening provider androidx.core.content.FileProvider from ProcessRecord{410d665 26311:com.android.systemui/u0a141} (pid=26311, uid=10141) that is not exported from UID 10151
                     E      at android.os.Parcel.createExceptionOrNull(Parcel.java:2373)
                     E      at android.os.Parcel.createException(Parcel.java:2357)
                     E      at android.os.Parcel.readException(Parcel.java:2340)
                     E      at android.os.Parcel.readException(Parcel.java:2282)
                     E      at android.app.IActivityManager$Stub$Proxy.getContentProvider(IActivityManager.java:5702)
                     E      at android.app.ActivityThread.acquireProvider(ActivityThread.java:6813)
                     E      at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2930)
                     E      at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:2481)
                     E      at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1967)
                     E      at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1921)
                     E      at android.graphics.ImageDecoder$ContentResolverSource.createImageDecoder(ImageDecoder.java:274)
                     E      at android.graphics.ImageDecoder.decodeBitmapImpl(ImageDecoder.java:1862)
                     E      at android.graphics.ImageDecoder.decodeBitmap(ImageDecoder.java:1855)
                     E      at com.android.systemui.media.MediaDataManager.loadBitmapFromUri(MediaDataManager.kt:462)
                     E      at com.android.systemui.media.MediaDataManager.loadBitmapFromUri(MediaDataManager.kt:433)
                     E      at com.android.systemui.media.MediaDataManager.loadMediaDataInBg(MediaDataManager.kt:331)
                     E      at com.android.systemui.media.MediaDataManager.access$loadMediaDataInBg(MediaDataManager.kt:89)
                     E      at com.android.systemui.media.MediaDataManager$loadMediaData$1.run(MediaDataManager.kt:241)
                     E      at android.os.Handler.handleCallback(Handler.java:938)
                     E      at android.os.Handler.dispatchMessage(Handler.java:99)
                     E      at android.os.Looper.loop(Looper.java:223)
                     E      at android.os.HandlerThread.run(HandlerThread.java:67)
                     E  Caused by: android.os.RemoteException: Remote stack trace:
                     E      at com.android.server.am.ActivityManagerService.getContentProviderImpl(ActivityManagerService.java:7155)
                     E      at com.android.server.am.ActivityManagerService.getContentProvider(ActivityManagerService.java:7594)
                     E      at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:2381)
                     E      at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2883)
                     E      at android.os.Binder.execTransactInternal(Binder.java:1159)

如果我删除设置小图标的构建器的行,它可以正常工作(但这会使通知只是一个没有媒体样式的普通通知)。您会注意到例外情况是缺少从文件提供程序获取某些内容的权限,但通知中没有使用类似的内容。

标签: androidnotifications

解决方案


我发现了这个问题。由于这是一个 MediaStyle,我们设置了 MediaSession,会话可以访问 MediaMetadataCompat 项。为了构建这些项目,我们有:

                    val builder = MediaMetadataCompat.Builder()
                        .putString(MediaMetadataCompat.METADATA_KEY_TITLE, doc.title)
                        .putString(MediaMetadataCompat.METADATA_KEY_AUTHOR, doc.author ?: "Unknown")
                        .putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, doc.documentId)
                        .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, folders.firstOrNull { it.folderId == doc.folderId }?.folderName)
                        .putString(MediaMetadataCompat.METADATA_KEY_GENRE, sourceType?.name ?: "Unknown") // We don't have Genre info, we'll use for the sourceType
                        .putLong(METADATA_KEY_UAMP_FLAGS, MediaBrowserCompat.MediaItem.FLAG_PLAYABLE.toLong())
                if (originalDocumentType != null) {
                    // We don't have a disc no, so
                    builder.putLong(MediaMetadataCompat.METADATA_KEY_DISC_NUMBER, originalDocumentType.ordinal.toLong())
                }
                // we'll use it doc type.

                if (icon != null) {
                    builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI, icon.toString())
                }

它是设置 Icon uri 的最后一行。那需要许可。在该行上方添加此内容

                        context.grantUriPermission("com.android.systemui", icon, Intent.FLAG_GRANT_READ_URI_PERMISSION)

现在应用程序运行正常。但是,由于缺少该权限而导致 Android UI 崩溃的事实仍然是一个错误。我希望无法显示图标甚至使应用程序崩溃,但肯定不会使 Android 本身崩溃。


推荐阅读