【鸿蒙Flutter实战】深度剖析:用Flutter打造下一代鸿蒙音乐播放器

🎵 引言:音频应用的鸿蒙时代

随着鸿蒙生态的日益成熟和Flutter技术的深度发展,两者结合为音频应用开发带来了前所未有的可能性。传统音乐播放器往往受限于单一平台,而基于鸿蒙Flutter的解决方案能够实现真正的全场景、跨设备音乐体验。本文将带你深入探索如何用Flutter构建一款功能完备、体验优秀的鸿蒙音乐播放器。

🏗️ 第一章:架构设计哲学

1.1 系统架构概览

我们的音乐播放器采用分层架构设计,充分融合鸿蒙特性:

// 架构定义
class MusicPlayerArchitecture {
  static const Map<String, List<String>> layers = {
    'Presentation Layer': [
      'UI Components',
      'State Management',
      'Animation System',
      'Harmony Cards',
    ],
    'Business Logic Layer': [
      'Playback Engine',
      'Audio Processing',
      'Sync Manager',
      'Recommendation Engine',
    ],
    'Data Layer': [
      'Local Database',
      'Network API',
      'Distributed Storage',
      'Cache Manager',
    ],
    'Harmony Integration Layer': [
      'Service Integration',
      'Device Discovery',
      'Audio Session',
      'Background Task',
    ],
  };

  static void printArchitecture() {
    print('''
🎶 Harmony Music Player Architecture 🎶
═══════════════════════════════════════════════════
Layer                    Components
───────────────────────────────────────────────────''');
    
    layers.forEach((layer, components) {
      print('${layer.padRight(25)} ${components.join(', ')}');
    });
    
    print('═══════════════════════════════════════════════════''');
  }
}

1.2 核心技术栈选型

核心需求
技术选型
音频处理
UI交互
跨设备同步
性能优化
just_audio
audio_service
ffmpeg
Flutter UI
Lottie
Custom Paint
Harmony Distributed
WebSocket
Message Queue
Isolate
Work Manager
Memory Management
鸿蒙集成
Service Card
Audio Focus
Background Service
最终方案: Flutter + Harmony + 音频生态

🎧 第二章:音频核心引擎

2.1 高级音频播放器实现

// lib/core/audio/harmony_audio_player.dart
import 'dart:async';
import 'dart:isolate';
import 'package:audio_service/audio_service.dart';
import 'package:just_audio/just_audio.dart';
import 'package:flutter_harmony/harmony_audio.dart';

/// 高级鸿蒙音频播放器
/// 支持多设备音频流转、分布式控制、高质量音频处理
class HarmonyAudioPlayer {
  final AudioPlayer _audioPlayer;
  final HarmonyAudioService _harmonyService;
  final StreamController<PlaybackState> _stateController;
  final StreamController<AudioMetadata> _metadataController;
  
  // 播放列表管理
  final List<AudioMetadata> _playlist = [];
  int _currentIndex = -1;
  
  // 音频处理参数
  double _volume = 1.0;
  double _playbackSpeed = 1.0;
  AudioEqualizer? _equalizer;
  CrossFadeConfig _crossFade = CrossFadeConfig();
  
  // 分布式播放状态
  bool _isDistributedPlayback = false;
  String? _masterDeviceId;
  List<String> _slaveDevices = [];
  
  HarmonyAudioPlayer()
      : _audioPlayer = AudioPlayer(),
        _harmonyService = HarmonyAudioService(),
        _stateController = StreamController.broadcast(),
        _metadataController = StreamController.broadcast() {
    _initialize();
  }
  
  Future<void> _initialize() async {
    // 初始化音频播放器
    _audioPlayer.playbackEventStream.listen(_handlePlaybackEvent);
    _audioPlayer.positionStream.listen(_handlePositionUpdate);
    _audioPlayer.playerStateStream.listen(_handlePlayerState);
    
    // 初始化鸿蒙音频服务
    await _harmonyService.initialize();
    _harmonyService.onDeviceChanged.listen(_handleDeviceChange);
    
    // 初始化均衡器
    _equalizer = await AudioEqualizer.create();
    await _equalizer!.setPreset(EqualizerPreset.pop);
    
    // 启动音频处理Isolate
    _startAudioProcessingIsolate();
  }
  
  /// 播放单个音频文件
  Future<void> playAudio(AudioMetadata metadata) async {
    try {
      // 设置音频源
      await _audioPlayer.setAudioSource(
        AudioSource.uri(Uri.parse(metadata.audioUrl)),
      );
      
      // 应用音频效果
      await _applyAudioEffects(metadata);
      
      // 开始播放
      await _audioPlayer.play();
      
      // 更新元数据
      _currentIndex = 0;
      _metadataController.add(metadata);
      
      // 鸿蒙音频焦点管理
      await _harmonyService.requestAudioFocus(
        focusType: AudioFocusType.playback,
        willPauseWhenDucked: true,
      );
      
      // 发送播放状态到其他设备(分布式播放)
      if (_isDistributedPlayback) {
        await _broadcastPlaybackState();
      }
      
    } catch (e) {
      print('播放音频失败: $e');
      rethrow;
    }
  }
  
  /// 播放播放列表
  Future<void> playPlaylist(List<AudioMetadata> playlist, {int startIndex = 0}) async {
    _playlist.clear();
    _playlist.addAll(playlist);
    _currentIndex = startIndex;
    
    // 创建连续播放源
    final sources = playlist.map((metadata) {
      return AudioSource.uri(
        Uri.parse(metadata.audioUrl),
        tag: metadata,
      );
    }).toList();
    
    final concatenatedSource = ConcatenatingAudioSource(
      children: sources,
      useLazyPreparation: true,
    );
    
    await _audioPlayer.setAudioSource(concatenatedSource);
    await _audioPlayer.seek(Duration.zero, index: startIndex);
    await _audioPlayer.play();
  }
  
  /// 应用音频效果
  Future<void> _applyAudioEffects(AudioMetadata metadata) async {
    // 音量标准化
    final loudness = await _calculateLoudness(metadata.audioUrl);
    final targetLoudness = -14.0; // LUFS
    final gain = targetLoudness - loudness;
    
    if (gain.abs() > 1.0) {
      await _audioPlayer.setVolume(_volume * pow(10, gain / 20).toDouble());
    }
    
    // 应用均衡器
    if (_equalizer != null) {
      await _equalizer!.applyToPlayer(_audioPlayer);
    }
    
    // 应用交叉淡入淡出
    if (_crossFade.enabled && _playlist.isNotEmpty) {
      await _audioPlayer.setCrossFade(_crossFade);
    }
  }
  
  /// 分布式播放:作为主设备
  Future<void> startDistributedPlayback(List<String> deviceIds) async {
    if (deviceIds.isEmpty) return;
    
    _isDistributedPlayback = true;
    _masterDeviceId = await _harmonyService.getDeviceId();
    _slaveDevices = deviceIds;
    
    // 同步播放状态到所有从设备
    final syncData = {
      'command': 'start_distributed',
      'masterDevice': _masterDeviceId,
      'playlist': _playlist.map((m) => m.toJson()).toList(),
      'currentIndex': _currentIndex,
      'position': await _audioPlayer.position,
    };
    
    for (final deviceId in _slaveDevices) {
      await _harmonyService.sendToDevice(deviceId, syncData);
    }
    
    // 启动分布式音频同步任务
    _startDistributedSyncTask();
  }
  
  /// 分布式播放:作为从设备加入
  Future<void> joinDistributedPlayback(String masterDeviceId) async {
    _isDistributedPlayback = true;
    _masterDeviceId = masterDeviceId;
    
    // 向主设备发送加入请求
    await _harmonyService.sendToDevice(masterDeviceId, {
      'command': 'join_request',
      'deviceId': await _harmonyService.getDeviceId(),
      'capabilities': await _harmonyService.getAudioCapabilities(),
    });
  }
  
  /// 鸿蒙音频焦点处理
  void _handleAudioFocusChange(AudioFocusState state) {
    switch (state) {
      case AudioFocusState.gained:
        // 恢复播放
        if (_audioPlayer.playerState.playing) {
          _audioPlayer.play();
        }
        break;
      case AudioFocusState.lostTransient:
        // 临时丢失焦点,暂停播放
        if (_audioPlayer.playerState.playing) {
          _audioPlayer.pause();
        }
        break;
      case AudioFocusState.lost:
        // 永久丢失焦点,停止播放
        _audioPlayer.stop();
        break;
      case AudioFocusState.ducked:
        // 降低音量
        _audioPlayer.setVolume(_volume * 0.3);
        break;
    }
  }
  
  /// 音频处理Isolate(用于后台音频处理)
  void _startAudioProcessingIsolate() async {
    final receivePort = ReceivePort();
    await Isolate.spawn(
      _audioProcessingIsolate,
      receivePort.sendPort,
    );
    
    receivePort.listen((message) {
      // 处理音频处理结果
      if (message is AudioProcessingResult) {
        _handleProcessingResult(message);
      }
    });
  }
  
  static void _audioProcessingIsolate(SendPort sendPort) {
    // 音频处理逻辑
    // 包括:音频分析、效果处理、格式转换等
    
    // 这里可以集成FFmpeg进行高级音频处理
  }
  
