为你的应用添加声音是吸引用户的好方法。新通知的小铃声,发送邮件的“嗖”的声音,或者删除文件的崩溃声,都能在很大程度上为你的 React Native 应用构建更好的用户体验。
本文中,我们将探索 react-native-sound
,这是一个强大的音频组件,可以处理你的 React Native 应用的声音相关任务。
什么是 react-native-sound?
react-native-sound 是一个 React Native 模块,用于在 iOS、Android 和 Windows 上播放声音片段。此模块使我们能够从各种来源添加音频,例如应用程序包(原生)、JavaScript 包,或远程路径(本地存储或远程 URL)。
react-native-sound
更像是一个类而不是类组件,它通过预定义的方法帮助控制实例,无需更新状态或属性。这缓解了与应用程序慢速重新渲染相关的问题。
尽管 react-native-sound
的文档警告称它是”alpha 版本可能有 bug”,但它是当今最流行、使用最广泛的 React Native 声音库之一。
设置 react-native-sound(iOS 和 Android)
要开始使用 react-native-sound
,如果你想在应用中播放的声音不是远程可用的(即,它们在应用的包内,而不是在设备的外部存储或远程服务器上),你需要准备这些声音。
要在你的应用中添加 react-native-sound
,只需在你的应用目录中使用你喜欢的包管理器(例如,npm
或 yarn
)输入以下命令:
yarn add react-native-sound
如果你正在为 Android 构建应用,链接过程会在构建过程中处理。
对于 iOS,只需导航到 iOS 目录并调用 pod install
即可。这将添加 react-native-sound 所需的 pod。
为应用添加声音
现在是时候添加你想要播放的声音了。这个步骤只是为了学习如何将音频文件打包到原生包中。我们还会介绍一种更简单的方法,从资产目录中获取音频文件。
对于 Android,创建 raw
目录并将声音复制到该目录:
{appDirectory}/android/app/src/main/res/raw
对于 iOS,打开 Xcode 中的工作区,然后右键点击项目并点击添加文件到{项目名称},如下图所示:
在添加了声音文件后,只需构建应用并在模拟器上运行,或者更好的是在真实设备上运行。
从包中播放声音
首先,我们需要在应用中导入声音组件:
import Sound from 'react-native-sound';
在设置我们要播放的声音之前,我们需要指定声音的类别:
Sound.setCategory('Playback');
要初始化声音,请使用以下代码:
var ding = new Sound('ding.mp3', Sound.MAIN_BUNDLE, (error) => { if (error) { console.log('failed to load the sound', error); return; } // when loaded successfully console.log('duration in seconds: ' + whoosh.getDuration() + 'number of channels: ' + whoosh.getNumberOfChannels()); });
上面的代码使用第一个参数 ding.mp3
,这是来自使用第二个参数 Sound.MAIN_BUNDLE
指定的包中的文件,并在第三个参数中返回一个回调函数。
getDuration
用于获取音频文件的持续时间(以秒为单位),getNumberOfChannels
用于获取音频通道的数量。
要设置播放音量,我们可以使用以下方法:
ding.setVolume(1);
这里, 1
是最高音量, 0
是最低音量,它们之间的差异用小数表示 —— 例如,要将音量降低到 50%,你可以将其设置为 0.5
。
要播放文件,我们可以使用 Sound
的 play
方法,如下所示:
ding.play(success => { if (success) { console.log('successfully finished playing'); } else { console.log('playback failed due to audio decoding errors'); } });
成功完成回款后会有一个回调(或者如果出了任何问题,也是如此)。
总结以上所述的步骤:
设置要播放的声音的类别
初始化一个声音文件
如有必要,调整音量
播放声音
这是从包中播放声音的最终代码:
import React, {useEffect} from 'react'; import {View, StyleSheet, TouchableOpacity} from 'react-native'; import Ionicons from 'react-native-vector-icons/Ionicons'; var Sound = require('react-native-sound'); Sound.setCategory('Playback'); var ding = new Sound('ding.mp3', Sound.MAIN_BUNDLE, (error) => { if (error) { console.log('failed to load the sound', error); return; } // if loaded successfully console.log('duration in seconds: ' + ding.getDuration() + 'number of channels: ' + ding.getNumberOfChannels()); }); const App = () => { useEffect(() => { ding.setVolume(1); return () => { ding.release(); }; }, []); const playPause = () => { ding.play(success => { if (success) { console.log('successfully finished playing'); } else { console.log('playback failed due to audio decoding errors'); } }); }; return (); }; const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: '#000', }, playBtn: { padding: 20, }, }); export default App;
导入声音文件
现在,对于来自资源目录(或应用程序中的任何目录)的文件,我们可以使用相同的旧 require
或 import
来获取文件的实例,并使用 react-native-sound 播放它。
import dings from './src/assets/ding.mp3';
并在 Sound 包中使用它,如下所示:
var ding = new Sound(dings, error => { if (error) { console.log('failed to load the sound', error); return; } // if loaded successfully console.log('duration in seconds: ' + ding.getDuration() + 'number of channels: ' + ding.getNumberOfChannels()); });
与使用捆绑文件相比,使用从资源导入或引用的文件的不同之处在于,你不必为文件指定 basePath
。相反,回调函数取代了它的位置。
这是播放导入文件的组件的代码:
import React, {useEffect} from 'react'; import {View, StyleSheet, TouchableOpacity} from 'react-native'; import dings from './src/assets/ding.mp3'; import Ionicons from 'react-native-vector-icons/Ionicons'; var Sound = require('react-native-sound'); Sound.setCategory('Playback'); var ding = new Sound(dings, error => { if (error) { console.log('failed to load the sound', error); return; } // if loaded successfully console.log( 'duration in seconds: ' + ding.getDuration() + 'number of channels: ' + ding.getNumberOfChannels(), ); }); const App = () => { useEffect(() => { ding.setVolume(1); return () => { ding.release(); }; }, []); const playPause = () => { ding.play(success => { if (success) { console.log('successfully finished playing'); } else { console.log('playback failed due to audio decoding errors'); } }); }; return (); }; const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: '#000', }, playBtn: { padding: 20, }, }); export default App;
以下是上述代码的结果。只需点击播放按钮即可播放声音。
111111
从远程路径播放声音文件
你可能想播放远程文件或本地存储中的文件。使用 react-native-sound
播放这些文件基本上和播放捆绑文件一样简单。你只需要将 URL 作为第一个参数添加到 Sound
中,并将第二个参数设置为 null
,因为文件来自远程或本地存储,而不是来自应用程序。
var audio = new Sound( 'https://file-examples-com.github.io/uploads/2017/11/file_example_MP3_700KB.mp3', null, error => { if (error) { console.log('failed to load the sound', error); return; } // if loaded successfully console.log( 'duration in seconds: ' + audio.getDuration() + 'number of channels: ' + audio.getNumberOfChannels(), ); }, );
以下是一个完整的示例,说明如何在应用关闭或组件卸载后播放、暂停和释放音频:
import React, {useEffect, useState} from 'react'; import {View, StyleSheet, TouchableOpacity} from 'react-native'; import Ionicons from 'react-native-vector-icons/Ionicons'; var Sound = require('react-native-sound'); Sound.setCategory('Playback'); var audio = new Sound( 'https://file-examples-com.github.io/uploads/2017/11/file_example_MP3_700KB.mp3', null, error => { if (error) { console.log('failed to load the sound', error); return; } // if loaded successfully console.log( 'duration in seconds: ' + audio.getDuration() + 'number of channels: ' + audio.getNumberOfChannels(), ); }, ); const App = () => { const [playing, setPlaying] = useState(); useEffect(() => { audio.setVolume(1); return () => { audio.release(); }; }, []); const playPause = () => { if (audio.isPlaying()) { audio.pause(); setPlaying(false); } else { setPlaying(true); audio.play(success => { if (success) { setPlaying(false); console.log('successfully finished playing'); } else { setPlaying(false); console.log('playback failed due to audio decoding errors'); } }); } }; return (); }; const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: '#000', }, playBtn: { padding: 20, }, }); export default App;
.release()
用于释放预留给播放音频文件的内存。在组件卸载或音频不再播放后释放内存非常重要。这有助于避免内存泄漏或其他错误。
总结
react-native-sound 是一个很好的模块,用于为你的 React Native 应用添加声音或构建一个简单的音频播放器。
在这个教程中,我们介绍了如何从本地包添加和播放音频,以及如何从远程文件播放音频。如果你想在这方面探索更多选项,我建议尝试使用 Expo unimodules 的 expo-av 模块在你的 React Native 应用中播放音频或视频文件。