概述

随着鸿蒙操作系统的不断发展,越来越多的开发者开始关注这个新兴的生态系统。本文将介绍如何使用鸿蒙应用开发框架(ArkUI)开发一个简单的音乐播放器应用,涵盖界面设计、音频播放控制和列表展示等核心功能。

环境准备

首先确保你的开发环境已配置完成:

  • DevEco Studio 3.0或更高版本

  • HarmonyOS SDK

  • Java SDK

项目结构

MusicPlayer/
├── entry/
│   └── src/
│       ├── main/
│       │   ├── ets/
│       │   │   ├── MainAbility/
│       │   │   ├── pages/
│       │   │   └── service/
│       │   ├── resources/
│       │   └── config.json
│       └── ohosTest/

核心功能实现

1. 音频播放服务

首先创建音频播放服务类 AudioService.ts

export class AudioService {
  private audioPlayer: audio.AudioPlayer | null = null;
  private currentState: string = 'stopped';
  
  // 初始化音频播放器
  async initAudioPlayer(): Promise<void> {
    try {
      const audioManager = audio.getAudioManager();
      const audioStreamInfo = {
        samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_44100,
        channels: audio.AudioChannel.CHANNEL_2,
        sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,
        encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW
      };
      
      const audioPlayer = await audioManager.createAudioPlayer(audioStreamInfo);
      this.audioPlayer = audioPlayer;
      
      // 注册状态回调
      this.audioPlayer.on('stateChange', (state) => {
        this.currentState = state;
        console.log(`Audio state changed to: ${state}`);
      });
      
    } catch (error) {
      console.error('Failed to initialize audio player:', error);
    }
  }
  
  // 播放音频
  async play(url: string): Promise<void> {
    if (!this.audioPlayer) {
      await this.initAudioPlayer();
    }
    
    try {
      await this.audioPlayer.setSource(url);
      await this.audioPlayer.play();
    } catch (error) {
      console.error('Failed to play audio:', error);
    }
  }
  
  // 暂停播放
  async pause(): Promise<void> {
    if (this.audioPlayer && this.currentState === 'playing') {
      await this.audioPlayer.pause();
    }
  }
  
  // 停止播放
  async stop(): Promise<void> {
    if (this.audioPlayer) {
      await this.audioPlayer.stop();
      await this.audioPlayer.release();
      this.audioPlayer = null;
    }
  }
  
  // 获取当前播放状态
  getCurrentState(): string {
    return this.currentState;
  }
}

2. 音乐数据模型

创建音乐数据模型 MusicModel.ts

export interface Music {
  id: number;
  title: string;
  artist: string;
  album: string;
  duration: number;
  coverUrl: string;
  audioUrl: string;
}

export class MusicModel {
  private musicList: Music[] = [
    {
      id: 1,
      title: "示例歌曲1",
      artist: "歌手A",
      album: "专辑1",
      duration: 180,
      coverUrl: "common/images/cover1.jpg",
      audioUrl: "https://example.com/audio1.mp3"
    },
    {
      id: 2,
      title: "示例歌曲2",
      artist: "歌手B",
      album: "专辑2",
      duration: 210,
      coverUrl: "common/images/cover2.jpg",
      audioUrl: "https://example.com/audio2.mp3"
    }
  ];
  
  // 获取所有音乐
  getAllMusic(): Music[] {
    return this.musicList;
  }
  
  // 根据ID获取音乐
  getMusicById(id: number): Music | undefined {
    return this.musicList.find(music => music.id === id);
  }
  
  // 搜索音乐
  searchMusic(keyword: string): Music[] {
    return this.musicList.filter(music => 
      music.title.includes(keyword) || 
      music.artist.includes(keyword) ||
      music.album.includes(keyword)
    );
  }
}

3. 主界面设计

创建主页面 Index.ets

@Component
struct Index {
  @State musicList: Music[] = []
  @State currentMusic: Music | null = null
  @State isPlaying: boolean = false
  @State searchKeyword: string = ""
  
  private audioService: AudioService = new AudioService()
  private musicModel: MusicModel = new MusicModel()
  
  aboutToAppear() {
    this.musicList = this.musicModel.getAllMusic()
  }
  
