Flutter实现Spotify当前播放歌曲展示应用:认证问题求助
Flutter实现Spotify认证及获取当前播放歌曲
一、添加依赖
使用spotify包处理Spotify API交互,webview_flutter处理OAuth网页授权。在pubspec.yaml中添加:
dependencies: flutter: sdk: flutter spotify: ^0.9.0 webview_flutter: ^4.4.0
执行flutter pub get安装依赖。
二、配置Spotify开发者平台回调URL
在Spotify开发者后台找到你的应用,设置Redirect URI为自定义scheme,比如myapp://spotify-auth,后续代码和平台配置要保持一致。
三、实现OAuth认证与核心功能
1. 授权WebView页面
用于加载Spotify授权页并捕获回调中的授权码:
import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; class SpotifyAuthWebView extends StatefulWidget { final String authUrl; final Function(String) onAuthCodeReceived; const SpotifyAuthWebView({ super.key, required this.authUrl, required this.onAuthCodeReceived, }); @override State<SpotifyAuthWebView> createState() => _SpotifyAuthWebViewState(); } class _SpotifyAuthWebViewState extends State<SpotifyAuthWebView> { late final WebViewController controller; @override void initState() { super.initState(); controller = WebViewController() ..loadRequest(Uri.parse(widget.authUrl)) ..setNavigationDelegate( NavigationDelegate( onNavigationRequest: (request) { if (request.url.startsWith('myapp://spotify-auth')) { final uri = Uri.parse(request.url); final code = uri.queryParameters['code']; if (code != null) { widget.onAuthCodeReceived(code); Navigator.pop(context); } return NavigationDecision.prevent; } return NavigationDecision.navigate; }, ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Spotify授权')), body: WebViewWidget(controller: controller), ); } }
2. 主页面实现认证与播放状态获取
替换代码中的YOUR_CLIENT_ID和YOUR_CLIENT_SECRET为你在Spotify平台获取的真实值:
import 'package:flutter/material.dart'; import 'package:spotify/spotify.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Spotify当前播放', home: const CurrentTrackPage(), ); } } class CurrentTrackPage extends StatefulWidget { const CurrentTrackPage({super.key}); @override State<CurrentTrackPage> createState() => _CurrentTrackPageState(); } class _CurrentTrackPageState extends State<CurrentTrackPage> { SpotifyApi? spotifyApi; Track? currentTrack; bool isLoading = false; final String clientId = 'YOUR_CLIENT_ID'; final String clientSecret = 'YOUR_CLIENT_SECRET'; final String redirectUri = 'myapp://spotify-auth'; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('当前播放歌曲')), body: Center( child: isLoading ? const CircularProgressIndicator() : spotifyApi == null ? ElevatedButton( onPressed: _initAuth, child: const Text('登录Spotify'), ) : currentTrack != null ? Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( currentTrack!.name, style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), const SizedBox(height: 8), Text('歌手: ${currentTrack!.artists!.first.name}'), const SizedBox(height: 16), ElevatedButton( onPressed: _fetchCurrentTrack, child: const Text('刷新当前播放'), ), ], ) : const Text('暂无播放歌曲'), ), ); } void _initAuth() async { final credentials = SpotifyApiCredentials(clientId, clientSecret); final grant = SpotifyApi.authorizationCodeGrant(credentials); // 请求获取当前播放状态的权限 final authUrl = grant.getAuthorizationUrl( Uri.parse(redirectUri), scopes: [Scopes.userReadCurrentlyPlaying], ); await Navigator.push( context, MaterialPageRoute( builder: (context) => SpotifyAuthWebView( authUrl: authUrl.toString(), onAuthCodeReceived: (code) async { setState(() => isLoading = true); final token = await grant.handleAuthorizationResponse( Uri.parse('$redirectUri?code=$code'), ); spotifyApi = SpotifyApi.fromToken(token); await _fetchCurrentTrack(); setState(() => isLoading = false); }, ), ), ); } Future<void> _fetchCurrentTrack() async { try { final currentPlayback = await spotifyApi!.me.currentlyPlaying(); setState(() { currentTrack = currentPlayback?.item as Track?; }); } catch (e) { setState(() => currentTrack = null); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('获取失败: $e')), ); } } }
四、配置平台Scheme
Android
在android/app/src/main/AndroidManifest.xml的<activity>标签内添加:
<intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="myapp" /> </intent-filter>
iOS
在ios/Runner/Info.plist中添加:
<key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>myapp</string> </array> </dict> </array>
五、注意事项
- 确保授权时请求了
user-read-currently-playing权限,否则无法获取当前播放状态 - 测试时需使用正在播放歌曲的Spotify账号登录
- 不要将Client Secret暴露在客户端代码中,正式环境建议通过后端代理处理认证流程
内容的提问来源于stack exchange,提问作者Ajay Kumar
相关产品推荐
相关产品推荐

