首发于公众号 前端混合开发,欢迎关注。

React Native 应用开发人员构建各种应用,其中一些涉及实现音乐播放列表。如果你计划用 React Native 构建音频播放器,你无疑需要一个播放列表实现,包括一个可管理的音乐轨道队列,对用户可见或作为后台服务运行,以特定顺序播放音乐轨道。

在 React Native 中创建和管理播放列表有几种可能的方法。我们可以从头开始构建播放列表和播放器,而不使用第三方库,但这是耗时的。我们也可以选择使用一个库来播放音乐曲目,并根据音乐播放器事件从头开始开发音乐队列。我们可以使用功能齐全的音乐曲目播放器库进一步加快开发过程。

react-native-track-player 库为在 React Native 中创建基于播放列表的音乐应用程序提供了功能齐全的 API。在这个教程中,我将通过实现一个包含可见播放列表的音乐播放器来解释 react-native-track-player 的功能。

react-native-track-player 的突出特性

对开发者友好的播放器状态管理

该库由两个逻辑模块组成:

  • 音乐播放器模块
  • 播放列表实现

音乐播放器模块播放播放列表中的音轨。这个库提供了函数和 React Hooks 来控制音乐播放器的状态并订阅播放器事件。这些对开发者友好的播放器状态管理功能使音轨播放器-UI 集成变得简单。此外,基于事件的 React Hooks 减少了 React 状态管理需求的复杂性。

简单的播放列表管理

这个库为开发者提供了一个简单的 API 来管理音乐轨道队列。可以通过自解释的功能来编程添加、删除、重复和跳过音乐轨道。使用这个库,创建自己的基于播放列表的音乐播放器非常容易。

性能优先的本地库核心

对于播放列表管理和播放,此库使用两个本地模块:

  • KotlinAudio:适用于 Android 的音轨播放器实现
  • SwiftAudioEx:适用于 iOS 的音轨播放器实现

JavaScript react-native-track-player 实现调用上述本地模块进行音乐播放和播放列表管理,因此,这个库致力于为的音乐应用提供本地性能。播放列表存储在最佳的本地数据结构中以获得更好的性能(即,Kotlin 中的 LinkedList)。

该库提供了一个对开发者友好的、一致的、异步的 API,因此你可以在你的 React Native 应用代码库中轻松使用现代的 async/await 模式。

平台支持和灵活的平台特定配置

该库适用于 Android、iOS 和 Windows 平台。它使用 WinRT 媒体播放 API 在 Windows 上播放音乐内容,所以你可以使用这个包来构建现代的 Windows 应用!

轨道播放器库从不通过仅提供通用的跨平台 API 来限制开发者,它为高级用例提供了特定于平台的配置。例如,它允许在 Android 上更改通知面板播放器图标。

react-native-track-player 教程

现在,我们将通过开发一个带有播放列表的音乐播放器应用来学习如何使用 react-native-track-player 库。在构建音乐播放器应用的过程中,我将向你展示一些额外的示例代码片段,以进一步解释库 API 函数。

将库集成到 React Native 项目中

通过安装 react-native-track-player 包来开始。首先,为构建音乐播放器创建一个新的 React Native 项目:

npx react-native init MusicTrackPlayer
cd MusicTrackPlayer

接下来,运行新创建的应用程序以确保一切正常:

npx react-native run-android
# --- or ---
npx react-native run-ios

现在,安装库:

npm install react-native-track-player
# --- or ---
yarn add react-native-track-player

我正在 Android 上开发这个示例应用,所以运行上述命令就足以设置库。但是,在 iOS 上,你需要手动安装本地依赖项:

cd ios && pod install

注意:在 Android 上,如果 :app:checkDebugAarMetadata Gradle 构建任务失败,请在在的 android/build.gradle 中使用 compileSdkVersion = 33

创建一个简单的音轨播放器

我们开始使用音轨播放器库播放音乐。在实现播放列表的 UI 组件之前,我们将以编程方式创建一个播放列表,以理解播放列表管理 API。

首先,在目录中创建一个名为 assets 的新目录,并下载这些音乐曲目(来自 Pixabay Music 的三个 MP3 音频文件)到其中。