  // 播放/暂停切换
  async togglePlayPause(music: Music) {
    if (this.currentMusic?.id === music.id && this.isPlaying) {
      await this.audioService.pause()
      this.isPlaying = false
    } else {
      if (this.currentMusic?.id !== music.id) {
        this.currentMusic = music
        await this.audioService.play(music.audioUrl)
      } else {
        await this.audioService.play(this.currentMusic.audioUrl)
      }
      this.isPlaying = true
    }
  }
  
  // 搜索功能
  onSearch() {
    if (this.searchKeyword.trim() === "") {
      this.musicList = this.musicModel.getAllMusic()
    } else {
      this.musicList = this.musicModel.searchMusic(this.searchKeyword)
    }
  }
  
  build() {
    Column() {
      // 搜索栏
      TextInput({ placeholder: "搜索歌曲、歌手或专辑" })
        .width('90%')
        .height(40)
        .onChange((value: string) => {
          this.searchKeyword = value
          this.onSearch()
        })
      
      // 音乐列表
      List({ space: 10 }) {
        ForEach(this.musicList, (music: Music) => {
          ListItem() {
            this.musicItem(music)
          }
        })
      }
      .width('100%')
      .layoutWeight(1)
      
      // 播放控制栏
      if (this.currentMusic) {
        this.buildPlayerControl()
      }
    }
    .width('100%')
    .height('100%')
    .padding(10)
  }
  
  // 音乐列表项组件
  @Builder
  musicItem(music: Music) {
    Row() {
      Image(music.coverUrl)
        .width(50)
        .height(50)
        .objectFit(ImageFit.Cover)
        .borderRadius(5)
      
      Column() {
        Text(music.title)
          .fontSize(16)
          .fontWeight(FontWeight.Bold)
        Text(`${music.artist} - ${music.album}`)
          .fontSize(12)
          .opacity(0.7)
      }
      .layoutWeight(1)
      .margin({ left: 10 })
      
      if (this.currentMusic?.id === music.id && this.isPlaying) {
        Loading()
          .width(20)
          .height(20)
      }
    }
    .padding(10)
    .onClick(() => {
      this.togglePlayPause(music)
    })
  }
  
  // 播放控制组件
  @Builder
  buildPlayerControl() {
    Column() {
      Text(this.currentMusic.title)
        .fontSize(16)
        .fontWeight(FontWeight.Bold)
      
      Text(this.currentMusic.artist)
        .fontSize(14)
        .opacity(0.8)
      
      Row() {
        Button("上一首")
          .onClick(() => {
            // 上一首逻辑
          })
        
        Button(this.isPlaying ? "暂停" : "播放")
          .onClick(() => {
            this.togglePlayPause(this.currentMusic)
          })
        
        Button("下一首")
          .onClick(() => {
            // 下一首逻辑
          })
      }
      .margin({ top: 10 })
    }
    .padding(10)
    .width('100%')
    .backgroundColor('#f0f0f0')
  }
}

4. 权限配置

在 config.json 中添加必要的权限:

{
  "module": {
    "reqPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      },
      {
        "name": "ohos.permission.MODIFY_AUDIO_SETTINGS"
      }
    ]
  }
}

功能扩展建议

  1. 播放列表管理:实现创建、编辑和删除播放列表功能

  2. 音频可视化:使用Canvas实现音频频谱可视化

  3. 本地音乐扫描:添加扫描设备本地音乐文件的功能

  4. 后台播放:实现后台播放和通知栏控制

  5. 歌词显示:集成歌词解析和显示功能

总结

本文介绍了如何使用鸿蒙应用开发框架构建一个基本的音乐播放器应用。通过实现音频播放服务、音乐数据管理和用户界面,我们创建了一个功能完整的音乐应用。鸿蒙系统的跨设备能力使得这个应用可以轻松扩展到其他设备,如智能手表、平板等。

开发过程中需要注意音频资源的合理管理和内存使用,确保应用的流畅性和稳定性。随着鸿蒙生态的不断完善,音乐应用开发将会有更多的可能性和创新空间。

希望本文能为你的鸿蒙音乐应用开发之旅提供有用的参考和启发!

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