Flutter音乐播放状态获取插件nowplaying的使用
Flutter音乐播放状态获取插件nowplaying的使用
nowplaying
是一个用于 iOS 和 Android 的 Flutter 插件,可以显示设备上当前正在播放的音频轨道的元数据。以下是如何在 Flutter 项目中使用 nowplaying
插件的详细步骤和示例代码。
安装
首先,在 pubspec.yaml
文件中添加 nowplaying
依赖:
dependencies:
nowplaying: ^3.0.3
iOS 设置
在 ios/Runner/Info.plist
中添加以下权限描述:
<key>NSAppleMusicUsageDescription</key>
<string>We need this to show you what's currently playing</string>
Android 设置
在 android/app/src/main/AndroidManifest.xml
中添加通知监听服务配置:
<service android:name="com.gomes.nowplaying.NowPlayingListenerService"
android:label="NowPlayingListenerService"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
对于 Android 11 或更高版本,可能需要添加以下内容:
<manifest ...>
...
<queries>
<package android:name="com.example.store" />
<package android:name="com.example.services" />
</queries>
...
<application ...>
...
</manifest>
或者请求所有应用的访问权限:
<manifest ...>
...
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
...
<application ...>
...
</manifest>
使用
初始化
初始化 nowplaying
服务:
await NowPlaying.instance.start();
可以在任何地方执行此操作,包括在 runApp
命令之前。
权限
iOS 自动具有所需的权限,通过安装阶段添加的使用键获得。
Android 用户必须明确授予服务访问通知流的权限。可以通过实例的 isEnabled
方法测试是否已授予权限:
final bool isEnabled = await NowPlaying.instance.isEnabled();
if (!isEnabled) {
// 请求权限
}
提供了一个方便的方法来打开设置页面:
final bool hasShownPermissions = await NowPlaying.instance.requestPermissions();
如果需要强制显示设置页面:
if (!hasShownPermissions) {
final bool pleasePleasePlease = await Navigator.of(context).pushNamed('ExplainAgainReallyNicelyPage');
if (pleasePleasePlease) NowPlaying.instance.requestPermissions(force: true);
}
Spotify 接入
访问 Spotify 需要客户端 ID 和客户端密钥,可以从 Spotify Developer Dashboard 获取。将这些凭据传递给 NowPlaying
的 start
函数:
await NowPlaying.instance.start(
spotifyClientId: '<CLIENT ID>',
spotifyClientSecret: '<CLIENT SECRET>',
);
连接到 Spotify:
if (NowPlaying.spotify.isEnabled && NowPlaying.spotify.isUnconnected) {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => NowPlaying.spotify.signInPage(context)),
);
}
访问当前播放元数据
现在播放的元数据通过 NowPlayingTrack
对象的流传递,暴露为 NowPlaying.instance.stream
。可以像通常消费流一样消费它:
StreamProvider.value(
value: NowPlaying.instance.stream,
child: MaterialApp(
home: Scaffold(
body: Consumer<NowPlayingTrack>(
builder: (context, track, _) {
return Container(
// 显示轨道信息
);
}
)
)
)
)
NowPlayingTrack
对象包含以下字段:
String title;
String artist;
String album;
String genre;
Duration duration;
Duration progress; // 检查下面的说明
NowPlayingState state;
ImageProvider image;
ImageProvider icon;
String source;
其中 NowPlayingState
定义如下:
enum NowPlayingState {
playing, paused, stopped
}
示例 Demo
以下是一个完整的示例应用程序,展示如何使用 nowplaying
插件:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:nowplaying/nowplaying.dart';
import 'package:provider/provider.dart';
void main() async {
await NowPlaying.instance.start(
resolveImages: true,
spotifyClientId: 'xxxx',
spotifyClientSecret: 'xxxx',
);
runApp(NowPlayingExample());
}
class NowPlayingExample extends StatelessWidget {
const NowPlayingExample({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('NowPlaying example app')),
body: Center(child: NowPlayingTrackWidget()),
),
);
}
}
class NowPlayingTrackWidget extends StatefulWidget {
@override
_NowPlayingTrackState createState() => _NowPlayingTrackState();
}
class _NowPlayingTrackState extends State<NowPlayingTrackWidget> {
@override
void initState() {
super.initState();
NowPlaying.instance.isEnabled().then((isEnabled) async {
if (!isEnabled) {
final shown = await NowPlaying.instance.requestPermissions();
print('MANAGED TO SHOW PERMS PAGE: $shown');
}
if (NowPlaying.spotify.isEnabled && NowPlaying.spotify.isUnconnected) {
NowPlaying.spotify.signIn(context);
}
});
}
@override
Widget build(BuildContext context) {
return StreamProvider<NowPlayingTrack>.value(
initialData: NowPlayingTrack.loading,
value: NowPlaying.instance.stream,
child: Consumer<NowPlayingTrack>(
builder: (context, track, _) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (track.isStopped) Text('nothing playing'),
if (!track.isStopped) ...[
if (track.title != null) Text(track.title!.trim()),
if (track.artist != null) Text(track.artist!.trim()),
if (track.album != null) Text(track.album!.trim()),
Text(track.duration.truncToSecond.toShortString()),
TrackProgressIndicator(track),
Text(track.state.toString()),
Stack(
alignment: Alignment.center,
children: [
Container(
margin: const EdgeInsets.fromLTRB(8, 8, 8, 16),
width: 200,
height: 200,
alignment: Alignment.center,
color: Colors.grey,
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 350),
child: _imageFrom(track),
),
),
Positioned(bottom: 0, right: 0, child: _iconFrom(track)),
Positioned(
bottom: 0, left: 8, child: Text(track.source!.trim())),
],
),
]
],
);
},
),
);
}
Widget _imageFrom(NowPlayingTrack track) {
if (track.hasImage)
return Image(
key: Key(track.id),
image: track.image!,
width: 200,
height: 200,
fit: BoxFit.contain,
);
if (track.isResolvingImage) {
return SizedBox(
width: 50.0,
height: 50.0,
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.white)),
);
}
return Text('NO\nARTWORK\nFOUND',
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 24, color: Colors.white));
}
Widget _iconFrom(NowPlayingTrack track) {
if (track.hasIcon)
return Container(
padding: const EdgeInsets.all(6),
decoration: const BoxDecoration(
color: Colors.white,
boxShadow: [const BoxShadow(blurRadius: 5, color: Colors.black)],
shape: BoxShape.circle),
child: Image(
image: track.icon!,
width: 25,
height: 25,
fit: BoxFit.contain,
color: _fgColorFor(track),
colorBlendMode: BlendMode.srcIn,
),
);
return Container();
}
Color _fgColorFor(NowPlayingTrack track) {
switch (track.source) {
case "com.apple.music":
return Colors.blue;
case "com.hughesmedia.big_finish":
return Colors.red;
case "com.spotify.music":
return Colors.green;
default:
return Colors.purpleAccent;
}
}
}
class TrackProgressIndicator extends StatefulWidget {
final NowPlayingTrack track;
TrackProgressIndicator(this.track);
@override
_TrackProgressIndicatorState createState() => _TrackProgressIndicatorState();
}
class _TrackProgressIndicatorState extends State<TrackProgressIndicator> {
late Timer _timer;
@override
void initState() {
_timer = Timer.periodic(const Duration(seconds: 1), (_) => setState(() {}));
super.initState();
}
@override
void dispose() {
_timer.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
final progress = widget.track.progress.truncToSecond;
final countdown =
widget.track.duration - progress + const Duration(seconds: 1);
return Column(
children: [
Text(progress.toShortString()),
Text(countdown.toShortString()),
],
);
}
}
extension DurationExtension on Duration {
Duration get truncToSecond {
final ms = this.inMilliseconds;
return Duration(milliseconds: ms - ms % 1000);
}
String toShortString() => toString().split(".").first;
}
以上是 nowplaying
插件的基本使用方法和完整示例代码。通过这个插件,您可以轻松地在 Flutter 应用中获取和显示当前正在播放的音乐信息。
更多关于Flutter音乐播放状态获取插件nowplaying的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter音乐播放状态获取插件nowplaying的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中使用nowplaying
插件来获取音乐播放状态的代码案例。这个插件通常用于与iOS和Android上的媒体会话(Media Session)进行交互,以获取当前播放的音乐信息。
首先,确保你已经在pubspec.yaml
文件中添加了nowplaying
依赖:
dependencies:
flutter:
sdk: flutter
nowplaying: ^最新版本号 # 替换为实际最新版本号
然后,运行flutter pub get
来安装依赖。
接下来,在你的Flutter项目中,你可以按照以下步骤使用nowplaying
插件来获取音乐播放状态。
1. 导入插件
在你的Dart文件中导入nowplaying
插件:
import 'package:nowplaying/nowplaying.dart';
2. 请求权限并监听播放状态
在你的主应用逻辑中,你可以请求必要的权限并开始监听媒体播放状态。以下是一个基本的示例:
import 'package:flutter/material.dart';
import 'package:nowplaying/nowplaying.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
NowPlaying? _nowPlaying;
String _playbackState = 'Unknown';
@override
void initState() {
super.initState();
// 初始化NowPlaying实例
_nowPlaying = NowPlaying();
// 请求权限(仅iOS需要)
_nowPlaying?.requestAuthorization().then((_) {
// 开始监听播放状态变化
_nowPlaying?.playerInfoStream.listen((playerInfo) {
setState(() {
// 更新播放状态
if (playerInfo != null) {
_playbackState = playerInfo.playbackState.toString();
} else {
_playbackState = 'No media info available';
}
});
});
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Music Playback State'),
),
body: Center(
child: Text('Playback State: $_playbackState'),
),
),
);
}
@override
void dispose() {
// 停止监听
_nowPlaying?.playerInfoStream.cancel();
super.dispose();
}
}
3. 注意事项
- iOS权限:在iOS上,你需要在
Info.plist
中添加适当的权限请求,例如NSAppleMusicUsageDescription
,如果你的应用需要访问Apple Music的信息。 - Android权限:在Android上,通常不需要额外的权限,但你需要确保你的应用具有适当的上下文来处理媒体会话。
- 错误处理:在实际应用中,添加适当的错误处理逻辑,以处理权限请求失败或流监听中的其他问题。
4. 运行应用
现在,你可以运行你的Flutter应用,并观察当媒体(如音乐)在设备上播放时,应用界面上显示的播放状态是如何变化的。
这个代码案例提供了一个基本的框架,展示了如何使用nowplaying
插件来获取当前的媒体播放状态。你可以根据需要进一步扩展和自定义这个示例。