在初始化轨道播放器实例以播放您下载的 MP3 文件之前,我们需要定义几个服务来帮助我们配置、初始化和控制轨道播放器实例。创建一个名为 trackPlayerServices.js 的新文件,并添加以下代码:

import TrackPlayer, {
  AppKilledPlaybackBehavior,
  Capability,
  RepeatMode,
  Event
} from 'react-native-track-player';

export async function setupPlayer() {
  let isSetup = false;
  try {
    await TrackPlayer.getCurrentTrack();
    isSetup = true;
  }
  catch {
    await TrackPlayer.setupPlayer();
    await TrackPlayer.updateOptions({
      android: {
        appKilledPlaybackBehavior:
          AppKilledPlaybackBehavior.StopPlaybackAndRemoveNotification,
      },
      capabilities: [
        Capability.Play,
        Capability.Pause,
        Capability.SkipToNext,
        Capability.SkipToPrevious,
        Capability.SeekTo,
      ],
      compactCapabilities: [
        Capability.Play,
        Capability.Pause,
        Capability.SkipToNext,
      ],
      progressUpdateEventInterval: 2,
    });

    isSetup = true;
  }
  finally {
    return isSetup;
  }
}

export async function addTracks() {
  await TrackPlayer.add([
    {
      id: '1',
      url: require('./assets/fluidity-100-ig-edit-4558.mp3'),
      title: 'Fluidity',
      artist: 'tobylane',
      duration: 60,
    }
  ]);
  await TrackPlayer.setRepeatMode(RepeatMode.Queue);
}

export async function playbackService() {
  // TODO: Attach remote event handlers
}

上述代码实现了三个服务:

  1. setupPlayer :仅一次初始化具有多种播放器功能和默认行为(即,应用程序被杀死的行为)的音轨播放器实例。
  2. addTracks : 从包资源中向当前播放列表添加一首曲目
  3. playbackService : 该服务接收远程事件。我们将在即将到来的部分讨论播放服务事件,所以现在让我们保持这个功能为空。

在这里,我们通过 require 函数从应用程序包中加载 MP3 文件。该库支持通过 http 协议加载远程音频文件,以及通过 file 协议加载本地音频文件。

接下来,我们需要将上述的 playbackService 函数注册为播放事件处理器。在你的 index.js 文件中使用以下代码:

import { AppRegistry } from 'react-native';
import TrackPlayer from 'react-native-track-player';
import App from './App';
import { name as appName } from './app.json';
import { playbackService } from './trackPlayerServices';

AppRegistry.registerComponent(appName, () => App);
TrackPlayer.registerPlaybackService(() => playbackService);

在这里,我们通过 require 函数从应用程序包中加载 MP3 文件。该库支持通过 http 协议加载远程音频文件,以及通过 file 协议加载本地音频文件。

接下来,我们需要将上述的 playbackService 函数注册为播放事件处理器。在你的 index.js 文件中使用以下代码:

import { AppRegistry } from 'react-native';
import TrackPlayer from 'react-native-track-player';
import App from './App';
import { name as appName } from './app.json';
import { playbackService } from './trackPlayerServices';

AppRegistry.registerComponent(appName, () => App);
TrackPlayer.registerPlaybackService(() => playbackService);

现在,我们可以开始构建应用程序的用户界面,因为我们的音轨播放器服务已经准备就绪。请将以下代码添加到您的 App.js 文件中:

import React, { useEffect, useState } from 'react';
import {
  SafeAreaView,
  StyleSheet,
  View,
  Button,
  ActivityIndicator,
} from 'react-native';
import TrackPlayer from 'react-native-track-player';
import { setupPlayer, addTracks } from './trackPlayerServices';

function App() {

  const [isPlayerReady, setIsPlayerReady] = useState(false);

  useEffect(() => {
    async function setup() {
      let isSetup = await setupPlayer();

      const queue = await TrackPlayer.getQueue();
      if(isSetup && queue.length <= 0) {
        await addTracks();
      }

      setIsPlayerReady(isSetup);
    }

    setup();
  }, []);

  if(!isPlayerReady) {
    return (
      <SafeAreaView style={styles.container}>
        <ActivityIndicator size="large" color="#bbb"/>
      </SafeAreaView>
    );
  }

  return (
    <SafeAreaView style={styles.container}>
      <Button title="Play" color="#777" onPress={() => TrackPlayer.play()}/>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    padding: 20,
    backgroundColor: '#112'
  },
});

