flutter 音乐播放器AudioPlayer使用

AudioPlayer 是flutter 的一个音乐播放器插件
插件地址 https://pub.dev/packages/audioplayers#-readme-tab-
测试demo效果图

image.png

初始化播放器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
 _initAudioPlayer(){
    //  /// Ideal for long media files or streams.
    mode =PlayerMode.MEDIA_PLAYER;
    //初始化
    _audioPlayer = AudioPlayer(mode: mode);

    _durationSubscription = _audioPlayer.onDurationChanged.listen((duration) {
      setState(() => _duration = duration);

      // TODO implemented for iOS, waiting for android impl
      if (Theme.of(context).platform == TargetPlatform.iOS) {
        // (Optional) listen for notification updates in the background
        _audioPlayer.startHeadlessService();

        // set at least title to see the notification bar on iOS.
        _audioPlayer.setNotification(
            title: 'App Name',
            artist: 'Artist or blank',
            albumTitle: 'Name or blank',
            imageUrl: 'url or blank',
            forwardSkipInterval: const Duration(seconds: 30), // default is 30s
            backwardSkipInterval: const Duration(seconds: 30), // default is 30s
            duration: duration,
            elapsedTime: Duration(seconds: 0));
      }
    });

    //监听进度
    _positionSubscription =
        _audioPlayer.onAudioPositionChanged.listen((p) => setState(() {
          _position = p;
        }));

    //播放完成
    _playerCompleteSubscription =
        _audioPlayer.onPlayerCompletion.listen((event) {
//          _onComplete();
          setState(() {
            _position = Duration();
          });
        });

    //监听报错
    _playerErrorSubscription = _audioPlayer.onPlayerError.listen((msg) {
      print('audioPlayer error : $msg');
      setState(() {
//        _playerState = PlayerState.stopped;
        _duration = Duration(seconds: 0);
        _position = Duration(seconds: 0);
      });
    });

    //播放状态改变
    _audioPlayer.onPlayerStateChanged.listen((state) {
      if (!mounted) return;
      setState(() {

      });
    });

    ///// iOS中来自通知区域的玩家状态变化流。
    _audioPlayer.onNotificationPlayerStateChanged.listen((state) {
      if (!mounted) return;
    });

//    _playingRouteState = PlayingRouteState.speakers;

  }

开始播放

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//开始播放
    void _play() async {
     final playPosition = (_position != null &&
         _duration != null &&
         _position.inMilliseconds > 0 &&
         _position.inMilliseconds < _duration.inMilliseconds)
         ? _position
         : null;
     final result = await _audioPlayer.play(url, position: playPosition);
     if (result == 1){
       print('succes');
     }

     // default playback rate is 1.0
     // this should be called after _audioPlayer.play() or _audioPlayer.resume()
     // this can also be called everytime the user wants to change playback rate in the UI
     _audioPlayer.setPlaybackRate(playbackRate: 1.0);

   }

暂停

1
2
3
4
5
6
    void _pause() async {
     final result = await _audioPlayer.pause();
     if (result == 1){
       print('succes');
     }
   }

停止播放

1
2
3
4
5
6
7
8
9
//停止播放
     _stop() async {
     final result = await _audioPlayer.stop();
     if (result == 1) {
       setState(() {
         _position = Duration();
       });
     }
   }

释放播放器

1
2
3
4
5
6
7
8
9
10
11
  @override
   void dispose() {
    //释放
     _audioPlayer.dispose();
     _durationSubscription?.cancel();
     _positionSubscription?.cancel();
     _playerCompleteSubscription?.cancel();
     _playerErrorSubscription?.cancel();
     _playerStateSubscription?.cancel();
     super.dispose();
   }

完整demo演示代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:audioplayers/audioplayers.dart';
class AudioPlaybackPage extends StatefulWidget {

  @override
  _AudioPlaybackPageState createState() => _AudioPlaybackPageState();
}

class _AudioPlaybackPageState extends State<AudioPlaybackPage> {

  String url;
  PlayerMode mode;

  AudioPlayer _audioPlayer;

  Duration _duration;
  Duration _position;
  StreamSubscription _durationSubscription;
  StreamSubscription _positionSubscription;
  StreamSubscription _playerCompleteSubscription;
  StreamSubscription _playerErrorSubscription;
  StreamSubscription _playerStateSubscription;