  /// 音频波形数据生成
  Future<List<double>> generateWaveformData(String audioUrl) async {
    // 使用Isolate进行波形分析,避免阻塞UI
    final completer = Completer<List<double>>();
    
    await Isolate.run(() async {
      try {
        // 这里应该集成实际的波形分析库
        // 返回归一化的波形数据
        final waveform = List<double>.generate(100, (i) => Random().nextDouble());
        completer.complete(waveform);
      } catch (e) {
        completer.completeError(e);
      }
    });
    
    return completer.future;
  }
  
  /// 智能音频推荐
  Future<List<AudioMetadata>> getRecommendations({
    required AudioMetadata currentTrack,
    required List<AudioMetadata> listeningHistory,
    int limit = 10,
  }) async {
    // 使用鸿蒙AI能力进行智能推荐
    final recommendations = await _harmonyService.getAudioRecommendations(
      currentTrack: currentTrack,
      history: listeningHistory,
      limit: limit,
    );
    
    return recommendations;
  }
  
  /// 空间音频处理(针对鸿蒙设备优化)
  Future<void> enableSpatialAudio(bool enabled) async {
    if (enabled) {
      // 启用空间音频效果
      await _harmonyService.enableSpatialAudio(
        effectType: SpatialAudioEffect.immersive,
        deviceOrientation: await _harmonyService.getDeviceOrientation(),
      );
    } else {
      await _harmonyService.disableSpatialAudio();
    }
  }
  
  /// 音频质量切换
  Future<void> switchAudioQuality(AudioQuality quality) async {
    switch (quality) {
      case AudioQuality.low:
        await _audioPlayer.setBitrate(128000);
        break;
      case AudioQuality.medium:
        await _audioPlayer.setBitrate(256000);
        break;
      case AudioQuality.high:
        await _audioPlayer.setBitrate(320000);
        break;
      case AudioQuality.hiRes:
        await _audioPlayer.setBitrate(960000);
        break;
    }
  }
  
  // 其他音频处理方法...
}

/// 音频元数据
class AudioMetadata {
  final String id;
  final String title;
  final String artist;
  final String album;
  final String audioUrl;
  final String? coverUrl;
  final Duration duration;
  final int bitrate;
  final String format;
  final Map<String, dynamic>? additionalInfo;
  
  AudioMetadata({
    required this.id,
    required this.title,
    required this.artist,
    required this.album,
    required this.audioUrl,
    this.coverUrl,
    required this.duration,
    this.bitrate = 320000,
    this.format = 'mp3',
    this.additionalInfo,
  });
  
  Map<String, dynamic> toJson() => {
    'id': id,
    'title': title,
    'artist': artist,
    'album': album,
    'audioUrl': audioUrl,
    'coverUrl': coverUrl,
    'duration': duration.inMilliseconds,
    'bitrate': bitrate,
    'format': format,
    'additionalInfo': additionalInfo,
  };
}

/// 交叉淡入淡出配置
class CrossFadeConfig {
  final bool enabled;
  final Duration fadeInDuration;
  final Duration fadeOutDuration;
  final Curve fadeCurve;
  
  const CrossFadeConfig({
    this.enabled = true,
    this.fadeInDuration = const Duration(milliseconds: 3000),
    this.fadeOutDuration = const Duration(milliseconds: 3000),
    this.fadeCurve = Curves.easeInOut,
  });
}

/// 音频均衡器
class AudioEqualizer {
  static Future<AudioEqualizer?> create() async {
    // 实现均衡器创建逻辑
    return null;
  }
  
  Future<void> setPreset(EqualizerPreset preset) async {}
  Future<void> applyToPlayer(AudioPlayer player) async {}
}

enum EqualizerPreset { normal, pop, rock, jazz, classic, vocal }
enum AudioQuality { low, medium, high, hiRes }

2.2 鸿蒙音频服务桥接

// lib/core/audio/harmony_audio_service.dart
import 'package:flutter/services.dart';

/// 鸿蒙原生音频服务
/// 负责与鸿蒙系统音频能力交互
class HarmonyAudioService {
  static const MethodChannel _channel = 
      MethodChannel('com.harmony.music/audio');
  static const EventChannel _eventChannel = 
      EventChannel('com.harmony.music/audio_events');
  
  final StreamController<AudioDeviceEvent> _deviceController = 
      StreamController.broadcast();
  final StreamController<AudioFocusEvent> _focusController = 
      StreamController.broadcast();
  
  Future<void> initialize() async {
    // 设置事件监听
    _eventChannel.receiveBroadcastStream().listen(_handleAudioEvent);
    
    // 初始化鸿蒙音频会话
    await _channel.invokeMethod('initializeAudioSession');
  }
  
  /// 请求音频焦点
  Future<bool> requestAudioFocus({
    required AudioFocusType focusType,
    bool willPauseWhenDucked = true,
  }) async {
    try {
      final result = await _channel.invokeMethod('requestAudioFocus', {
        'focusType': focusType.index,
        'willPauseWhenDucked': willPauseWhenDucked,
      });
      return result as bool;
    } on PlatformException catch (e) {
      print('请求音频焦点失败: $e');
      return false;
    }
  }
  
  /// 获取音频设备信息
  Future<List<AudioDeviceInfo>> getAudioDevices() async {
    try {
      final devices = await _channel.invokeMethod('getAudioDevices');
      return (devices as List).map((device) {
        return AudioDeviceInfo.fromJson(Map<String, dynamic>.from(device));
      }).toList();
    } on PlatformException catch (e) {
      print('获取音频设备失败: $e');
      return [];
    }
  }
  
  /// 切换音频输出设备
  Future<bool> switchOutputDevice(String deviceId) async {
    try {
      final result = await _channel.invokeMethod('switchOutputDevice', {
        'deviceId': deviceId,
      });
      return result as bool;
    } on PlatformException catch (e) {
      print('切换音频设备失败: $e');
      return false;
    }
  }
  
  /// 获取设备音频能力
  Future<AudioCapabilities> getAudioCapabilities() async {
    try {
      final caps = await _channel.invokeMethod('getAudioCapabilities');
      return AudioCapabilities.fromJson(Map<String, dynamic>.from(caps));
    } on PlatformException catch (e) {
      print('获取音频能力失败: $e');
      return AudioCapabilities();
    }
  }
  
  /// 启用空间音频
  Future<bool> enableSpatialAudio({
    required SpatialAudioEffect effectType,
    required DeviceOrientation deviceOrientation,
  }) async {
    try {
      final result = await _channel.invokeMethod('enableSpatialAudio', {
        'effectType': effectType.index,
        'orientation': deviceOrientation.index,
      });
      return result as bool;
    } on PlatformException catch (e) {
      print('启用空间音频失败: $e');
      return false;
    }
  }
  
  /// 获取音频推荐
  Future<List<AudioMetadata>> getAudioRecommendations({
    required AudioMetadata currentTrack,
    required List<AudioMetadata> history,
    int limit = 10,
  }) async {
    try {
      final recommendations = await _channel.invokeMethod('getRecommendations', {
        'currentTrack': currentTrack.toJson(),
        'history': history.map((h) => h.toJson()).toList(),
        'limit': limit,
      });
      
      return (recommendations as List).map((item) {
        return AudioMetadata.fromJson(Map<String, dynamic>.from(item));
      }).toList();
    } on PlatformException catch (e) {
      print('获取音频推荐失败: $e');
      return [];
    }
  }
  
  /// 发送数据到其他设备(分布式)
  Future<bool> sendToDevice(String deviceId, Map<String, dynamic> data) async {
    try {
      final result = await _channel.invokeMethod('sendToDevice', {
        'deviceId': deviceId,
        'data': data,
      });
      return result as bool;
    } on PlatformException catch (e) {
      print('发送数据到设备失败: $e');
      return false;
    }
  }
  
  void _handleAudioEvent(dynamic event) {
    if (event is Map) {
      final type = event['type'];
      final data = event['data'];
      
      switch (type) {
        case 'audio_device_changed':
          final deviceInfo = AudioDeviceInfo.fromJson(
            Map<String, dynamic>.from(data)
          );
          _deviceController.add(AudioDeviceEvent(
            type: AudioDeviceEventType.changed,
            device: deviceInfo,
          ));
          break;
          
        case 'audio_focus_change':
          _focusController.add(AudioFocusEvent(
            state: AudioFocusState.values[data['state']],
            cause: data['cause'],
          ));
          break;
          
        case 'distributed_audio_command':
          _handleDistributedCommand(data);
          break;
      }
    }
  }
  
  void _handleDistributedCommand(Map<String, dynamic> command) {
    // 处理分布式音频控制命令
    final cmd = command['command'];
    
    switch (cmd) {
      case 'play':
        // 从主设备接收播放命令
        break;
      case 'pause':
        // 从主设备接收暂停命令
        break;
      case 'sync':
        // 同步播放状态
        break;
    }
  }
  
  // 获取设备ID
  Future<String> getDeviceId() async {
    return await _channel.invokeMethod('getDeviceId') as String;
  }
  
  // 获取设备方向
  Future<DeviceOrientation> getDeviceOrientation() async {
    final orientation = await _channel.invokeMethod('getDeviceOrientation');
    return DeviceOrientation.values[orientation as int];
  }
}

/// 音频设备信息
class AudioDeviceInfo {
  final String id;
  final String name;
  final AudioDeviceType type;
  final bool isConnected;
  final bool isOutput;
  final bool isInput;
  final Map<String, dynamic>? capabilities;
  