export default App;

上述 App 组件通过 useEffect 调用 setupPlayer 服务,以在本地端初始化音轨播放器。接下来,如果当前播放列表为空,它将调用 addTracks 服务来初始化播放列表。该组件使用如下的条件渲染逻辑:

  • 如果播放器尚未准备好(正在进行设置),则渲染加载动画
  • 如果播放器设置过程成功,将渲染一个播放按钮

播放按钮调用 TrackPlayer.play 函数开始播放曲目队列。运行上述应用程序代码并按下播放按钮。播放列表将开始!看看以下预览:

使用以下代码为 addTracks 服务播放所有已下载的音乐曲目:

export async function addTracks() {
  await TrackPlayer.add([
    {
      id: '1',
      url: require('./assets/fluidity-100-ig-edit-4558.mp3'),
      title: 'Fluidity',
      artist: 'tobylane',
      duration: 60,
    },
    {
      id: '2',
      url: require('./assets/penguinmusic-modern-chillout-future-calm-12641.mp3'),
      title: 'Modern Chillout',
      artist: 'penguinmusic',
      duration: 66,
    },
    {
      id: '3',
      url: require('./assets/powerful-beat-121791.mp3'),
      title: 'Powerful Beat',
      artist: 'penguinmusic',
      duration: 73,
    }
  ]);
  await TrackPlayer.setRepeatMode(RepeatMode.Queue);
}

每当播放列表结束时,它将会因为 RepeatMode.Queue 模式而重新开始播放。

在前面的示例代码中,我们使用了 TrackPlayer.add 函数来向播放列表中添加新的音乐轨道。同样,你可以使用以下函数来管理当前的播放列表:

  • TrackPlayer.remove : 通过音轨索引删除音乐曲目
  • TrackPlayer.skip : 跳至给定索引的音乐曲目
  • TrackPlayer.next : 跳至下一首音乐曲目
  • TrackPlayer.previous : 跳至上一首音乐曲目
  • TrackPlayer.reset : 清除当前播放列表并停止播放音乐

在官方文档中浏览所有支持的播放列表管理功能。

一旦你按下播放按钮,使用热重载功能逐一执行以下函数调用,以熟悉播放列表管理功能

TrackPlayer.remove(0)
TrackPlayer.skip(2)
TrackPlayer.next()
TrackPlayer.previous()
TrackPlayer.reset()

可视化管理播放列表

我们在实际场景中使用上述播放列表管理功能。我们可以开始改进示例应用,将其变成基于播放列表的音乐播放器。

作为第一步,让我们创建一个 React 组件来显示当前的播放列表,并让用户播放首选的音乐曲目。为了简单起见,在本教程中,我们将在我们的 App.js 文件中开发所有组件,但在开发生产级应用时,请确保将你的应用适当地分解到单独的源文件中。

首先,将以下导入行添加到 App.js

import {
  SafeAreaView,
  StyleSheet,
  Text,
  View,
  Button,
  FlatList,
  ActivityIndicator,
  TouchableOpacity,
} from 'react-native';
import TrackPlayer, {
  useTrackPlayerEvents,
  Event,
  State
} from 'react-native-track-player';

接下来,将 Playlist 组件实现添加到源文件中:

function Playlist() {
  const [queue, setQueue] = useState([]);
  const [currentTrack, setCurrentTrack] = useState(0);

  async function loadPlaylist() {
    const queue = await TrackPlayer.getQueue();
    setQueue(queue);
  }

  useEffect(() => {
    loadPlaylist();
  }, []);

  useTrackPlayerEvents([Event.PlaybackTrackChanged], async (event) => {
    if(event.state == State.nextTrack) {
      let index = await TrackPlayer.getCurrentTrack();
      setCurrentTrack(index);
    }
  });

  function PlaylistItem({index, title, isCurrent}) {

    function handleItemPress() {
      TrackPlayer.skip(index);
    }

    return (
      <TouchableOpacity onPress={handleItemPress}>
        <Text
          style={{...styles.playlistItem,
            ...{backgroundColor: isCurrent ? '#666' : 'transparent'}}}>
        {title}
        </Text>
      </TouchableOpacity>
    );
  }

  return(
    <View>
      <View style={styles.playlist}>
        <FlatList
          data={queue}
          renderItem={({item, index}) => <PlaylistItem
                                            index={index}
                                            title={item.title}
                                            isCurrent={currentTrack == index }/>
          }
        />
      </View>
    </View>
  );
}

