Flutter Android前台音频服务在应用被终止时意外停止的问题求助
Flutter Android前台音频服务在应用被终止时意外停止的问题求助
大家好,我最近在开发一个Flutter Android的前台音频流服务,用Kotlin结合ExoPlayer实现直播音频播放,同时通过系统通知栏展示媒体控制按钮。目前应用在前台或后台挂起时都能正常工作,但一旦把应用从最近应用列表划掉,或者进程被系统杀死,音频服务就跟着停了,通知栏的控制通知也直接消失了——这完全不符合我对前台服务应该持续运行的预期。
我已经配置了必要的权限,也按照前台服务的要求完成了核心逻辑,但问题还是没解决,想请各位大佬帮忙排查下可能的问题。
已实现的核心内容
1. AndroidManifest.xml配置
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <uses-permission android:name="android.permission.WAKE_LOCK"/> <application android:label="Simple Radio" android:name="${applicationName}" android:icon="@mipmap/ic_launcher"> <activity android:name=".MainActivity" android:exported="true" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:windowSoftInputMode="adjustResize"> <meta-data android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme"/> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <service android:name=".AudioPlayerService" android:foregroundServiceType="mediaPlayback" android:exported="true" android:enabled="true"/> <receiver android:name=".NotificationActionReceiver" android:exported="true"> <intent-filter> <action android:name="ACTION_PLAY"/> <action android:name="ACTION_PAUSE"/> <action android:name="ACTION_STOP"/> </intent-filter> </receiver> <meta-data android:name="flutterEmbedding" android:value="2" /> <meta-data android:name="firebase_messaging_auto_init_enabled" android:value="false" /> <meta-data android:name="firebase_analytics_collection_enabled" android:value="false" /> </application> </manifest>
2. MainActivity代码(Flutter与原生通信部分)
package com.example.simple_radio import android.content.Intent import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.EventChannel class MainActivity : FlutterActivity() { private val CHANNEL = "audio.channel" private val EVENT_CHANNEL = "audio.events" companion object { var eventSink: EventChannel.EventSink? = null } override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result -> when (call.method) { "play" -> { val url = call.argument<String>("url") ?: "" val title = call.argument<String>("title") ?: "Live Stream" val image = call.argument<String>("image") ?: "Live Stream" val intent = Intent(this, AudioPlayerService::class.java).apply { action = "ACTION_PLAY" putExtra("url", url) putExtra("title", title) putExtra("image", image) } startForegroundService(intent) result.success(null) } "pause" -> { val intent = Intent(this, AudioPlayerService::class.java).apply { action = "ACTION_PAUSE" } startService(intent) result.success(null) } "stop" -> { val intent = Intent(this, AudioPlayerService::class.java).apply { action = "ACTION_STOP" } startService(intent) result.success(null) } "getStatus" -> { val intent = Intent(this, AudioPlayerService::class.java).apply { action = "GET_STATUS" } startService(intent) result.success(null) } else -> result.notImplemented() } } EventChannel(flutterEngine.dartExecutor.binaryMessenger, EVENT_CHANNEL).setStreamHandler( object : EventChannel.StreamHandler { override fun onListen(arguments: Any?, events: EventChannel.EventSink?) { eventSink = events } override fun onCancel(arguments: Any?) { eventSink = null } } ) } }
3. AudioPlayerService(部分代码)
package com.example.simple_radio import android.app.* import android.content.Context import android.content.Intent import android.os.IBinder import androidx.core.app.NotificationCompat // 注:完整代码尚未粘贴,核心逻辑已包含: // 1. 初始化ExoPlayer并加载音频流 // 2. 在onStartCommand中创建媒体风格通知 // 3. 调用startForeground(NOTIFICATION_ID, notification)将服务设为前台 // 4. 实现了播放、暂停、停止的逻辑处理
我的疑问和排查点
我已经做了这些操作:
- 申请了所有必要的权限:
INTERNET、POST_NOTIFICATIONS、FOREGROUND_SERVICE、WAKE_LOCK - 给服务指定了
foregroundServiceType="mediaPlayback" - 用
startForegroundService()启动服务,并且在服务内部及时调用了startForeground()绑定通知 - 通知用的是
MediaStyle,包含了播放/暂停/停止的控制按钮
但为什么应用从最近列表划掉后,前台服务还是会被杀死?会不会是:
- 我的
onStartCommand返回值有问题?我目前返回的是START_STICKY,是不是应该用START_REDELIVER_INTENT? - 厂商的后台限制?比如小米、华为这类厂商的“纯净模式”或者后台管理策略?
- 通知的配置有问题?比如没有设置正确的
ContentIntent或者通知渠道? - ExoPlayer的配置有没有遗漏?比如没有设置
WakeLock或者AudioAttributes?
有没有大佬能帮我分析下可能的原因,或者给我一些排查的方向?非常感谢!
内容来源于stack exchange