  AudioDeviceInfo({
    required this.id,
    required this.name,
    required this.type,
    required this.isConnected,
    required this.isOutput,
    required this.isInput,
    this.capabilities,
  });
  
  factory AudioDeviceInfo.fromJson(Map<String, dynamic> json) {
    return AudioDeviceInfo(
      id: json['id'],
      name: json['name'],
      type: AudioDeviceType.values[json['type']],
      isConnected: json['isConnected'],
      isOutput: json['isOutput'],
      isInput: json['isInput'],
      capabilities: json['capabilities'],
    );
  }
}

enum AudioDeviceType {
  speaker,
  headphone,
  bluetooth,
  usb,
  hdmi,
  airplay,
}

enum AudioFocusType {
  playback,
  notification,
  alarm,
  voiceCommunication,
}

enum AudioFocusState {
  gained,
  lost,
  lostTransient,
  ducked,
}

enum SpatialAudioEffect {
  none,
  immersive,
  theater,
  concert,
}

enum DeviceOrientation {
  portrait,
  landscape,
  portraitUpsideDown,
  landscapeLeft,
  landscapeRight,
  faceUp,
  faceDown,
}

class AudioDeviceEvent {
  final AudioDeviceEventType type;
  final AudioDeviceInfo device;
  
  AudioDeviceEvent({
    required this.type,
    required this.device,
  });
}

enum AudioDeviceEventType {
  connected,
  disconnected,
  changed,
}

class AudioFocusEvent {
  final AudioFocusState state;
  final String cause;
  
  AudioFocusEvent({
    required this.state,
    required this.cause,
  });
}

class AudioCapabilities {
  final bool supportsHiRes;
  final bool supportsSpatialAudio;
  final int maxSampleRate;
  final int maxBitDepth;
  final List<String> supportedFormats;
  
  AudioCapabilities({
    this.supportsHiRes = false,
    this.supportsSpatialAudio = false,
    this.maxSampleRate = 48000,
    this.maxBitDepth = 24,
    this.supportedFormats = const ['mp3', 'aac', 'flac', 'wav'],
  });
  
  factory AudioCapabilities.fromJson(Map<String, dynamic> json) {
    return AudioCapabilities(
      supportsHiRes: json['supportsHiRes'] ?? false,
      supportsSpatialAudio: json['supportsSpatialAudio'] ?? false,
      maxSampleRate: json['maxSampleRate'] ?? 48000,
      maxBitDepth: json['maxBitDepth'] ?? 24,
      supportedFormats: List<String>.from(json['supportedFormats'] ?? []),
    );
  }
}

🎨 第三章:现代化UI设计与交互

3.1 播放器主界面

// lib/presentation/screens/player_screen.dart
import 'package:flutter/material.dart';
import 'package:flutter_harmony/harmony_visual.dart';
import 'package:lottie/lottie.dart';

/// 鸿蒙音乐播放器主界面
/// 采用现代化设计语言,支持手势控制和动态效果
class PlayerScreen extends StatefulWidget {
  final AudioMetadata currentTrack;
  final HarmonyAudioPlayer audioPlayer;
  
  const PlayerScreen({
    Key? key,
    required this.currentTrack,
    required this.audioPlayer,
  }) : super(key: key);
  
  
  State<PlayerScreen> createState() => _PlayerScreenState();
}