在这里,我们使用 FlatList 组件来渲染当前的播放列表。 FlatList 组件使用 queue 状态变量来加载当前播放列表的详细信息。同时, useEffect 调用 TrackPlayer.getQueue 来将当前播放列表捕获到 queue 中。

播放列表的用户界面还会突出显示当前的音乐曲目,因此我们在 currentTrack 状态变量中存储当前音乐曲目的索引。一旦用户按下列表项,我们就会要求音轨播放器实例通过调用 TrackPlayer.skip 函数来播放选定的音轨。我们通过 useTrackPlayerEvents 库钩子来跟踪 currentTrack 的变化。

接下来,在 App 组件中添加 <Playlist/> ,如下面的代码片段所示:

return (
  <SafeAreaView style={styles.container}>
    <Playlist/>
    <Button title="Play" color="#777" onPress={() => TrackPlayer.play()}/>
  </SafeAreaView>
);

将以下样式定义添加到您的样式表中:

playlist: {
  marginTop: 40,
  marginBottom: 40
},
playlistItem: {
  fontSize: 16,
  paddingTop: 4,
  paddingBottom: 4,
  paddingLeft: 8,
  paddingRight: 8,
  borderRadius: 4
},

运行应用程序。现在,你可以按下并选择一首音乐曲目。等待音乐曲目播放完毕 - 播放列表组件将自动设置下一首当前音乐曲目,如下预览所示:

处理播放和播放器状态

之前,我们调用了 TrackPlayer.play 函数来开始播放音轨队列。在构建音乐应用时,我们经常需要暂停,控制播放速度,调整音乐音量,并跳到当前音乐轨道的特定位置。 react-native-track-player 库除了播放操作外,还让你可以使用以下函数来控制播放和播放器状态:

  • TrackPlayer.pause : 暂停当前播放的音轨;你可以用 TrackPlayer.play 函数再次播放
  • TrackPlayer.seekTo : 根据输入的秒数跳到特定位置
  • TrackPlayer.setRate : 改变播放速度
  • TrackPlayer.setVolume : 设置音乐播放器音量

上述功能影响当前的播放/播放器状态。在调用上述功能之前,也可以获取播放/播放器的状态。以下是我们经常需要的一些获取器:

  • TrackPlayer.getState : 返回当前的播放状态
  • TrackPlayer.getVolume : 返回当前音量级别

注意:如前所述,该库提供了一个异步 API,所以必须使用 await 令牌从已解决的承诺中提取返回的数据。从官方文档中浏览所有支持的播放状态控制功能。

一旦你按下播放按钮,依次执行以下函数调用,并使用热重载来熟悉播放器/播放状态函数:

TrackPlayer.pause()
TrackPlayer.seekTo(10)
TrackPlayer.setRate(0.5)
TrackPlayer.setVolume(0.2)

可视化播放和播放器状态

现在,我们将使用上述函数在我们的音乐播放器中添加一个控制框。用户可以使用控制框按钮播放/暂停,跳到上一首音乐,以及跳到下一首音乐。我们将使用 react-native-vector-icons 包来构建控制框图标按钮。

首先,根据官方安装指南安装它并重建项目。然后,在的 App.js 文件中添加以下导入:

现在,请更新现有的 Playlist 组件并添加新的 Controls 组件源:

