You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android 13下Media3 MediaSessionService前台服务启动崩溃求助

问题描述

我开发了一款基于Media3 MediaSessionService的媒体播放器应用,核心实现与遇到的问题如下:

ExoPlayer初始化(Service的onCreate方法中)

mTrackSelector = DefaultTrackSelector(this)
mTrackSelector.parameters = mTrackSelector.parameters
    .buildUpon()
    .setPreferredAudioLanguage("en")
    .setPreferredTextLanguage("en")
    .build()

val mAudioAttr = AudioAttributes.Builder()
    .setUsage(C.USAGE_MEDIA)
    .setContentType(C.AUDIO_CONTENT_TYPE_SPEECH)
    .build()

mPlayer = ExoPlayer.Builder(this)
    .setSeekBackIncrementMs(30000)
    .setSeekForwardIncrementMs(30000)
    .setTrackSelector(mTrackSelector)
    .setAudioAttributes(mAudioAttr, true)
    .setVideoScalingMode(C.VIDEO_SCALING_MODE_SCALE_TO_FIT)
    .build()

MediaSession创建

mMediaSession = MediaSession.Builder(this, forwardingPlayer)
    .setId(System.currentTimeMillis().toString().takeLast(5))
    .setCallback(librarySessionCallback).build()

测试与生产环境差异

  • 测试环境(Android 8-14真机/模拟器):无需通知权限即可正常运行,Media3控制通知正常显示
  • 生产环境:Firebase Crashlytics上报Android 13设备出现以下崩溃:
Fatal Exception: 
android.app.RemoteServiceException$ForegroundServiceDidNotStartInTimeException
Context.startForegroundService() did not then call Service.startForeground(): 
ServiceRecord{4e0c02b u0 xx.xxxxx.PlayerService}

已尝试的操作

  • 实现MediaSessionServiceListener并重写onForegroundServiceStartNotAllowedException,但在自用Android13-14设备/模拟器上无法复现崩溃或触发该方法
  • Gradle配置:compileSdk 34、targetSdk 34
  • 服务启动方式:
val mSessionToken = SessionToken(nInterface.getActivity(), ComponentName(nInterface.getActivity(), PlayerService::class.java))

AndroidManifest配置

<service android:name=".engine.notification.PlayerService"
    android:foregroundServiceType="mediaPlayback"
    android:stopWithTask="true"
    android:exported="true">
    <intent-filter>
        <action android:name="androidx.media3.session.MediaSessionService"/>
    </intent-filter>
</service>

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />

注意到YouTube Premium在Android13-14无需通知权限即可后台播放,请问:

  1. 我哪里出错了?
  2. 如何复现该崩溃?

问题分析与解决方案

1. 崩溃原因定位

这个崩溃的核心是服务启动后未在5秒(Android 12+规定时限)内完成startForeground()调用,结合你的实现,可能的触发点如下:

  • MediaSession初始化延迟:你在onCreate中先初始化ExoPlayer,再创建MediaSession。如果ExoPlayer初始化耗时过长(比如解码器加载、轨道选择器初始化阻塞),会导致Media3无法及时触发前台服务的通知绑定,超过系统时限。
  • 音频属性适配问题:你设置的AUDIO_CONTENT_TYPE_SPEECH类型,部分Android 13设备可能对语音类音频的前台服务判定逻辑特殊,导致Media3未自动触发前台通知。
  • 后台启动场景限制:若服务是从后台场景触发(比如应用被杀死后通过耳机线控/蓝牙设备启动),Android 13的后台启动限制会让服务启动后处于受限状态,无法及时完成前台绑定。
  • Media3版本bug:若使用的Media3版本较旧,可能存在Android 13前台服务适配漏洞,未正确处理mediaPlayback类型的前台服务豁免逻辑。

2. 修复方案

  • 调整初始化顺序:将MediaSession的创建提前到ExoPlayer初始化之前,确保Media3能及时接管前台服务逻辑:
    override fun onCreate() {
        super.onCreate()
        // 先创建MediaSession
        mMediaSession = MediaSession.Builder(this, forwardingPlayer)
            .setId(System.currentTimeMillis().toString().takeLast(5))
            .setCallback(librarySessionCallback).build()
        // 再初始化ExoPlayer
        initExoPlayer()
    }
    
  • 修改音频属性:将音频类型改为通用媒体类型,避免设备对语音类型的特殊处理:
    val mAudioAttr = AudioAttributes.Builder()
        .setUsage(C.USAGE_MEDIA)
        .setContentType(C.AUDIO_CONTENT_TYPE_MUSIC) // 改为通用媒体类型
        .build()
    
  • 升级Media3版本:更新至Media3最新稳定版(如1.2.0+),修复已知的Android 13适配问题。
  • 绑定SessionActivity:通过MediaSession.Builder.setSessionActivity()绑定一个合法的Activity,帮助系统识别合法的前台启动场景。

3. 复现崩溃的方法

  • 后台触发服务启动:完全退出应用(划掉后台),通过耳机线控、蓝牙设备的播放按钮触发服务启动,此时Android 13的后台启动限制会放大服务初始化延迟的影响,容易触发超时崩溃。
  • 模拟初始化耗时:在ExoPlayer初始化前添加Thread.sleep(6000)模拟缓慢初始化,超过系统5秒时限触发崩溃。
  • 禁用通知权限测试:手动禁用应用的通知权限后启动播放,部分Android 13设备会因Media3无法创建前台通知,导致服务无法完成前台绑定而崩溃。

内容的提问来源于stack exchange,提问作者BejanCorneliu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 01:25:55