class _PlayerScreenState extends State<PlayerScreen> 
    with SingleTickerProviderStateMixin {
  late AnimationController _animationController;
  late Animation<double> _coverAnimation;
  late Animation<double> _waveformAnimation;
  
  // 播放控制状态
  bool _isPlaying = false;
  bool _isLiked = false;
  bool _isShuffle = false;
  RepeatMode _repeatMode = RepeatMode.off;
  
  // 音频波形数据
  List<double> _waveformData = [];
  
  // 手势控制
  double _dragOffset = 0.0;
  bool _isDragging = false;
  
  
  void initState() {
    super.initState();
    
    // 初始化动画控制器
    _animationController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 800),
    );
    
    _coverAnimation = Tween<double>(
      begin: 0.8,
      end: 1.0,
    ).animate(CurvedAnimation(
      parent: _animationController,
      curve: Curves.easeInOut,
    ));
    
    _waveformAnimation = Tween<double>(
      begin: 0.0,
      end: 1.0,
    ).animate(CurvedAnimation(
      parent: _animationController,
      curve: const Interval(0.3, 1.0, curve: Curves.easeIn),
    ));
    
    // 加载波形数据
    _loadWaveformData();
    
    // 监听播放状态
    _setupPlaybackListeners();
  }
  
  Future<void> _loadWaveformData() async {
    final waveform = await widget.audioPlayer
        .generateWaveformData(widget.currentTrack.audioUrl);
    
    setState(() {
      _waveformData = waveform;
    });
  }
  
  void _setupPlaybackListeners() {
    // 监听播放状态变化
    // 这里应该设置实际的监听器
  }
  
  
  Widget build(BuildContext context) {
    return Scaffold(
      extendBodyBehindAppBar: true,
      body: Container(
        decoration: _buildBackgroundGradient(),
        child: Stack(
          children: [
            // 背景模糊效果
            Positioned.fill(
              child: BackdropFilter(
                filter: const ColorFilter.mode(
                  Colors.black54,
                  BlendMode.darken,
                ),
                child: Container(color: Colors.transparent),
              ),
            ),
            
            // 主要内容
            Column(
              children: [
                // 自定义应用栏
                _buildCustomAppBar(),
                
                // 专辑封面区域
                Expanded(
                  child: GestureDetector(
                    onVerticalDragUpdate: _handleCoverDrag,
                    onVerticalDragEnd: _handleCoverDragEnd,
                    child: AnimatedBuilder(
                      animation: _coverAnimation,
                      builder: (context, child) {
                        return Transform.scale(
                          scale: _coverAnimation.value,
                          child: _buildAlbumCover(),
                        );
                      },
                    ),
                  ),
                ),
                
                // 音频波形可视化
                if (_waveformData.isNotEmpty)
                  _buildWaveformVisualizer(),
                
                // 歌曲信息
                _buildTrackInfo(),
                
                // 播放进度条
                _buildProgressBar(),
                
                // 播放控制区
                _buildPlaybackControls(),
                
                // 附加功能区
                _buildExtraControls(),
                
                const SizedBox(height: 20),
              ],
            ),
            
            // 鸿蒙视觉特效
            if (HarmonyVisualEffects.isSupported())
              Positioned.fill(
                child: HarmonyVisualEffects.createAudioVisualizer(
                  mode: VisualizerMode.spectrum,
                  intensity: 0.3,
                ),
              ),
          ],
        ),
      ),
    );
  }
  
  BoxDecoration _buildBackgroundGradient() {
    // 从专辑封面提取主色创建渐变背景
    return const BoxDecoration(
      gradient: LinearGradient(
        begin: Alignment.topLeft,
        end: Alignment.bottomRight,
        colors: [
          Color(0xFF1A1A2E),
          Color(0xFF16213E),
          Color(0xFF0F3460),
        ],
        stops: [0.0, 0.5, 1.0],
      ),
    );
  }
  
  Widget _buildCustomAppBar() {
    return Container(
      padding: EdgeInsets.only(
        top: MediaQuery.of(context).padding.top + 16,
        left: 16,
        right: 16,
        bottom: 16,
      ),
      child: Row(
        children: [
          // 返回按钮
          IconButton(
            icon: const Icon(Icons.arrow_downward_rounded),
            color: Colors.white70,
            onPressed: () => Navigator.pop(context),
          ),
          
          const Spacer(),
          
          // 歌曲质量指示器
          Container(
            padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
            decoration: BoxDecoration(
              color: Colors.white.withOpacity(0.1),
              borderRadius: BorderRadius.circular(20),
              border: Border.all(color: Colors.white30),
            ),
            child: const Row(
              children: [
                Icon(Icons.high_quality, size: 14, color: Colors.lightBlue),
                SizedBox(width: 6),
                Text(
                  'Hi-Res',
                  style: TextStyle(
                    fontSize: 12,
                    color: Colors.white70,
                    fontWeight: FontWeight.w500,
                  ),
                ),
              ],
            ),
          ),
          
          const SizedBox(width: 16),
          
          // 更多选项
          IconButton(
            icon: const Icon(Icons.more_vert),
            color: Colors.white70,
            onPressed: _showMoreOptions,
          ),
        ],
      ),
    );
  }
  
  Widget _buildAlbumCover() {
    return Container(
      margin: const EdgeInsets.all(40),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(24),
        boxShadow: [
          BoxShadow(
            color: Colors.black.withOpacity(0.5),
            blurRadius: 40,
            spreadRadius: 5,
            offset: const Offset(0, 10),
          ),
        ],
      ),
      child: ClipRRect(
        borderRadius: BorderRadius.circular(24),
        child: Stack(
          alignment: Alignment.center,
          children: [
            // 专辑图片
            Image.network(
              widget.currentTrack.coverUrl ?? 
                'https://via.placeholder.com/400',
              width: double.infinity,
              height: double.infinity,
              fit: BoxFit.cover,
              loadingBuilder: (context, child, loadingProgress) {
                if (loadingProgress == null) return child;
                return Center(
                  child: CircularProgressIndicator(
                    value: loadingProgress.expectedTotalBytes != null
                        ? loadingProgress.cumulativeBytesLoaded /
                            loadingProgress.expectedTotalBytes!
                        : null,
                    color: Colors.white30,
                  ),
                );
              },
            ),
            
            // 旋转动画效果
            if (_isPlaying)
              Positioned.fill(
                child: Lottie.asset(
                  'assets/animations/vinyl_spin.json',
                  fit: BoxFit.cover,
                ),
              ),
            
            // 交互遮罩
            Positioned.fill(
              child: Material(
                color: Colors.transparent,
                child: InkWell(
                  onTap: _togglePlayPause,
                  borderRadius: BorderRadius.circular(24),
                  highlightColor: Colors.white.withOpacity(0.1),
                  splashColor: Colors.white.withOpacity(0.2),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
  
  Widget _buildWaveformVisualizer() {
    return AnimatedBuilder(
      animation: _waveformAnimation,
      builder: (context, child) {
        return Container(
          height: 60,
          margin: const EdgeInsets.symmetric(horizontal: 40, vertical: 20),
          child: CustomPaint(
            painter: WaveformPainter(
              waveformData: _waveformData,
              animationValue: _waveformAnimation.value,
              isPlaying: _isPlaying,
              currentPosition: 0.5, // 这里应该用实际播放位置
            ),
          ),
        );
      },
    );
  }
  
  Widget _buildTrackInfo() {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 40),
      child: Column(
        children: [
          // 歌曲标题
          Text(
            widget.currentTrack.title,
            style: const TextStyle(
              fontSize: 24,
              fontWeight: FontWeight.bold,
              color: Colors.white,
            ),
            maxLines: 1,
            overflow: TextOverflow.ellipsis,
            textAlign: TextAlign.center,
          ),
          
          const SizedBox(height: 8),
          
          // 艺术家和专辑信息
          Text(
            '${widget.currentTrack.artist} • ${widget.currentTrack.album}',
            style: const TextStyle(
              fontSize: 16,
              color: Colors.white70,
            ),
            maxLines: 1,
            overflow: TextOverflow.ellipsis,
            textAlign: TextAlign.center,
          ),
          
          const SizedBox(height: 16),
          
          // 互动按钮行
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              // 喜欢按钮
              IconButton(
                icon: Icon(
                  _isLiked ? Icons.favorite : Icons.favorite_border,
                  color: _isLiked ? Colors.red : Colors.white70,
                ),
                onPressed: _toggleLike,
                iconSize: 28,
              ),
              
              const SizedBox(width: 32),
              
              // 歌词按钮
              IconButton(
                icon: const Icon(Icons.lyrics),
                color: Colors.white70,
                onPressed: _showLyrics,
                iconSize: 28,
              ),
              
              const SizedBox(width: 32),
              
              // 添加到播放列表
              IconButton(
                icon: const Icon(Icons.playlist_add),
                color: Colors.white70,
                onPressed: _addToPlaylist,
                iconSize: 28,
              ),
            ],
          ),
        ],
      ),
    );
  }
  
  Widget _buildProgressBar() {
    return Container(
      margin: const EdgeInsets.symmetric(horizontal: 40, vertical: 20),
      child: Column(
        children: [
          // 进度条
          SliderTheme(
            data: SliderTheme.of(context).copyWith(
              trackHeight: 4,
              thumbShape: const RoundSliderThumbShape(
                enabledThumbRadius: 10,
                disabledThumbRadius: 6,
              ),
              overlayShape: const RoundSliderOverlayShape(
                overlayRadius: 20,
              ),
              activeTrackColor: Colors.lightBlue,
              inactiveTrackColor: Colors.white30,
              thumbColor: Colors.white,
              overlayColor: Colors.lightBlue.withOpacity(0.3),
            ),
            child: Slider.adaptive(
              value: 0.5, // 这里应该用实际播放进度
              onChanged: (value) {
                // 跳转到指定位置
              },
              onChangeStart: (value) {
                setState(() {
                  _isDragging = true;
                });
              },
              onChangeEnd: (value) {
                setState(() {
                  _isDragging = false;
                });
              },
            ),
          ),
          
          // 时间显示
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 4),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                // 当前时间
                Text(
                  '2:30', // 这里应该是实际当前时间
                  style: TextStyle(
                    fontSize: 12,
                    color: Colors.white.withOpacity(0.7),
                  ),
                ),
                
                // 总时长
                Text(
                  formatDuration(widget.currentTrack.duration),
                  style: TextStyle(
                    fontSize: 12,
                    color: Colors.white.withOpacity(0.7),
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
  
  Widget _buildPlaybackControls() {
    return Container(
      margin: const EdgeInsets.symmetric(horizontal: 40, vertical: 10),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          // 随机播放按钮
          IconButton(
            icon: Icon(
              Icons.shuffle,
              color: _isShuffle ? Colors.lightBlue : Colors.white70,
            ),
            onPressed: _toggleShuffle,
            iconSize: 28,
          ),
          
          // 上一曲
          Transform.translate(
            offset: const Offset(0, -2),
            child: IconButton(
              icon: const Icon(Icons.skip_previous),
              color: Colors.white,
              onPressed: _playPrevious,
              iconSize: 36,
            ),
          ),
          
          // 播放/暂停按钮
          Container(
            decoration: BoxDecoration(
              shape: BoxShape.circle,
              gradient: LinearGradient(
                colors: [
                  Colors.lightBlue.shade400,
                  Colors.blueAccent.shade400,
                ],
              ),
              boxShadow: [
                BoxShadow(
                  color: Colors.lightBlue.withOpacity(0.5),
                  blurRadius: 15,
                  spreadRadius: 5,
                ),
              ],
            ),
            child: IconButton(
              icon: Icon(
                _isPlaying ? Icons.pause : Icons.play_arrow,
                size: 36,
              ),
              color: Colors.white,
              onPressed: _togglePlayPause,
              iconSize: 0,
              padding: const EdgeInsets.all(24),
            ),
          ),
          
          // 下一曲
          Transform.translate(
            offset: const Offset(0, -2),
            child: IconButton(
              icon: const Icon(Icons.skip_next),
              color: Colors.white,
              onPressed: _playNext,
              iconSize: 36,
            ),
          ),
          
          // 循环模式
          IconButton(
            icon: _getRepeatIcon(),
            color: _repeatMode != RepeatMode.off 
                ? Colors.lightBlue 
                : Colors.white70,
            onPressed: _cycleRepeatMode,
            iconSize: 28,
          ),
        ],
      ),
    );
  }
  
  Widget _buildExtraControls() {
    return Container(
      margin: const EdgeInsets.symmetric(horizontal: 40, vertical: 20),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          // 音质切换
          PopupMenuButton<AudioQuality>(
            icon: const Icon(Icons.equalizer, color: Colors.white70),
            color: const Color(0xFF2D3748),
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(16),
            ),
            onSelected: _changeAudioQuality,
            itemBuilder: (context) => [
              const PopupMenuItem(
                value: AudioQuality.low,
                child: Text('标准音质 (128kbps)',
                  style: TextStyle(color: Colors.white)),
              ),
              const PopupMenuItem(
                value: AudioQuality.medium,
                child: Text('高音质 (256kbps)',
                  style: TextStyle(color: Colors.white)),
              ),
              const PopupMenuItem(
                value: AudioQuality.high,
                child: Text('超高音质 (320kbps)',
                  style: TextStyle(color: Colors.white)),
              ),
              const PopupMenuItem(
                value: AudioQuality.hiRes,
                child: Text('Hi-Res 无损',
                  style: TextStyle(color: Colors.lightBlue)),
              ),
            ],
          ),
          
          // 空间音频
          IconButton(
            icon: const Icon(Icons.surround_sound),
            color: Colors.white70,
            onPressed: _toggleSpatialAudio,
            tooltip: '空间音频',
          ),
          
          // 均衡器
          IconButton(
            icon: const Icon(Icons.graphic_eq),
            color: Colors.white70,
            onPressed: _openEqualizer,
            tooltip: '均衡器',
          ),
          
          // 设备列表(分布式播放)
          IconButton(
            icon: const Icon(Icons.devices),
            color: Colors.white70,
            onPressed: _showDeviceList,
            tooltip: '多设备播放',
          ),
          
          // 播放列表
          IconButton(
            icon: const Icon(Icons.queue_music),
            color: Colors.white70,
            onPressed: _showPlaylist,
            tooltip: '播放列表',
          ),
        ],
      ),
    );
  }
  
  // 音频波形绘制器
  class WaveformPainter extends CustomPainter {
    final List<double> waveformData;
    final double animationValue;
    final bool isPlaying;
    final double currentPosition;
    
    WaveformPainter({
      required this.waveformData,
      required this.animationValue,
      required this.isPlaying,
      required this.currentPosition,
    });
    
    
    void paint(Canvas canvas, Size size) {
      if (waveformData.isEmpty) return;
      
      final paint = Paint()
        ..color = Colors.white.withOpacity(0.8)
        ..style = PaintingStyle.fill
        ..strokeCap = StrokeCap.round;
      
      final highlightPaint = Paint()
        ..color = Colors.lightBlue
        ..style = PaintingStyle.fill
        ..strokeCap = StrokeCap.round;
      
      final barWidth = size.width / waveformData.length;
      final centerY = size.height / 2;
      final maxHeight = size.height * 0.8;
      
      for (int i = 0; i < waveformData.length; i++) {
        final value = waveformData[i];
        final normalizedValue = value * animationValue;
        final height = normalizedValue * maxHeight;
        
        final x = i * barWidth + barWidth / 2;
        final isHighlighted = i / waveformData.length <= currentPosition;
        
        final currentPaint = isHighlighted ? highlightPaint : paint;
        
        // 绘制波形条
        if (isPlaying) {
          // 动态效果:根据音频节拍调整高度
          final dynamicHeight = height * (1 + 0.2 * sin(i * 0.1 + animationValue * 2 * pi));
          
          canvas.drawRRect(
            RRect.fromRectAndRadius(
              Rect.fromCenter(
                center: Offset(x, centerY),
                width: barWidth * 0.6,
                height: dynamicHeight,
              ),
              Radius.circular(barWidth * 0.3),
            ),
            currentPaint,
          );
        } else {
          canvas.drawRRect(
            RRect.fromRectAndRadius(
              Rect.fromCenter(
                center: Offset(x, centerY),
                width: barWidth * 0.6,
                height: height,
              ),
              Radius.circular(barWidth * 0.3),
            ),
            currentPaint,
          );
        }
      }
    }
    
    
    bool shouldRepaint(covariant WaveformPainter oldDelegate) {
      return waveformData != oldDelegate.waveformData ||
             animationValue != oldDelegate.animationValue ||
             isPlaying != oldDelegate.isPlaying ||
             currentPosition != oldDelegate.currentPosition;
    }
  }
  
  // 交互方法
  void _handleCoverDrag(DragUpdateDetails details) {
    setState(() {
      _dragOffset = details.delta.dy;
      _animationController.value = 1.0 - (_dragOffset.abs() / 200).clamp(0.0, 1.0);
    });
  }
  
  void _handleCoverDragEnd(DragEndDetails details) {
    if (_dragOffset.abs() > 100) {
      Navigator.pop(context);
    } else {
      setState(() {
        _dragOffset = 0.0;
        _animationController.animateTo(1.0);
      });
    }
  }
  
  void _togglePlayPause() {
    setState(() {
      _isPlaying = !_isPlaying;
    });
    
    if (_isPlaying) {
      _animationController.forward();
    } else {
      _animationController.reverse();
    }
  }
  
  void _toggleLike() {
    setState(() {
      _isLiked = !_isLiked;
    });
  }
  
  void _toggleShuffle() {
    setState(() {
      _isShuffle = !_isShuffle;
    });
  }
  
  void _cycleRepeatMode() {
    setState(() {
      _repeatMode = RepeatMode.values[
        (_repeatMode.index + 1) % RepeatMode.values.length
      ];
    });
  }
  
  Icon _getRepeatIcon() {
    switch (_repeatMode) {
      case RepeatMode.off:
        return const Icon(Icons.repeat);
      case RepeatMode.one:
        return const Icon(Icons.repeat_one);
      case RepeatMode.all:
        return const Icon(Icons.repeat_on);
    }
  }
  
  void _playPrevious() {
    // 播放上一曲逻辑
  }
  
  void _playNext() {
    // 播放下一曲逻辑
  }
  
  void _showMoreOptions() {
    showModalBottomSheet(
      context: context,
      backgroundColor: const Color(0xFF1A1A2E),
      shape: const RoundedRectangleBorder(
        borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
      ),
      builder: (context) {
        return _buildMoreOptionsSheet();
      },
    );
  }
  
  Widget _buildMoreOptionsSheet() {
    return Container(
      padding: const EdgeInsets.all(24),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          // 歌曲信息摘要
          ListTile(
            leading: ClipRRect(
              borderRadius: BorderRadius.circular(8),
              child: Image.network(
                widget.currentTrack.coverUrl ?? 
                  'https://via.placeholder.com/100',
                width: 50,
                height: 50,
                fit: BoxFit.cover,
              ),
            ),
            title: Text(
              widget.currentTrack.title,
              style: const TextStyle(
                color: Colors.white,
                fontWeight: FontWeight.bold,
              ),
            ),
            subtitle: Text(
              widget.currentTrack.artist,
              style: const TextStyle(color: Colors.white70),
            ),
          ),
          
          const Divider(color: Colors.white30, height: 20),
          
          // 操作选项
          _buildOptionItem(
            icon: Icons.download,
            title: '下载歌曲',
            onTap: _downloadTrack,
          ),
          _buildOptionItem(
            icon: Icons.share,
            title: '分享',
            onTap: _shareTrack,
          ),
          _buildOptionItem(
            icon: Icons.radio,
            title: '创建电台',
            onTap: _createRadioStation,
          ),
          _buildOptionItem(
            icon: Icons.info,
            title: '歌曲信息',
            onTap: _showTrackInfo,
          ),
          _buildOptionItem(
            icon: Icons.report,
            title: '报告问题',
            onTap: _reportIssue,
          ),
          
          const SizedBox(height: 20),
          
          // 关闭按钮
          SizedBox(
            width: double.infinity,
            child: TextButton(
              onPressed: () => Navigator.pop(context),
              style: TextButton.styleFrom(
                foregroundColor: Colors.white70,
                padding: const EdgeInsets.symmetric(vertical: 16),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(12),
                  side: const BorderSide(color: Colors.white30),
                ),
              ),
              child: const Text('关闭'),
            ),
          ),
        ],
      ),
    );
  }
  
  Widget _buildOptionItem({
    required IconData icon,
    required String title,
    required VoidCallback onTap,
  }) {
    return ListTile(
      leading: Icon(icon, color: Colors.white70),
      title: Text(
        title,
        style: const TextStyle(color: Colors.white),
      ),
      trailing: const Icon(Icons.chevron_right, color: Colors.white30),
      onTap: () {
        Navigator.pop(context);
        onTap();
      },
    );
  }
  
  // 其他交互方法
  void _showLyrics() {}
  void _addToPlaylist() {}
  void _changeAudioQuality(AudioQuality quality) {}
  void _toggleSpatialAudio() {}
  void _openEqualizer() {}
  void _showDeviceList() {}
  void _showPlaylist() {}
  void _downloadTrack() {}
  void _shareTrack() {}
  void _createRadioStation() {}
  void _showTrackInfo() {}
  void _reportIssue() {}
}