function Playlist() {
  const [queue, setQueue] = useState([]);
  const [currentTrack, setCurrentTrack] = useState(0);

  async function loadPlaylist() {
    const queue = await TrackPlayer.getQueue();
    setQueue(queue);
  }

  useEffect(() => {
    loadPlaylist();
  }, []);

  useTrackPlayerEvents([Event.PlaybackTrackChanged], (event) => {
    if(event.state == State.nextTrack) {
      TrackPlayer.getCurrentTrack().then((index) => setCurrentTrack(index));
    }
  });

  function PlaylistItem({index, title, isCurrent}) {

    function handleItemPress() {
      TrackPlayer.skip(index);
    }

    return (
      <TouchableOpacity onPress={handleItemPress}>
        <Text
          style={{...styles.playlistItem,
            ...{backgroundColor: isCurrent ? '#666' : 'transparent'}}}>
        {title}
        </Text>
      </TouchableOpacity>
    );
  }

  return(
    <View>
      <View style={styles.playlist}>
        <FlatList
          data={queue}
          renderItem={({item, index}) => <PlaylistItem
                                            index={index}
                                            title={item.title}
                                            isCurrent={currentTrack == index }/>
          }
        />
      </View>
      <Controls/>
    </View>
  );
}

function Controls({ onShuffle }) {
  const playerState = usePlaybackState();

  async function handlePlayPress() {
    if(await TrackPlayer.getState() == State.Playing) {
      TrackPlayer.pause();
    }
    else {
      TrackPlayer.play();
    }
  }

  return(
    <View style={{flexDirection: 'row',
      flexWrap: 'wrap', alignItems: 'center'}}>
        <Icon.Button
          name="arrow-left"
          size={28}
          backgroundColor="transparent"
          onPress={() => TrackPlayer.skipToPrevious()}/>
        <Icon.Button
          name={playerState == State.Playing ? 'pause' : 'play'}
          size={28}
          backgroundColor="transparent"
          onPress={handlePlayPress}/>
        <Icon.Button
          name="arrow-right"
          size={28}
          backgroundColor="transparent"
          onPress={() => TrackPlayer.skipToNext()}/>
    </View>
  );
}

在这里,我们使用一个图标按钮来切换播放/暂停状态,具有以下条件:

await TrackPlayer.getState() == State.Playing

从 App 组件中移除之前的播放按钮,因为它已经不再需要了:

return (
  <SafeAreaView style={styles.container}>
    <Playlist/>
  </SafeAreaView>
);

运行应用程序。现在,你可以使用控制框。

该库提供了 useProgress Hook 来跟踪音乐轨迹的进度。默认情况下,此 Hook 每秒轮询一次轨迹进度,但您可以根据需要配置间隔(即, useProgress(200) )。

使用 useProgress 钩子创建一个新的组件来显示音乐轨迹的进度:

function TrackProgress() {
  const { position, duration } = useProgress(200);

  function format(seconds) {
    let mins = (parseInt(seconds / 60)).toString().padStart(2, '0');
    let secs = (Math.trunc(seconds) % 60).toString().padStart(2, '0');
    return `${mins}:${secs}`;
  }

  return(
    <View>
      <Text style={styles.trackProgress}>
        { format(position) } / { format(duration) }
      </Text>
    </View>
  );
}

上述的 TrackProgress 组件使用音轨时长以 mm:ss 格式显示当前音轨的进度。

添加另一个组件以显示当前音乐轨道信息:

function Header() {
  const [info, setInfo] = useState({});
  useEffect(() => {
    setTrackInfo();
  }, []);

  useTrackPlayerEvents([Event.PlaybackTrackChanged], (event) => {
    if(event.state == State.nextTrack) {
      setTrackInfo();
    }
  });

  async function setTrackInfo() {
    const track = await TrackPlayer.getCurrentTrack();
    const info = await TrackPlayer.getTrack(track);
    setInfo(info);
  }

  return(
    <View>
        <Text style={styles.songTitle}>{info.title}</Text>
        <Text style={styles.artistName}>{info.artist}</Text>
    </View>
  );
}

在这里,我们使用了 useTrackPlayerEvents 钩子来更新当前音轨的详细信息,每当当前音轨发生变化时。接下来,将 useProgress 钩子添加到导入列表中:

import TrackPlayer, {
  useTrackPlayerEvents,
  usePlaybackState,
  useProgress,
  Event,
  State
} from 'react-native-track-player';

