【问题标题】:Why onDurationChanged is not called in Flutter ios?为什么在 Flutter ios 中不调用 onDurationChanged?
【发布时间】:2022-12-08 21:45:01
【问题描述】:

我正在使用 audioplayers: 1.1.0 库从 url 播放音频

我使用 onDurationChanged 方法来获取音频文件的长度。这在 android 上运行完美,但在 iOSonDurationChanged 没有被调用。 我尝试了互联网上所有可用的解决方案。正如预期的那样,注意会有所帮助。你的帮助将拯救我的一天。

注意:如果我使用

 player.play(UrlSource('theme_01.mp3')); 

现在工作正常。但是如果我使用

 player.play(UrlSource('https://www.kozco.com/tech/LRMonoPhase4.mp3');

onDurationChanged 不工作

import 'package:flutter/material.dart';
import 'package:audioplayers/audioplayers.dart';
import 'dart:async';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Audio Player'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final player = AudioPlayer();
  bool isPlaying = false;
  Duration duration = Duration.zero;
  Duration position = Duration.zero;

  String formatTime(int seconds) {
    return '${(Duration(seconds: seconds))}'.split('.')[0].padLeft(8, '0');
  }

  final AudioContext audioContext = AudioContext(
    iOS: AudioContextIOS(
      defaultToSpeaker: true,
      category: AVAudioSessionCategory.ambient,
      options: [
        AVAudioSessionOptions.defaultToSpeaker,
        AVAudioSessionOptions.mixWithOthers,
      ],
    ),
    android: AudioContextAndroid(
      isSpeakerphoneOn: true,
      stayAwake: true,
      contentType: AndroidContentType.sonification,
      usageType: AndroidUsageType.assistanceSonification,
      audioFocus: AndroidAudioFocus.none,
    ),
  );

  @override
  void initState() {
    super.initState();
    AudioPlayer.global.setGlobalAudioContext(audioContext);

    player.onPlayerStateChanged.listen((state) {
      setState(() {
        isPlaying = state == PlayerState.playing;
      });
    });

    player.onDurationChanged.listen((newDuration) {
      setState(() {
        duration = newDuration;
      });
    });

    player.onPositionChanged.listen((newPosition) {
      setState(() {
        position = newPosition;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Slider(
              min: 0,
              max: duration.inSeconds.toDouble(),
              value: position.inSeconds.toDouble(),
              onChanged: (value) {
                final position = Duration(seconds: value.toInt());
                player.seek(position);
                player.resume();
              },
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                CircleAvatar(
                  radius: 25,
                  child: IconButton(
                    icon: Icon(
                      isPlaying ? Icons.pause : Icons.play_arrow,
                    ),
                    onPressed: () {
                      if (isPlaying) {
                        player.pause();
                      } else {
                         // player.play(UrlSource('theme_01.mp3'));
// If I use local audio works fine. But If I use the below audio url onDurationChanged is not called.

                        player.play(UrlSource('https://www.kozco.com/tech/LRMonoPhase4.mp3'));
                      }
                    },
                  ),
                ),
                SizedBox(
                  width: 20,
                ),
                CircleAvatar(
                  radius: 25,
                  child: IconButton(
                    icon: const Icon(Icons.stop),
                    onPressed: () {
                      player.stop();
                    },
                  ),
                ),
              ],
            ),
            Container(
              padding: const EdgeInsets.all(20),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Text(formatTime(position.inSeconds)),
                  Text(formatTime((duration - position).inSeconds)),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

【问题讨论】:

    标签: ios flutter dart audio audio-player


    【解决方案1】:

    如果在 iOS 上的 Flutter 应用程序中未调用 onDurationChanged 回调,这可能是因为您使用的 AudioPlayer 插件不支持 iOS 上的 onDurationChanged 回调.

    onDurationChanged 回调是 AudioPlayer 类的一个方法,只要正在播放的音频文件的持续时间发生变化,就会调用该方法。此回调在适用于 Android 的 AudioPlayer 插件上可用,但在 iOS 上不受支持。

    要解决此问题,您需要使用不同的方法来跟踪在 iOS 上播放的音频文件的持续时间。一种选择是使用 AudioPlayer 类的位置属性,它提供正在播放的音频文件的当前位置。您可以使用此属性来跟踪音频文件的持续时间并相应地更新您的应用程序。

    例如,您可以将以下代码添加到您的 Flutter 应用程序以跟踪 iOS 上音频文件的持续时间:

    import 'package:audioplayers/audioplayers.dart';
    
    final AudioPlayer _player = AudioPlayer();
    
    // Start playing the audio file
    _player.play('https://www.kozco.com/tech/LRMonoPhase4.mp3');
    
    // Track the duration of the audio file
    _player.onPlayerStateChanged.listen((state) {
      if (state == AudioPlayerState.PLAYING) {
        // Update the duration of the audio file
        final duration = _player.position.inSeconds;
      }
    });
    

    在此代码中,监听 AudioPlayer 类的 onPlayerStateChanged 流,并且位置属性用于在音频播放器处于 PLAYING 状态时跟踪音频文件的持续时间。这允许您在 iOS 上更新音频文件的持续时间,而无需使用不受支持的 onDurationChanged 回调。

    总体而言,如果在 iOS 上的 Flutter 应用程序中未调用 onDurationChanged 回调,则可能是因为 AudioPlayer 插件不支持在 iOS 上的此回调。要解决此问题,您可以使用不同的方法(例如 position 属性)来跟踪在 iOS 上播放的音频文件的持续时间。

    编辑:- 例如,您可以将以下代码添加到您的 Flutter 应用程序中以获取正在播放的音频文件的完整长度:

    import 'package:audioplayers/audioplayers.dart';
    
    final AudioPlayer _player = AudioPlayer();
    
    // Start playing the audio file
    _player.play('<audio_file_url>');
    
    // Get the full length of the audio file
    _player.onDurationChanged.listen((duration) {
      print('The full length of the audio file is $duration seconds.');
    });
    

    【讨论】:

    • 从你的回答中我只能得到当前的播放长度。但我想要完整的音频文件长度
    • 我怎样才能得到完整的音频文件长度
    • 获取音频文件的全长 player.onDurationChanged.listen((duration) { print('音频文件的全长为 $duration 秒。'); });
    • ? 这就是问题所在,兄弟,onDurationChanged 这没有被调用