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

Flutter Android App使用audio_service,杀死应用后音频未停止的问题求助

Flutter Android App使用audio_service,杀死应用后音频未停止的问题求助

大家好,我正在开发一个基于Flutter的安卓电台应用,目前遇到了一个棘手的问题:当音乐正在播放时,如果我“杀掉”应用进程,音频并不会停止,还会继续播放。我尝试查找了相关的解决方案,但还是没能结合自己的项目解决问题,所以想把代码贴出来,麻烦大家帮我看看哪里出了问题。

我当前使用audio_service和just_audio来处理音频播放,已经配置了安卓通知通道并设置了androidNotificationOngoing: true,但问题依然存在。


main.dart 代码

late AudioHandler audioHandler;

void main() async {
  audioHandler = await AudioService.init(
    builder: () => AudioPlayerHandler(),
    config: const AudioServiceConfig(
      androidNotificationChannelId: 'com.radio.cyprus.audio',
      androidNotificationChannelName: 'Radio Playback',
      androidNotificationOngoing: true,
    ),
  );

  await JustAudioBackground.init(
    androidNotificationChannelId: 'com.radio.cyprus.audio',
    androidNotificationChannelName: 'Radio Playback',
    androidNotificationOngoing: true,
  );

  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
  MobileAds.instance.initialize();

  // 禁用横屏
  SystemChrome.setPreferredOrientations(
      [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
  // HttpOverrides.global = MyHttpOverrides();

  runApp(const MyApp());
  DependencyInjection.init();
}

radio_stations.dart 代码

import 'dart:io';
import 'package:audio_service/audio_service.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_carplay/flutter_carplay.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:just_audio/just_audio.dart';
import 'package:overlay_support/overlay_support.dart';
import 'package:radio_stream_player/radio_card.dart';
import 'ad_helper.dart';
import 'firebase_options.dart';

class RadioStations extends StatefulWidget {
  const RadioStations({super.key});

  @override
  State<RadioStations> createState() => _RadioStationsState();
}

class _RadioStationsState extends State<RadioStations> {
  final player = AudioPlayer();
  dynamic currentlyPlaying;
  int adCounter = 0;
  InterstitialAd? interstitialAd;
  bool interstitialAdLoaded = false;
  bool nowPlaying = false;

  final CollectionReference _collectionRef =
      FirebaseFirestore.instance.collection('stations');
  List documentIDsList = [];
  List<dynamic> stationList = [];
  late Future<dynamic> stationData;
  int currentStation = 0;

  CPConnectionStatusTypes connectionStatus = CPConnectionStatusTypes.unknown;
  final FlutterCarplay _flutterCarplay = FlutterCarplay();

  Future<List> getFirestoreStations() async {
    try {
      await Firebase.initializeApp(
          options: DefaultFirebaseOptions.currentPlatform);
      QuerySnapshot querySnapshot =
          await _collectionRef.orderBy("name", descending: true).get();
      stationList = querySnapshot.docs.map((doc) => doc.data()).toList();
      documentIDsList = querySnapshot.docs.map((doc) => doc.id).toList();
      return stationList;
    } catch (e, s) {
      debugPrint("Error fetching Firebase data: $e");
      debugPrint("Stack trace: $s");
      return [];
    }
  }

  Future<void> loadCarPlay(List<dynamic> stationList) async {
    FlutterCarplay.setRootTemplate(
      animated: true,
      rootTemplate: CPListTemplate(
        title: "Radio Cyprus",
        systemIcon: '',
        sections: [
          CPListSection(
            header: "Cyprus Radio Stations",
            items: stationList
                .map(
                  (station) => CPListItem(
                    image: 'assets/radio.png',
                    text: station['name'],
                    detailText: station['categories'].toString(),
                    onPress: (complete, self) {
                      setState(() {
                        currentlyPlaying = station;
                      });
                      checkStation();
                      complete();
                    },
                  ),
                )
                .toList(),
          ),
        ],
      ),
    );
    _flutterCarplay.forceUpdateRootTemplate();
  }

  Future<void> initApp() async {
    loadCarPlay(stationList);
  }

  void onCarplayConnectionChange(CPConnectionStatusTypes status) {
    // 车载连接状态变化时的处理逻辑
    setState(() async {
      connectionStatus = status;
      if (status == CPConnectionStatusTypes.connected) {
        await loadCarPlay(stationList);
      }
      showSimpleNotification(
        ListTile(
          leading: const Icon(Icons.directions_car),
          title: Text('Carplay Status: ${CPEnumUtils.stringFromEnum(status)}'),
        ),
        position: NotificationPosition.top,
        duration: const Duration(seconds: 3),
        slideDismissDirection: DismissDirection.up,
        background: Colors.blueGrey,
      );
    });
  }

  @override
  void initState() {
    stationData = getFirestoreStations();
    if (!kIsWeb) {
      loadInterstitialAd();
      if (Platform.isIOS) {
        WidgetsBinding.instance.addPostFrameCallback((_) => initApp());
        _flutterCarplay.addListenerOnConnectionChange(onCarplayConnectionChange);
        _flutterCarplay.forceUpdateRootTemplate();
      }
    }
    super.initState();
  }

  @override
  void dispose() {
    player.dispose();
    if (Platform.isIOS) {
      _flutterCarplay.removeListenerOnConnectionChange();
    }
    interstitialAd?.dispose();
    super.dispose();
  }

  void checkStation() {
    player.stop();
    stationList.asMap().forEach((index, items) {
      if (items == currentlyPlaying) {
        if (currentlyPlaying['isPlay'] == true) {
          setState(() {
            stationList[index]['isPlay'] = false;
            nowPlaying = false;
            player.pause();
          });
        } else {
          setState(() {
            stationList[index]['isPlay'] = true;
            nowPlaying = true;
          });
          player.setUrl(currentlyPlaying['url']).then((value) {
            player.play();
          });
        }
      } else {
        setState(() {
          stationList[index]['isPlay'] = false;
        });
      }
    });
  }
}

我自己也有个疑问:在radio_stations.dart里我直接用了AudioPlayer实例player控制播放,但同时在main.dart里又初始化了AudioHandler,会不会是这里的使用方式冲突了?比如应该统一通过audioHandler来管理播放逻辑,这样AudioService才能在应用被杀掉时正确处理停止音频的操作?

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 12:23:09