现在,在 App 中渲染上述组件:

return (
  <SafeAreaView style={styles.container}>
    <Header/>
    <TrackProgress/>
    <Playlist/>
  </SafeAreaView>
);

将以下样式定义添加到你的样式表中:

 trackProgress: {
    marginTop: 40,
    textAlign: 'center',
    fontSize: 24,
    color: '#eee'
  },
  songTitle: {
    fontSize: 32,
    marginTop: 50,
    color: '#ccc'
  },
  artistName: {
    fontSize: 24,
    color: '#888'
  },

运行应用程序。现在,你将看到带有音乐轨道详情、轨道进度、播放列表和控制框组件的界面。

可以通过添加带有 react-native-slider 的进度条来改善音乐轨道播放器,但是我们在本教程中不会深入介绍 react-native-slider 的集成。添加进度条的步骤很简单,如下所示:

  • 使用 useProgress 钩子更新滑块
  • 为滑块附加一个事件处理器,并调用 TrackPlayer.seekTo 来改变播放状态

如何循环和随机播放列表项

可以使用我们之前测试过的源代码来切换到上一首或下一首音乐曲目。由于我们在 addTracks 服务中使用了 RepeatMode.Queue 模式,所以每当播放列表结束时,它都会重新开始(循环)。可以使用 RepeatMode.Track 通过 TrackPlayer.setRepeatMode 功能来循环当前曲目。尝试自己在控制框中添加一个播放列表重复模式选择按钮!