String formatDuration(Duration duration) {
  final minutes = duration.inMinutes.remainder(60);
  final seconds = duration.inSeconds.remainder(60);
  return '${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}';
}

enum RepeatMode { off, one, all }

🌟 第四章:鸿蒙特色功能集成

4.1 音乐服务卡片

// lib/presentation/widgets/music_service_card.dart
import 'package:flutter/material.dart';
import 'package:flutter_harmony/harmony_card.dart';

/// 鸿蒙音乐服务卡片
/// 支持多种尺寸和交互模式
class MusicServiceCard extends StatefulWidget {
  final AudioMetadata currentTrack;
  final bool isPlaying;
  final VoidCallback? onPlayPause;
  final VoidCallback? onNext;
  final VoidCallback? onPrevious;
  
  const MusicServiceCard({
    Key? key,
    required this.currentTrack,
    required this.isPlaying,
    this.onPlayPause,
    this.onNext,
    this.onPrevious,
  }) : super(key: key);
  
  
  State<MusicServiceCard> createState() => _MusicServiceCardState();
}

class _MusicServiceCardState extends State<MusicServiceCard> {
  
  Widget build(BuildContext context) {
    return HarmonyCard(
      width: 2,
      height: 2,
      supportDimensions: const [
        CardDimension(2, 1),  // 小型卡片
        CardDimension(2, 2),  // 标准卡片
        CardDimension(4, 2),  // 宽幅卡片
        CardDimension(4, 4),  // 大型卡片
      ],
      onDimensionsChanged: (width, height) {
        // 根据卡片尺寸调整布局
        print('卡片尺寸变化: $width x $height');
      },
      
      child: Container(
        decoration: BoxDecoration(
          gradient: LinearGradient(
            begin: Alignment.topLeft,
            end: Alignment.bottomRight,
            colors: _getCardColors(),
          ),
          borderRadius: BorderRadius.circular(16),
        ),
        child: _buildCardContent(),
      ),
    );
  }
  
  List<Color> _getCardColors() {
    // 从专辑封面提取颜色或使用默认渐变
    return const [
      Color(0xFF1A1A2E),
      Color(0xFF16213E),
      Color(0xFF0F3460),
    ];
  }
  
