权限配置暂时到此,后台播放问题并入生命周期管理同步开发

This commit is contained in:
2026-08-20 22:07:59 +08:00
parent b2c7582ca7
commit f94cda4234
9 changed files with 787 additions and 364 deletions
+142 -37
View File
@@ -1,32 +1,59 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:media_kit/media_kit.dart';
//import 'package:audio_service/audio_service.dart' as audio_service;
import 'package:permission_handler/permission_handler.dart';
import 'services/audio_service.dart';
import 'services/playback_service.dart';
import 'services/app_lifecycle_service.dart';
import 'services/webdav_service.dart';
import 'services/audio_player_handler.dart';
import 'pages/home_page.dart';
import 'pages/player_page.dart';
import 'pages/playlist_page.dart';
import 'widgets/global_mini_player.dart';
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
// ⏱️ 全局计时器
final stopwatch = Stopwatch();
void main() {
// ⭐ 防止 Hot Restart / 热重载时重复初始化
bool _appInitialized = false;
// ⭐ 全局缓存 Handler
AudioPlayerHandler? _audioHandler;
void main() async {
// ⭐ P0:防止重复初始化
if (_appInitialized) {
debugPrint('⏱️ main 已初始化,跳过重复执行');
return;
}
_appInitialized = true;
stopwatch.start();
debugPrint('⏱️ T0 main: ${stopwatch.elapsedMilliseconds}ms');
WidgetsFlutterBinding.ensureInitialized();
debugPrint('⏱️ T0.5 ensureInitialized: ${stopwatch.elapsedMilliseconds}ms');
// ⭐ MediaKit 在 runApp 前初始化(官方要求)
try {
MediaKit.ensureInitialized();
debugPrint('⏱️ T0.6 MediaKit 初始化完成');
} catch (e) {
debugPrint('❌ MediaKit 初始化失败: $e');
}
// ⭐ 创建 HandlerAudioService 稍后初始化)
_audioHandler = AudioPlayerHandler();
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => AudioService()),
ChangeNotifierProvider(create: (_) => AppLifecycleService()),
Provider<AudioPlayerHandler>(create: (_) => _audioHandler!),
],
child: const QTPlayerApp(),
),
@@ -35,13 +62,15 @@ void main() {
debugPrint('⏱️ T0.8 runApp 完成: ${stopwatch.elapsedMilliseconds}ms');
}
// ════════════════════════════════════════════════════════════
// 路由管理器(控制 MiniPlayer 显示/隐藏)
// ════════════════════════════════════════════════════════════
class RouteManager extends ChangeNotifier {
static final RouteManager _instance = RouteManager._internal();
factory RouteManager() => _instance;
RouteManager._internal();
String _currentRoute = '/';
String get currentRoute => _currentRoute;
bool get showMiniPlayer =>
@@ -56,6 +85,9 @@ class RouteManager extends ChangeNotifier {
}
}
// ════════════════════════════════════════════════════════════
// 导航观察者(监听路由变化)
// ════════════════════════════════════════════════════════════
class MiniPlayerNavigatorObserver extends NavigatorObserver {
void _updateRoute(Route? route) {
final name = route?.settings.name ?? '/';
@@ -78,6 +110,9 @@ class MiniPlayerNavigatorObserver extends NavigatorObserver {
}
}
// ════════════════════════════════════════════════════════════
// 主应用
// ════════════════════════════════════════════════════════════
class QTPlayerApp extends StatefulWidget {
const QTPlayerApp({super.key});
@@ -86,21 +121,123 @@ class QTPlayerApp extends StatefulWidget {
}
class _QTPlayerAppState extends State<QTPlayerApp> {
bool _isInitializing = false;
// ============================================================
// 生命周期
// ============================================================
@override
void initState() {
super.initState();
debugPrint('⏱️ T1.5 initState: ${stopwatch.elapsedMilliseconds}ms');
WidgetsBinding.instance.addPostFrameCallback((_) {
debugPrint('⏱️ T2 首帧回调: ${stopwatch.elapsedMilliseconds}ms');
_initializeServices();
_startBackgroundInitialization();
});
}
@override
void dispose() {
super.dispose();
}
// ============================================================
// 后台初始化(不阻塞首帧)
// ============================================================
Future<void> _startBackgroundInitialization() async {
if (_isInitializing) return;
_isInitializing = true;
debugPrint('⏱️ T3 后台初始化开始');
// 1. PlaybackService(轻量级)
try {
PlaybackService().init();
debugPrint('⏱️ T3.1 PlaybackService 初始化完成');
} catch (e) {
debugPrint('❌ PlaybackService 初始化失败: $e');
}
// 2. ⭐ AudioService 暂时禁用(等 MainActivity 改为 AudioServiceActivity 后启用)
// await _initAudioService();
// 3. WebDAV
await _initWebDAV();
// 4. 通知权限
await _requestPermissions();
debugPrint('⏱️ T4 全部初始化完成');
}
// ════════════════════════════════════════════════════════════
// 子初始化方法
// ════════════════════════════════════════════════════════════
// ⭐ 暂时禁用,等 MainActivity 改为 AudioServiceActivity 后启用
// Future<void> _initAudioService() async {
// try {
// await audio_service.AudioService.init(
// builder: () => _audioHandler!,
// config: const audio_service.AudioServiceConfig(
// androidNotificationChannelId: 'com.example.qt_player.music',
// androidNotificationChannelName: '清听音乐播放',
// androidNotificationOngoing: true,
// androidStopForegroundOnPause: true,
// ),
// );
// debugPrint('✅ AudioService 初始化完成');
// } catch (e) {
// debugPrint('❌ AudioService 初始化失败: $e');
// }
// }
Future<void> _initWebDAV() async {
try {
final hasCred = await WebDAVService.instance.loadCredentials();
debugPrint('✅ WebDAV 加载完成, 已连接: $hasCred');
} catch (e) {
debugPrint('❌ WebDAV 加载失败: $e');
}
}
Future<void> _requestPermissions() async {
try {
if (await Permission.notification.isDenied) {
final status = await Permission.notification.request();
debugPrint('📢 通知权限状态: $status');
}
} catch (e) {
debugPrint('❌ 权限申请失败: $e');
}
}
// ============================================================
// Build
// ============================================================
@override
Widget build(BuildContext context) {
debugPrint('⏱️ T1 build: ${stopwatch.elapsedMilliseconds}ms');
// 监听歌曲变化,更新通知栏
final audioService = context.watch<AudioService>();
final handler = context.read<AudioPlayerHandler>();
final song = audioService.currentSong;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (song != null) {
handler.updateNotification(
id: song.id,
title: song.title,
artist: song.artist,
);
} else {
handler.mediaItem.add(null);
}
});
return MaterialApp(
title: '清听',
theme: ThemeData(
@@ -144,35 +281,3 @@ class _QTPlayerAppState extends State<QTPlayerApp> {
);
}
}
void _initializeServices() async {
debugPrint('⏱️ T3 开始初始化: ${stopwatch.elapsedMilliseconds}ms');
final lifecycle = AppLifecycleService();
try {
lifecycle.updateStatus(AppStatus.mediaKitInitializing);
MediaKit.ensureInitialized();
debugPrint('⏱️ T4 MediaKit 完成: ${stopwatch.elapsedMilliseconds}ms');
lifecycle.updateStatus(AppStatus.mediaKitReady);
lifecycle.updateStatus(AppStatus.playerInitializing);
PlaybackService().init();
debugPrint('⏱️ T5 Player 完成: ${stopwatch.elapsedMilliseconds}ms');
lifecycle.updateStatus(AppStatus.playerReady);
lifecycle.updateStatus(AppStatus.webdavChecking);
final hasCred = await WebDAVService.instance.loadCredentials();
debugPrint('⏱️ T6 WebDAV 完成: ${stopwatch.elapsedMilliseconds}ms');
if (hasCred) {
lifecycle.updateStatus(AppStatus.webdavReady);
} else {
lifecycle.updateStatus(AppStatus.webdavMissing);
}
lifecycle.updateStatus(AppStatus.fullReady);
debugPrint('✅ 应用完全就绪: ${stopwatch.elapsedMilliseconds}ms');
} catch (e) {
debugPrint('❌ 初始化错误: $e');
lifecycle.updateStatus(AppStatus.error);
}
}