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

Flutter应用使用just_audio_background在OnePlus 8T播放时崩溃

Flutter just_audio_background 在OnePlus 8T上崩溃问题解决

问题概述

使用just_audio_background实现后台音频播放的Flutter应用,在OnePlus 8T设备上关闭应用设置中的「Audio Playback」静默通知分类后,启动音频播放时触发崩溃,报错如下:

D/OplusScrollToTopManager(31518): com.example.yessey/com.ryanheise.audioservice.AudioServiceActivity,This DecorView@6dbafe8[AudioServiceActivity] change focus to true
D/AndroidRuntime(31518): Shutting down VM
E/AndroidRuntime(31518): FATAL EXCEPTION: main
E/AndroidRuntime(31518): Process: com.example.yessey, PID: 31518
E/AndroidRuntime(31518): android.app.RemoteServiceException$BadForegroundServiceNotificationException: Bad notification(tag=null, id=1124) posted from package com.example.yessey, crashing app(uid=11029, pid=31518): Couldn't inflate contentViewsjava.lang.IndexOutOfBoundsException: Index: 3, Size: 3

应用在模拟器及开启该通知分类时运行正常,卸载重装、移除专辑图片等操作均无法解决问题。

问题原因

OnePlus定制ROM对通知渠道的权限管控存在特殊逻辑:当用户禁用了对应通知渠道(或关闭静默通知分类),just_audio_background尝试通过该渠道创建前台服务通知时,系统会拒绝并抛出未被插件捕获的异常,直接导致应用崩溃。

解决方案

1. 显式设置通知渠道重要性

在初始化just_audio_background时,添加渠道重要性配置,确保渠道创建时的优先级,降低被系统标记为易禁用类型的概率:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await Wakelock.enable();
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);

  try {
    await JustAudioBackground.init(
      androidNotificationChannelId: 'com.ryanheise.bg_demo.channel.audio',
      androidNotificationChannelName: 'Audio playback',
      androidNotificationOngoing: true,
      // 添加渠道重要性设置
      androidNotificationChannelImportance: AndroidNotificationImportance.high,
    );
  } catch (e) {
    print("JustAudioBackground初始化错误: $e");
  }
}

2. 捕获播放阶段异常

在启动播放的方法中添加try-catch块,捕获平台异常并处理,避免应用直接崩溃:

Future<void> initializePlayer() async {
  try {
    final audioSource = AudioSource.uri(
      Uri.parse('https://example/mute.mp3'),
      tag: MediaItem(
        id: '1',
        album: "per salvare il replay!",
        title: "Cambia volume",
        artUri: Uri.parse('https://example.png'),
      ),
    );
    await _player.setAudioSource(audioSource);
    await _player.setLoopMode(LoopMode.one);
    await _player.play();
  } catch (e) {
    print("播放启动失败: $e");
    // 可在此处添加用户提示,例如弹出AlertDialog告知需开启通知权限
  }
}

3. 提前检查通知渠道状态(需Platform Channel实现)

通过原生Android API检查对应通知渠道是否可用,在播放前引导用户开启权限:

Flutter端代码

import 'package:flutter/services.dart';

class NotificationChannelChecker {
  static const MethodChannel _channel = MethodChannel('notification_channel_checker');

  static Future<bool> isChannelEnabled(String channelId) async {
    try {
      return await _channel.invokeMethod('isChannelEnabled', {'channelId': channelId});
    } on PlatformException catch (e) {
      print("检查渠道状态失败: ${e.message}");
      return false;
    }
  }
}

Android端代码(MainActivity中)

import android.app.NotificationManager
import android.content.Context
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity: FlutterActivity() {
    private val CHANNEL = "notification_channel_checker"

    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
            if (call.method == "isChannelEnabled") {
                val channelId = call.argument<String>("channelId")
                val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
                val channel = notificationManager.getNotificationChannel(channelId)
                val isEnabled = channel != null && channel.importance != NotificationManager.IMPORTANCE_NONE
                result.success(isEnabled)
            } else {
                result.notImplemented()
            }
        }
    }
}

使用时,在initializePlayer前调用:

bool isChannelEnabled = await NotificationChannelChecker.isChannelEnabled('com.ryanheise.bg_demo.channel.audio');
if (!isChannelEnabled) {
  // 引导用户前往应用设置开启通知渠道
} else {
  // 启动播放
}

4. 请求通知权限(Android 13+)

使用permission_handler插件请求POST_NOTIFICATIONS权限,确保应用拥有创建通知的基础权限:

import 'package:permission_handler/permission_handler.dart';

// 在应用启动或播放前调用
await Permission.notification.request();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 04:54:57