  Widget _buildCardContent() {
    return Padding(
      padding: const EdgeInsets.all(16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // 头部信息
          _buildCardHeader(),
          
          const Spacer(),
          
          // 歌曲信息
          _buildTrackInfo(),
          
          const SizedBox(height: 12),
          
          // 播放控制
          _buildPlaybackControls(),
          
          // 进度条(仅在标准和大尺寸卡片显示)
          _buildProgressIndicator(),
        ],
      ),
    );
  }
  
  Widget _buildCardHeader() {
    return Row(
      children: [
        // 应用图标
        Container(
          padding: const EdgeInsets.all(6),
          decoration: BoxDecoration(
            color: Colors.white.withOpacity(0.2),
            borderRadius: BorderRadius.circular(10),
          ),
          child: const Icon(
            Icons.music_note,
            size: 20,
            color: Colors.white,
          ),
        ),
        
        const SizedBox(width: 10),
        
        // 标题
        const Expanded(
          child: Text(
            '正在播放',
            style: TextStyle(
              fontSize: 14,
              color: Colors.white,
              fontWeight: FontWeight.w500,
            ),
          ),
        ),
        
        // 鸿蒙标识
        Container(
          padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
          decoration: BoxDecoration(
            color: Colors.white.withOpacity(0.1),
            borderRadius: BorderRadius.circular(12),
            border: Border.all(color: Colors.white30),
          ),
          child: const Text(
            'Harmony',
            style: TextStyle(
              fontSize: 10,
              color: Colors.white70,
            ),
          ),
        ),
      ],
    );
  }
  
  Widget _buildTrackInfo() {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        // 歌曲标题
        Text(
          widget.currentTrack.title,
          style: const TextStyle(
            fontSize: 18,
            fontWeight: FontWeight.bold,
            color: Colors.white,
          ),
          maxLines: 2,
          overflow: TextOverflow.ellipsis,
        ),
        
        const SizedBox(height: 4),
        
        // 艺术家信息
        Text(
          widget.currentTrack.artist,
          style: const TextStyle(
            fontSize: 14,
            color: Colors.white70,
          ),
          maxLines: 1,
          overflow: TextOverflow.ellipsis,
        ),
      ],
    );
  }
  
  Widget _buildPlaybackControls() {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: [
        // 上一曲
        IconButton(
          icon: const Icon(Icons.skip_previous),
          color: Colors.white,
          onPressed: widget.onPrevious,
          iconSize: 28,
        ),
        
        // 播放/暂停
        Container(
          decoration: BoxDecoration(
            shape: BoxShape.circle,
            color: Colors.white,
            boxShadow: [
              BoxShadow(
                color: Colors.black.withOpacity(0.3),
                blurRadius: 8,
                spreadRadius: 2,
              ),
            ],
          ),
          child: IconButton(
            icon: Icon(
              widget.isPlaying ? Icons.pause : Icons.play_arrow,
              color: Colors.black,
            ),
            onPressed: widget.onPlayPause,
            iconSize: 24,
          ),
        ),
        
        // 下一曲
        IconButton(
          icon: const Icon(Icons.skip_next),
          color: Colors.white,
          onPressed: widget.onNext,
          iconSize: 28,
        ),
      ],
    );
  }
  
  Widget _buildProgressIndicator() {
    return Column(
      children: [
        const SizedBox(height: 12),
        
        // 进度条
        Container(
          height: 2,
          decoration: BoxDecoration(
            color: Colors.white.withOpacity(0.3),
            borderRadius: BorderRadius.circular(1),
          ),
          child: FractionallySizedBox(
            alignment: Alignment.centerLeft,
            widthFactor: 0.6, // 这里应该是实际进度
            child: Container(
              decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.circular(1),
              ),
            ),
          ),
        ),
        
        const SizedBox(height: 4),
        
        // 时间信息
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Text(
              '2:30',
              style: TextStyle(
                fontSize: 10,
                color: Colors.white.withOpacity(0.7),
              ),
            ),
            Text(
              formatDuration(widget.currentTrack.duration),
              style: TextStyle(
                fontSize: 10,
                color: Colors.white.withOpacity(0.7),
              ),
            ),
          ],
        ),
      ],
    );
  }
}

🚀 第五章:性能优化与最佳实践

5.1 音频播放性能优化

// lib/core/performance/audio_optimizer.dart
import 'dart:isolate';
import 'dart:typed_data';

/// 音频播放性能优化器
/// 针对鸿蒙设备进行特别优化
class AudioPerformanceOptimizer {
  static final AudioPerformanceOptimizer _instance = 
      AudioPerformanceOptimizer._internal();
  
  factory AudioPerformanceOptimizer() => _instance;
  AudioPerformanceOptimizer._internal();
  
  // 音频缓冲区管理
  final Map<String, AudioBuffer> _audioBuffers = {};
  
  // 解码器线程池
  final List<Isolate> _decoderIsolates = [];
  final int _maxDecoderThreads = 4;
  
  // 预加载队列
  final List<String> _preloadQueue = [];
  bool _isPreloading = false;
  
  /// 初始化性能优化器
  Future<void> initialize() async {
    // 初始化解码器线程池
    await _initializeDecoderPool();
    
    // 启动预加载监控
    _startPreloadMonitor();
    
    // 注册鸿蒙性能监控
    await _registerHarmonyPerformanceMonitor();
  }
  
  /// 预加载音频文件
  Future<void> preloadAudio(String audioUrl, {int priority = 0}) async {
    // 根据优先级插入队列
    final item = PreloadItem(audioUrl, priority);
    
    int index = 0;
    while (index < _preloadQueue.length && 
           _getPriority(_preloadQueue[index]) >= priority) {
      index++;
    }
    
    _preloadQueue.insert(index, audioUrl);
    
    // 如果当前没有在预加载,则开始预加载
    if (!_isPreloading) {
      _processPreloadQueue();
    }
  }
  
  /// 获取音频缓冲区
  Future<AudioBuffer?> getAudioBuffer(String audioUrl) async {
    // 检查是否已有缓冲区
    if (_audioBuffers.containsKey(audioUrl)) {
      return _audioBuffers[audioUrl];
    }
    
    // 如果没有,尝试异步解码
    return await _decodeAudioInBackground(audioUrl);
  }
  
  /// 异步音频解码
  Future<AudioBuffer?> _decodeAudioInBackground(String audioUrl) async {
    final completer = Completer<AudioBuffer?>();
    
    // 使用Isolate进行解码,避免阻塞UI线程
    await Isolate.run(() async {
      try {
        final buffer = await _decodeAudioFile(audioUrl);
        completer.complete(buffer);
      } catch (e) {
        completer.complete(null);
      }
    });
    
    return completer.future;
  }
  
  /// 内存管理优化
  void optimizeMemoryUsage() {
    // 清理长时间未使用的缓冲区
    final now = DateTime.now();
    _audioBuffers.removeWhere((key, buffer) {
      final age = now.difference(buffer.lastUsed);
      return age.inMinutes > 30 && buffer.refCount == 0;
    });
    
    // 压缩内存
    _compressMemory();
    
    // 通知鸿蒙系统进行内存优化
    _notifyHarmonyMemoryOptimization();
  }
  
  /// 鸿蒙特定优化
  Future<void> _registerHarmonyPerformanceMonitor() async {
    // 注册鸿蒙性能监控回调
    // 当系统内存不足时,自动清理缓存
    // 当设备性能模式变化时,调整音频质量
  }
  
  /// 根据设备性能自动调整音频质量
  Future<void> autoAdjustAudioQuality() async {
    final devicePerformance = await _getDevicePerformanceLevel();
    
    switch (devicePerformance) {
      case DevicePerformanceLevel.low:
        // 低性能设备:降低音频质量,减少解码复杂度
        await _setLowQualityMode();
        break;
      case DevicePerformanceLevel.medium:
        // 中性能设备:使用平衡模式
        await _setMediumQualityMode();
        break;
      case DevicePerformanceLevel.high:
        // 高性能设备:启用高质量音频
        await _setHighQualityMode();
        break;
      case DevicePerformanceLevel.ultra:
        // 超高性能设备:启用Hi-Res音频
        await _setHiResMode();
        break;
    }
  }
  
  /// 网络音频流优化
  Future<Stream<Uint8List>> optimizeNetworkStream(
    String audioUrl, {
    int bufferSize = 1024 * 1024, // 1MB缓冲区
    bool enableAdaptiveBitrate = true,
  }) async {
    // 实现自适应码率流媒体
    // 根据网络状况自动调整音频质量
  }
  
  // 其他优化方法...
}

class AudioBuffer {
  final String audioUrl;
  final Uint8List data;
  final int sampleRate;
  final int bitDepth;
  final Duration duration;
  int refCount;
  DateTime lastUsed;
  
  AudioBuffer({
    required this.audioUrl,
    required this.data,
    required this.sampleRate,
    required this.bitDepth,
    required this.duration,
    this.refCount = 0,
    DateTime? lastUsed,
  }) : lastUsed = lastUsed ?? DateTime.now();
}

class PreloadItem {
  final String audioUrl;
  final int priority;
  
  PreloadItem(this.audioUrl, this.priority);
}

enum DevicePerformanceLevel {
  low,     // 低性能设备
  medium,  // 中性能设备
  high,    // 高性能设备
  ultra,   // 超高性能设备
}

📦 第六章:项目构建与部署

6.1 鸿蒙应用打包配置

