Flutter audio_service 插件不播放音频

时间:2021-03-18 10:04:56

标签: flutter dart

AudioService.play(); 抛出错误:

java.lang.NullPointerException: Attempt to invoke virtual method 'void io.flutter.plugin.common.MethodChannel.invokeMethod(java.lang.String, java.lang.Object, io.flutter.plugin.common.MethodChannel$Result)' on a null object reference, null, null, null)

调试停止:

Debug stop

 onPressed: () async {
            if (playing) {
              // AudioService.pause();
            } else {
              AudioService.play();
            }
          },

background_audio.dart

import 'package:audio_service/audio_service.dart';
import 'package:just_audio/just_audio.dart';
import 'package:neodiom/api/_queue.dart' as player;
import 'package:neodiom/models/_Track.dart';

// Must be a top-level function
// void _entrypoint() => AudioServiceBackground.run(() => AudioPlayerTask());

class AudioPlayerTask extends BackgroundAudioTask {
  // the Audio player works fine itself and the problem is not related to it
  final _player = player.queue.player; // just_audio player

  // Implement callbacks here. e.g. onStart, onStop, onPlay, onPause
  onPlay() => _player.play();
  onPause() => _player.pause();
  onSeekTo(Duration duration) => _player.seek(duration);
  onSetSpeed(double speed) => _player.setSpeed(speed);

  onStop() async {
    // Stop and dispose of the player.
    await _player.dispose();
    // Shut down the background task.
    await super.onStop();
  }

  onStart(Map<String, dynamic> params) async {
    print(" **** Starting AudioPlayerTask ...");
    // Tell the UI and media notification what we're playing.
    Track t = player.Samples.tracks[0];
    MediaItem m =
        MediaItem(id: t.getTrack, album: t.album['title'], title: t.title);
    AudioServiceBackground.setMediaItem(m);
    _player.currentIndexStream.listen((index) {
      AudioServiceBackground.setMediaItem(player.queue.currentTrackMediaItem);
    });

    // Listen to state changes on the player...
    _player.playerStateStream.listen((playerState) {
      // ... and forward them to all audio_service clients.
      AudioServiceBackground.setState(
        playing: playerState.playing,
        // Every state from the audio player gets mapped onto an audio_service state.
        processingState: {
          ProcessingState.loading: AudioProcessingState.connecting,
          ProcessingState.buffering: AudioProcessingState.buffering,
          ProcessingState.ready: AudioProcessingState.ready,
          ProcessingState.completed: AudioProcessingState.completed,
        }[playerState.processingState],
        // Tell clients what buttons/controls should be enabled in the
        // current state.
        controls: [
          playerState.playing ? MediaControl.pause : MediaControl.play,
          MediaControl.stop,
        ],
      );
    });
  }
}

entrypoint

void _entrypoint() => AudioServiceBackground.run(() => AudioPlayerTask());

main.dart / Service initializer (during App initState)

 void initBackgroundAudioService() async {
    try {
      await AudioService.connect();
      await AudioService.start(
        backgroundTaskEntrypoint: _entrypoint,
        androidNotificationChannelName: 'Audio Service Demo',
        // Enable this if you want the Android service to exit the foreground state on pause.
        //androidStopForegroundOnPause: true,
        androidNotificationColor: 0xFF2196f3,
        androidNotificationIcon: 'mipmap/ic_launcher',
        androidEnableQueue: true,
      );
    } catch (e) {
      print("** Error on start : $e");
    }
  }

1 个答案:

答案 0 :(得分:1)

我只需要根据 Android setup instruction 中的以下配方遵循操作系统设置(在我的情况下为 documentation

<块引用>
  1. 编辑您项目的 AndroidManifest.xml 文件以声明创建唤醒锁的权限,并为 <service><receiver> 添加组件条目:
<manifest ...>
  <uses-permission android:name="android.permission.WAKE_LOCK"/>
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
  
  <application ...>
    
    ...
    
    <service android:name="com.ryanheise.audioservice.AudioService">
      <intent-filter>
        <action android:name="android.media.browse.MediaBrowserService" />
      </intent-filter>
    </service>

    <receiver android:name="com.ryanheise.audioservice.MediaButtonReceiver" >
      <intent-filter>
        <action android:name="android.intent.action.MEDIA_BUTTON" />
      </intent-filter>
    </receiver> 
  </application>
</manifest>
<块引用>
  1. 从 Flutter 1.12 开始,你需要在你的 android/app/build.gradle 文件中禁用 shrinkResources 设置,否则 Android 通知中使用的图标资源将在构建过程中被移除:
android {
    compileSdkVersion 28

    ...

    buildTypes {
        release {
            signingConfig ...
            shrinkResources false // ADD THIS LINE
        }
    }
}