   get _durationText => _duration?.toString()?.split('.')?.first ?? '';
   get _positionText => _position?.toString()?.split('.')?.first ?? '';
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
      url = 'https://cdn.laitoon.com/audio/1561606091656-a510bda9a6ef0bcfd535253a283b102e.mp3?Expires=1591776008&OSSAccessKeyId=LTAI4Fikui9yCgsEVhzKa9Xe&Signature=ZIEc3pNLI2MD1o%2BgN9e0kGVnQDg%3D';
    _initAudioPlayer();
  }

   @override
   void dispose() {
    //释放
     _audioPlayer.dispose();
     _durationSubscription?.cancel();
     _positionSubscription?.cancel();
     _playerCompleteSubscription?.cancel();
     _playerErrorSubscription?.cancel();
     _playerStateSubscription?.cancel();
     super.dispose();
   }


   _initAudioPlayer(){
    //  /// Ideal for long media files or streams.
    mode =PlayerMode.MEDIA_PLAYER;
    //初始化
    _audioPlayer = AudioPlayer(mode: mode);

    _durationSubscription = _audioPlayer.onDurationChanged.listen((duration) {
      setState(() => _duration = duration);

      // TODO implemented for iOS, waiting for android impl
      if (Theme.of(context).platform == TargetPlatform.iOS) {
        // (Optional) listen for notification updates in the background
        _audioPlayer.startHeadlessService();

        // set at least title to see the notification bar on iOS.
        _audioPlayer.setNotification(
            title: 'App Name',
            artist: 'Artist or blank',
            albumTitle: 'Name or blank',
            imageUrl: 'url or blank',
            forwardSkipInterval: const Duration(seconds: 30), // default is 30s
            backwardSkipInterval: const Duration(seconds: 30), // default is 30s
            duration: duration,
            elapsedTime: Duration(seconds: 0));
      }
    });

    //监听进度
    _positionSubscription =
        _audioPlayer.onAudioPositionChanged.listen((p) => setState(() {
          _position = p;
        }));

    //播放完成
    _playerCompleteSubscription =
        _audioPlayer.onPlayerCompletion.listen((event) {
//          _onComplete();
          setState(() {
            _position = Duration();
          });
        });

    //监听报错
    _playerErrorSubscription = _audioPlayer.onPlayerError.listen((msg) {
      print('audioPlayer error : $msg');
      setState(() {
//        _playerState = PlayerState.stopped;
        _duration = Duration(seconds: 0);
        _position = Duration(seconds: 0);
      });
    });

    //播放状态改变
    _audioPlayer.onPlayerStateChanged.listen((state) {
      if (!mounted) return;
      setState(() {

      });
    });

    ///// iOS中来自通知区域的玩家状态变化流。
    _audioPlayer.onNotificationPlayerStateChanged.listen((state) {
      if (!mounted) return;
    });

//    _playingRouteState = PlayingRouteState.speakers;

  }

  //开始播放
    void _play() async {
     final playPosition = (_position != null &&
         _duration != null &&
         _position.inMilliseconds > 0 &&
         _position.inMilliseconds < _duration.inMilliseconds)
         ? _position
         : null;
     final result = await _audioPlayer.play(url, position: playPosition);
     if (result == 1){
       print('succes');
     }

     // default playback rate is 1.0
     // this should be called after _audioPlayer.play() or _audioPlayer.resume()
     // this can also be called everytime the user wants to change playback rate in the UI
     _audioPlayer.setPlaybackRate(playbackRate: 1.0);

   }

   //暂停
     void _pause() async {
     final result = await _audioPlayer.pause();
     if (result == 1){
       print('succes');
     }
   }

  //停止播放
     _stop() async {
     final result = await _audioPlayer.stop();
     if (result == 1) {
       setState(() {
         _position = Duration();
       });
     }
   }

   @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Column(
        children: <Widget>[

          Text(    _position != null
              ? '${_positionText ?? ''} / ${_durationText ?? ''}'
              : _duration != null ? _durationText : '',),
          Padding(
            padding: EdgeInsets.all(12.0),
            child: Stack(
              children: [
                Slider(
                  onChanged: (v) {
                    final Position = v * _duration.inMilliseconds;
                    _audioPlayer
                        .seek(Duration(milliseconds: Position.round()));
                  },
                  value: (_position != null &&
                      _duration != null &&
                      _position.inMilliseconds > 0 &&
                      _position.inMilliseconds < _duration.inMilliseconds)
                      ? _position.inMilliseconds / _duration.inMilliseconds
                      : 0.0,
                ),
              ],
            ),
          ),
          Row(
            children: <Widget>[

              IconButton(icon: Icon(Icons.play_arrow), onPressed: (){
                _play();
              }),
              IconButton(icon: Icon(Icons.pause), onPressed: (){
                _pause();
              }),
              IconButton(icon: Icon(Icons.stop), onPressed: (){
                _stop();
              }),
            ],
          )
        ],
      )
    );
  }
}