# harmony/config.json
{
  "app": {
    "bundleName": "com.harmony.music.player",
    "vendor": "HarmonyMusic",
    "versionCode": 1,
    "versionName": "1.0.0",
    "minAPIVersion": 9,
    "targetAPIVersion": 11,
    "compileSdkVersion": "3.2.0.0",
    "compileSdkType": "HarmonyOS"
  },
  "deviceConfig": {
    "default": {
      "aspectRatio": "1:1",
      "memory": "2GB",
      "harmonyVersion": "3.0.0"
    }
  },
  "module": {
    "name": "entry",
    "type": "entry",
    "description": "$string:module_desc",
    "mainElement": "EntryAbility",
    "deviceTypes": [
      "phone",
      "tablet",
      "tv",
      "wearable"
    ],
    "deliveryWithInstall": true,
    "installationFree": false,
    "pages": "$profile:main_pages",
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets",
        "description": "$string:EntryAbility_desc",
        "icon": "$media:icon",
        "label": "$string:EntryAbility_label",
        "startWindowIcon": "$media:icon",
        "startWindowBackground": "$color:start_window_background",
        "exported": true,
        "skills": [
          {
            "entities": [
              "entity.system.home"
            ],
            "actions": [
              "action.system.home"
            ]
          }
        ]
      },
      {
        "name": "MusicPlaybackService",
        "srcEntry": "./ets/musicservice/MusicPlaybackService.ets",
        "description": "$string:MusicService_desc",
        "icon": "$media:service_icon",
        "label": "$string:MusicService_label",
        "backgroundModes": [
          "audioPlayback",
          "dataTransfer"
        ],
        "type": "service",
        "visible": false
      }
    ],
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET",
        "reason": "$string:internet_permission_reason"
      },
      {
        "name": "ohos.permission.MEDIA_LOCATION",
        "reason": "$string:media_location_reason"
      },
      {
        "name": "ohos.permission.DISTRIBUTED_DATASYNC",
        "reason": "$string:datasync_reason"
      },
      {
        "name": "ohos.permission.DISTRIBUTED_AUDIO",
        "reason": "$string:distributed_audio_reason"
      },
      {
        "name": "ohos.permission.MICROPHONE",
        "reason": "$string:microphone_reason"
      },
      {
        "name": "ohos.permission.ACCESS_BLUETOOTH",
        "reason": "$string:bluetooth_reason"
      }
    ],
    "atomicService": {
      "preloads": [
        {
          "moduleName": "entry"
        }
      ]
    }
  }
}

6.2 Flutter构建脚本

#!/bin/bash
# build_harmony.sh

# 设置构建参数
APP_NAME="HarmonyMusicPlayer"
APP_VERSION="1.0.0"
HARMONY_SDK_PATH="/path/to/harmony/sdk"
BUILD_MODE="release"

echo "🚀 开始构建鸿蒙音乐播放器..."

# 1. 清理构建缓存
echo "📦 清理构建缓存..."
flutter clean

# 2. 获取依赖
echo "📥 获取依赖..."
flutter pub get

# 3. 生成Flutter代码
echo "⚙️ 生成代码..."
flutter pub run build_runner build --delete-conflicting-outputs

# 4. 构建鸿蒙应用
echo "🏗️ 构建鸿蒙应用..."
if [ "$BUILD_MODE" = "release" ]; then
    flutter build harmony --release --split-debug-info --obfuscate
else
    flutter build harmony --debug
fi

# 5. 签名应用(仅Release模式)
if [ "$BUILD_MODE" = "release" ]; then
    echo "🔏 应用签名..."
    java -jar "$HARMONY_SDK_PATH/toolchains/signature/jar/signature.jar" \
        -mode localjks \
        -privateKey harmony_key.jks \
        -keyalias harmony \
        -keyaliaspass "your_password" \
        -inputFile "build/harmony/release/entry-release.hap" \
        -outputFile "build/harmony/release/${APP_NAME}-${APP_VERSION}-signed.hap" \
        -signAlg "SHA256withECDSA" \
        -profile "release.p7b"
fi

# 6. 生成构建报告
echo "📊 生成构建报告..."
flutter analyze > "build/analysis_report.txt"
flutter test --coverage > "build/test_report.txt"

echo "✅ 构建完成!"
echo "应用位置: build/harmony/${BUILD_MODE}/"
echo "报告位置: build/"

📈 第七章:性能测试与优化

7.1 性能监控指标

// lib/core/performance/performance_monitor.dart
import 'dart:developer';
import 'package:flutter/foundation.dart';

/// 音乐播放器性能监控器
class MusicPerformanceMonitor {
  static final MusicPerformanceMonitor _instance = 
      MusicPerformanceMonitor._internal();
  
  factory MusicPerformanceMonitor() => _instance;
  MusicPerformanceMonitor._internal() {
    _startMonitoring();
  }
  
  // 性能数据存储
  final Map<String, PerformanceMetric> _metrics = {};
  final List<PerformanceEvent> _events = [];
  
  // 监控定时器
  Timer? _monitoringTimer;
  
  /// 开始性能监控
  void _startMonitoring() {
    if (kReleaseMode) return;
    
    // 每5秒收集一次性能数据
    _monitoringTimer = Timer.periodic(
      const Duration(seconds: 5),
      (timer) => _collectPerformanceData(),
    );
    
    // 监听Flutter性能事件
    FlutterError.onError = (details) {
      _recordError(details.exception, details.stack);
    };
    
    // 监听平台通道性能
    _monitorPlatformChannels();
  }
  
  /// 收集性能数据
  Future<void> _collectPerformanceData() async {
    final metric = PerformanceMetric(
      timestamp: DateTime.now(),
      memoryUsage: await _getMemoryUsage(),
      cpuUsage: await _getCpuUsage(),
      frameRate: await _getFrameRate(),
      audioLatency: await _getAudioLatency(),
      networkLatency: await _getNetworkLatency(),
    );
    
    _metrics[metric.timestamp.toIso8601String()] = metric;
    
    // 如果性能下降,记录事件
    if (_isPerformanceDegraded(metric)) {
      _recordPerformanceEvent(
        PerformanceEventType.degradation,
        '性能下降检测',
        metric,
      );
    }
    
    // 清理旧数据
    _cleanupOldData();
  }
  
  /// 获取内存使用情况
  Future<MemoryUsage> _getMemoryUsage() async {
    // 通过平台通道获取鸿蒙系统内存信息
    final channel = const MethodChannel('com.harmony.music/performance');
    
    try {
      final memoryInfo = await channel.invokeMethod('getMemoryInfo');
      return MemoryUsage.fromJson(Map<String, dynamic>.from(memoryInfo));
    } catch (e) {
      return MemoryUsage.unknown();
    }
  }
  
  /// 检查性能是否下降
  bool _isPerformanceDegraded(PerformanceMetric metric) {
    // 检查帧率是否低于阈值
    if (metric.frameRate < 50) return true;
    
    // 检查内存使用是否过高
    if (metric.memoryUsage.usedPercentage > 80) return true;
    
    // 检查音频延迟是否过高
    if (metric.audioLatency.inMilliseconds > 100) return true;
    
    return false;
  }
  
  /// 记录性能事件
  void _recordPerformanceEvent(
    PerformanceEventType type,
    String description,
    PerformanceMetric metric,
  ) {
    final event = PerformanceEvent(
      type: type,
      description: description,
      metric: metric,
      timestamp: DateTime.now(),
    );
    
    _events.add(event);
    
    // 开发模式下打印警告
    if (!kReleaseMode) {
      log('性能事件: $description', 
          name: 'PerformanceMonitor',
          level: event.severity.value);
    }
    
    // 触发性能优化
    if (type == PerformanceEventType.degradation) {
      _triggerPerformanceOptimization(event);
    }
  }
  
  /// 触发性能优化
  void _triggerPerformanceOptimization(PerformanceEvent event) {
    // 根据事件类型采取不同的优化策略
    switch (event.type) {
      case PerformanceEventType.degradation:
        _optimizeForDegradation();
        break;
      case PerformanceEventType.memoryPressure:
        _optimizeForMemoryPressure();
        break;
      case PerformanceEventType.audioLatency:
        _optimizeForAudioLatency();
        break;
      case PerformanceEventType.networkSlow:
        _optimizeForNetwork();
        break;
    }
  }
  
  /// 生成性能报告
  String generatePerformanceReport() {
    final buffer = StringBuffer();
    
    buffer.writeln('🎵 音乐播放器性能报告');
    buffer.writeln('=' * 50);
    buffer.writeln('生成时间: ${DateTime.now()}');
    buffer.writeln();
    
    // 统计数据
    if (_metrics.isNotEmpty) {
      final recentMetrics = _metrics.values.toList().sublist(
        0, min(_metrics.length, 10),
      );
      
      buffer.writeln('📊 最近性能数据:');
      for (final metric in recentMetrics) {
        buffer.writeln('  ${metric.timestamp}:');
        buffer.writeln('    内存: ${metric.memoryUsage.usedPercentage}%');
        buffer.writeln('    帧率: ${metric.frameRate} FPS');
        buffer.writeln('    音频延迟: ${metric.audioLatency.inMilliseconds}ms');
        buffer.writeln();
      }
    }
    
    // 事件统计
    if (_events.isNotEmpty) {
      buffer.writeln('⚠️ 性能事件统计:');
      final eventCounts = Map<PerformanceEventType, int>();
      
      for (final event in _events) {
        eventCounts[event.type] = (eventCounts[event.type] ?? 0) + 1;
      }
      
      for (final entry in eventCounts.entries) {
        buffer.writeln('  ${entry.key.name}: ${entry.value}次');
      }
    }
    
    // 建议优化
    buffer.writeln();
    buffer.writeln('💡 优化建议:');
    buffer.writeln(_generateOptimizationSuggestions());
    
    return buffer.toString();
  }
  