如果你需要打乱播放列表怎么办?原生的播放列表随机功能仍然是一个正在进行的功能请求(问题#1711),但是现在,我们可以在 JavaScript 端实现播放列表的随机功能。

首先,在 Playlist 组件中实现播放列表的随机播放:

async function handleShuffle() {
  let queue = await TrackPlayer.getQueue();
  await TrackPlayer.reset();
  queue.sort(() => Math.random() - 0.5);
  await TrackPlayer.add(queue);

  loadPlaylist()
}

return(
  <View>
    <View style={styles.playlist}>
      <FlatList
        data={queue}
        renderItem={({item, index}) => <PlaylistItem
                                          index={index}
                                          title={item.title}
                                          isCurrent={currentTrack == index }/>
        }
      />
    </View>
    <Controls onShuffle={handleShuffle}/>
  </View>
);

在这里,我们提取当前队列,对其进行洗牌,然后通过 handleShuffle 函数将其重新加载到播放列表中。接下来,为洗牌添加一个新的图标按钮:

function Controls({ onShuffle }) {
  const playerState = usePlaybackState();

  async function handlePlayPress() {
    if(await TrackPlayer.getState() == State.Playing) {
      TrackPlayer.pause();
    }
    else {
      TrackPlayer.play();
    }
  }

  return(
    <View style={{flexDirection: 'row',
      flexWrap: 'wrap', alignItems: 'center'}}>
        <Icon.Button
          name="arrow-left"
          size={28}
          backgroundColor="transparent"
          onPress={() => TrackPlayer.skipToPrevious()}/>
        <Icon.Button
          name={playerState == State.Playing ? 'pause' : 'play'}
          size={28}
          backgroundColor="transparent"
          onPress={handlePlayPress}/>
        <Icon.Button
          name="arrow-right"
          size={28}
          backgroundColor="transparent"
          onPress={() => TrackPlayer.skipToNext()}/>
        <Icon.Button
          name="random"
          size={28}
          backgroundColor="transparent"
          onPress={onShuffle}/>
    </View>
  );
}

一旦你运行这个应用,你就可以使用洗牌功能:

请自行添加一个按钮来播放随机音乐曲目!同样,你可以通过操作音轨播放器队列来重新排序播放列表项目并创建多个播放列表。由于库在本地端使用适当的数据结构处理播放列表,所以播放列表管理操作将高效运行。

使用轨道播放器事件

我们已经在上述组件中使用了一些轨道播放器事件。例如,在 Header 组件中,我们使用了 useTrackPlayerEvents 钩子来检测音乐轨道更改事件。

该库允许你为两种事件类型附加函数:

  1. 应用内事件:这些事件在应用内自动发生或由用户启动,即播放/暂停事件。该库提供 useTrackPlayerEventsusePlaybackState 钩子来订阅这些应用内事件。
  2. 远程事件:这些事件由操作系统启动,即当用户按下通知区域迷你播放器的播放按钮时,库会派发 Event.RemoteNext 事件。我们将在下一节中讨论如何处理远程事件。

使用后台模式

用户通常在使用音乐应用时进行多任务处理。例如,移动用户可能在听音乐时使用消息应用。

音乐应用通常会在后台模式下播放当前的播放列表,但如果用户想要播放下一首歌怎么办?用户可以从通知面板中按下“下一首”按钮,而不是再次打开音乐播放器应用。

运行示例应用并检查通知栏。您将看到如下的小型,平台特定的播放器组件:

但是,你还不能用这个迷你播放器来控制播放列表。原因是库触发远程事件处理程序,而不是改变音轨播放器状态。这种情况为开发者提供了处理远程事件的灵活性。

你还记得我们在演示应用的代码库中有一个 TODO: 的评论吗?那就是我们将 playbackService 附加到库的地方——但我们还没有为远程事件实现操作。

在 playbackService 中使用以下代码来根据远程事件控制轨道播放器:

export async function playbackService() {
  TrackPlayer.addEventListener(Event.RemotePause, () => {
    console.log('Event.RemotePause');
    TrackPlayer.pause();
  });

  TrackPlayer.addEventListener(Event.RemotePlay, () => {
    console.log('Event.RemotePlay');
    TrackPlayer.play();
  });

  TrackPlayer.addEventListener(Event.RemoteNext, () => {
    console.log('Event.RemoteNext');
    TrackPlayer.skipToNext();
  });

  TrackPlayer.addEventListener(Event.RemotePrevious, () => {
    console.log('Event.RemotePrevious');
    TrackPlayer.skipToPrevious();
  });
}

即使应用在后台播放,上述服务也会被执行。在后台模式下,播放/播放器事件应该按预期工作——换句话说, react-native-track-player 库支持后台模式,无需自定义调整!

运行该应用程序,打开音乐播放器上的另一个应用程序,并使用通知区域的迷你播放器播放下一首音乐曲目 - 一切都将正常运行。

在 Android 上,音乐播放器应用在被终止时会移除通知区域的迷你播放器并停止播放音乐,但您可以通过在 setupPlayer 服务中使用以下设置来避免这种行为:

await TrackPlayer.updateOptions({
  android: {
    appKilledPlaybackBehavior:
      AppKilledPlaybackBehavior.ContinuePlayback,
  },
// ---

如何存储播放列表

在这个教程中,我们使用了硬编码的播放列表进行演示。但是,在生产音乐应用中,您可能需要以更易管理的方式存储您的播放列表。请考虑以下存储播放列表信息的选项:

  • 如果应用程序可以自动从设备存储中获取音乐文件(即,使用 react-native-fs) ,请考虑在应用程序偏好设置或临时文件中缓存播放列表。
  • 也可以缓存播放列表,并提供一个导出/导入播放列表的功能,如果您让用户管理播放列表
  • 如果您的音乐应用是一个远程音乐播放器(即,像 Spotify),您无疑可以在服务器中存储您的播放列表,并提供一个用于播放列表管理的 CRUD API

最后

在这个教程中,我们开发了一个基于播放列表的音乐轨道播放器,以学习 react-native-track-player 库的功能。 react-native-track-player 库让你创建和管理可播放的音乐播放列表

或者,你可以使用 react-native-sound 库通过 JavaScript 播放音乐并自行处理播放列表——然后,需要根据 react-native-sound 事件编写整个播放列表队列的实现。尽管肯定可以开发出这样的实现,但您可能会面临应用程序性能的问题,因为您同时处理播放事件和 JavaScript 中的播放列表状态。

交流

首发于公众号 大迁世界,欢迎关注。📝 每周一篇实用的前端文章 🛠️ 分享值得关注的开发工具 ❓ 有疑问?我来回答

本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试完整考点、资料以及我的系列文章。


王大冶
68k 声望104.9k 粉丝