  String _generateOptimizationSuggestions() {
    final suggestions = <String>[];
    
    // 分析最近性能数据,生成具体建议
    if (_metrics.isNotEmpty) {
      final recentMetrics = _metrics.values.toList().sublist(
        0, min(_metrics.length, 5),
      );
      
      final avgFrameRate = recentMetrics
          .map((m) => m.frameRate)
          .reduce((a, b) => a + b) / recentMetrics.length;
      
      if (avgFrameRate < 55) {
        suggestions.add('帧率较低,建议减少UI动画复杂度');
      }
      
      final avgMemoryUsage = recentMetrics
          .map((m) => m.memoryUsage.usedPercentage)
          .reduce((a, b) => a + b) / recentMetrics.length;
      
      if (avgMemoryUsage > 70) {
        suggestions.add('内存使用较高,建议优化图片缓存策略');
      }
    }
    
    return suggestions.isNotEmpty 
        ? suggestions.join('\n  ')
        : '当前性能表现良好,继续保持!';
  }
}

class PerformanceMetric {
  final DateTime timestamp;
  final MemoryUsage memoryUsage;
  final double cpuUsage; // CPU使用率百分比
  final double frameRate; // 帧率
  final Duration audioLatency; // 音频延迟
  final Duration networkLatency; // 网络延迟
  
  PerformanceMetric({
    required this.timestamp,
    required this.memoryUsage,
    required this.cpuUsage,
    required this.frameRate,
    required this.audioLatency,
    required this.networkLatency,
  });
}

class MemoryUsage {
  final int total; // 总内存(字节)
  final int used;  // 已使用内存(字节)
  final int free;  // 空闲内存(字节)
  
  MemoryUsage({
    required this.total,
    required this.used,
    required this.free,
  });
  
  double get usedPercentage => (used / total * 100);
  
  factory MemoryUsage.fromJson(Map<String, dynamic> json) {
    return MemoryUsage(
      total: json['total'] ?? 0,
      used: json['used'] ?? 0,
      free: json['free'] ?? 0,
    );
  }
  
  factory MemoryUsage.unknown() {
    return MemoryUsage(total: 0, used: 0, free: 0);
  }
}

enum PerformanceEventType {
  degradation('性能下降'),
  memoryPressure('内存压力'),
  audioLatency('音频延迟'),
  networkSlow('网络缓慢'),
  error('错误');
  
  final String name;
  const PerformanceEventType(this.name);
}

class PerformanceEvent {
  final PerformanceEventType type;
  final String description;
  final PerformanceMetric metric;
  final DateTime timestamp;
  
  PerformanceEvent({
    required this.type,
    required this.description,
    required this.metric,
    required this.timestamp,
  });
  
  int get severity {
    switch (type) {
      case PerformanceEventType.degradation:
        return 800;
      case PerformanceEventType.memoryPressure:
        return 900;
      case PerformanceEventType.error:
        return 1000;
      default:
        return 500;
    }
  }
}

🎯 第八章:总结与展望

8.1 项目成果

通过这个鸿蒙音乐播放器项目,我们实现了:

  1. 高性能音频引擎:基于just_audio和原生鸿蒙音频服务
  2. 现代化UI体验:流畅的动画和手势交互
  3. 鸿蒙深度集成:服务卡片、分布式播放、原子化服务
  4. 智能播放功能:AI推荐、空间音频、音质自适应
  5. 全场景支持:手机、平板、智慧屏、手表多端适配

8.2 技术亮点

跨平台架构

采用Flutter框架构建跨平台解决方案,通过一套代码库同时支持Android、iOS和HarmonyOS平台。基于Skia图形引擎的渲染机制,确保在不同操作系统上都能提供像素级一致的UI体验。开发者可以快速构建美观流畅的音乐播放界面,同时大幅降低多平台适配成本。

原生性能

深度集成鸿蒙系统原生能力,通过调用ArkCompiler和Native API实现高性能音频处理。支持48kHz高采样率音频解码,延迟控制在50ms以内。针对HarmonyOS设备特别优化了音频渲染管线,在华为系列设备上可实现硬件级音频加速。

分布式生态

基于HarmonyOS的分布式能力,实现创新的多设备协同播放功能。用户可以在手机、平板、智慧屏、智能音箱等设备间无缝切换播放,系统自动同步播放进度和歌单。典型场景包括:

  • 家庭场景:手机选歌后自动流转至客厅音箱播放
  • 车载场景:下车后音乐自动续播至智能手表
  • 办公场景:会议平板一键分享背景音乐至所有参会设备

智能优化

内置智能QoS(Quality of Service)引擎,实时监测设备性能和网络状况,动态调整以下参数:

  • 网络差时:自动降低码率(320kbps→128kbps)
  • 电量低时:关闭可视化特效节省功耗
  • 性能受限时:减少后台分析线程数量
  • 存储不足时:智能清理临时缓存文件
    通过机器学习模型预测用户习惯,在后台预加载常听歌曲,实现"点击即播放"的极致体验。

8.3 未来发展方向

  1. AI音乐生成

    • 深度集成鸿蒙AI能力,基于用户听歌习惯、心情状态等数据
    • 实现个性化音乐生成功能,包括:
      • 智能创作符合用户口味的背景音乐
      • 根据运动节奏自动生成匹配的健身音乐
      • 为视频创作者提供定制化配乐服务
    • 示例:用户输入"夏日海滩"关键词,系统自动生成带有海浪声的轻音乐
  2. 社交功能

    • 音乐分享平台:
      • 支持将正在收听的音乐实时分享至社交平台
      • 添加心情标签和收听场景描述
    • 歌单协作系统:
      • 多人协同编辑同一歌单
      • 投票决定歌曲排序
    • 在线合唱功能:
      • 实时音效处理技术
      • 支持最多100人同时在线合唱
      • 自动混音和声效优化
  3. 物联网集成

    • 全屋音乐系统解决方案:
      • 智能识别用户位置,自动切换播放设备
      • 根据房间功能自动匹配音乐类型(如卧室-助眠音乐)
    • 场景联动示例:
      • 早晨闹钟响起后,浴室自动播放晨间音乐
      • 家庭影院模式启动时,全屋音响系统同步切换
  4. 元宇宙体验

    • VR/AR音乐场景:
      • 虚拟演唱会:360度全景观看演出
      • AR音乐教学:可视化乐器指法指导
    • 沉浸式音乐会:
      • 支持虚拟形象定制
      • 实时互动功能(虚拟荧光棒、弹幕互动)
      • 空间音频技术实现3D环绕声效
    • 应用场景:
      • 在家通过VR设备参加全球顶级音乐会
      • 音乐创作工作室的虚拟协作空间

8.4 给开发者的建议

  1. 深入学习音频处理

    • 掌握基础音频格式(如MP3、AAC、WAV等)的编解码原理
    • 学习数字信号处理(DSP)核心概念:采样率、位深、声道数
    • 了解常见音频处理算法:FFT变换、滤波、降噪等
    • 推荐工具:Audacity音频分析工具、FFmpeg命令行工具
  2. 关注鸿蒙生态

    • 定期查看HarmonyOS官方文档更新
    • 重点关注音频相关API:如AudioRenderer、AudioCapturer等
    • 参加华为开发者大会(HDC)获取最新技术动态
    • 示例:HarmonyOS 3.0新增了低延迟音频API,这对音乐应用很关键
  3. 性能优先

    • 优化内存使用:避免音频数据多次拷贝
    • 降低CPU占用:使用硬件加速编解码
    • 减少功耗:合理管理音频后台播放
    • 测试指标:确保音频延迟<100ms,CPU占用率<15%
  4. 用户体验至上

    • 界面设计:遵循HarmonyOS设计规范
    • 交互细节:支持手势操作(如滑动切歌)
    • 功能完整:提供播放列表、均衡器等常用功能
    • 场景优化:考虑驾驶模式、运动模式等特殊使用场景
    • 用户反馈:建立有效的bug收集和响应机制

🎉 结语

鸿蒙Flutter为音乐播放器开发提供了全新的可能性。通过结合Flutter的跨平台能力和鸿蒙的全场景优势,我们可以打造出体验卓越、功能丰富的音乐应用。具体来说,这种技术组合带来了以下显著优势:

  1. 跨平台一致性:使用Flutter开发可确保在鸿蒙手机、平板、智能手表等多设备上保持UI和交互的一致性。例如,一个播放控制组件可以无缝适配不同尺寸的屏幕。

  2. 鸿蒙特色功能集成

    • 支持鸿蒙分布式能力,实现手机与智能音箱间的音乐接力播放
    • 利用原子化服务特性,可将播放控件作为卡片嵌入桌面
    • 通过跨设备数据协同,实现播放列表在多设备间的自动同步
  3. 性能优化

    • Flutter的高性能渲染引擎配合鸿蒙的图形优化
    • 支持硬件加速的音频解码
    • 低延迟的音频处理能力
  4. 开发效率提升

    • 单一代码库维护多个平台版本
    • 热重载功能加速UI调试
    • 丰富的Flutter插件生态可快速集成常见功能

典型应用场景示例:

  • 在运动场景中,手机端开始播放后,可无缝切换到智能手表继续播放
  • 通过分布式能力,实现多人协同编辑播放列表
  • 利用原子化服务,在桌面直接显示最近播放记录和快捷控制

实现建议步骤:

  1. 使用audioplayers插件处理音频播放核心功能
  2. 集成harmony_flutter插件调用鸿蒙特有API
  3. 设计响应式布局适配不同设备
  4. 实现分布式数据管理同步播放状态

希望本文能够为你提供有价值的参考,期待看到更多优秀的鸿蒙Flutter应用诞生!建议开发者可以从小型功能模块开始尝试,逐步构建完整的音乐应用生态。

欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