Cordova - 媒体
Cordova - 音频播放和录制 (Media)
Section titled “Cordova - 音频播放和录制 (Media)”cordova-plugin-media 插件提供了在设备上录制和播放音频文件的能力。本教程重点介绍音频播放及其控制。
步骤 1 - 安装 Media 插件
Section titled “步骤 1 - 安装 Media 插件”使用 Cordova CLI 安装插件:
cordova plugin add cordova-plugin-media如果您要从设备的特定位置播放文件或录制文件,此插件可能还需要 cordova-plugin-file。对于从 www 文件夹或远程 URL 进行的基本播放,单独的 cordova-plugin-media 最初可能就足够了,但 cordova-plugin-file 通常是 Media 插件的好搭档。
# Optional, but often useful with media:# 可选,但通常在处理 media 时很有用:cordova plugin add cordova-plugin-file添加插件后,重新构建您的项目:cordova build <platform>。
步骤 2 - 准备音频文件
Section titled “步骤 2 - 准备音频文件”将音频文件(例如,sound.mp3)放在您的 www/audio/ 目录中。在本示例中,请创建 www/audio/sound.mp3。如果您没有 MP3 文件,可以在线查找简短的、免版税的声音文件。
步骤 3 - 准备 UI
Section titled “步骤 3 - 准备 UI”在 www/index.html 中,添加用于控制音频播放的按钮:
<body> <h1>Media Player Demo</h1> <button id="playAudioBtn">PLAY</button> <button id="pauseAudioBtn">PAUSE</button> <button id="stopAudioBtn">STOP</button> <br><br> <label for="volumeRange">Volume:</label> <input type="range" id="volumeRange" min="0" max="1" step="0.1" value="0.5"> <br><br> <div id="mediaStatus">Status: Idle</div>
<script src="cordova.js"></script> <script src="js/index.js"></script></body>步骤 4 - 实现 JavaScript 逻辑
Section titled “步骤 4 - 实现 JavaScript 逻辑”在 www/js/index.js 中,实现音频控制函数。所有 Media 对象的交互都必须在 deviceready 事件触发后进行。
document.addEventListener('deviceready', onDeviceReady, false);
let myMedia = null;let mediaTimer = null; // For updating playback position, not used in this basic example// 用于更新播放位置,在本基本示例中未使用const audioFilePath = 'audio/sound.mp3'; // Relative path within www folder// www 文件夹内的相对路径// For Android, files in www are typically accessed via 'file:///android_asset/www/audio/sound.mp3'// 在 Android 上,www 文件夹中的文件通常通过 'file:///android_asset/www/audio/sound.mp3' 访问// The plugin often handles resolving this, but be aware of platform differences for local files.// 插件通常会处理路径解析,但请注意本地文件在不同平台上的差异。
function onDeviceReady() { console.log('Device is ready. Media API available.'); console.log('设备已就绪。Media API 可用。');
document.getElementById('playAudioBtn').addEventListener('click', playAudio); document.getElementById('pauseAudioBtn').addEventListener('click', pauseAudio); document.getElementById('stopAudioBtn').addEventListener('click', stopAudio); document.getElementById('volumeRange').addEventListener('input', setVolume);
// Initialize buttons (optional) // 初始化按钮(可选) document.getElementById('pauseAudioBtn').disabled = true; document.getElementById('stopAudioBtn').disabled = true;}
function updateMediaStatus(statusText) { document.getElementById('mediaStatus').textContent = `Status: ${statusText}`; document.getElementById('mediaStatus').textContent = `状态: ${statusText}`; console.log(`Media Status: ${statusText}`); console.log(`Media 状态: ${statusText}`);}
// Media object success callback// Media 对象成功回调函数function mediaSuccess() { updateMediaStatus('Action successful.'); updateMediaStatus('操作成功。');}
// Media object error callback// Media 对象错误回调函数function mediaError(error) { updateMediaStatus(`Error: Code ${error.code}, Message: ${error.message}`); updateMediaStatus(`错误: 错误码 ${error.code}, 消息: ${error.message}`); console.error('Media Error:', error); console.error('Media 错误:', error); // Reset UI if playback failed critically // 如果播放发生严重错误,重置 UI if (myMedia) myMedia.release(); // Release resources // 释放资源 myMedia = null; document.getElementById('playAudioBtn').disabled = false; document.getElementById('pauseAudioBtn').disabled = true; document.getElementById('stopAudioBtn').disabled = true;}
// Media object status callback (optional)// Media 对象状态回调函数(可选)function mediaStatusCallback(status) { if (status === Media.MEDIA_STARTING) updateMediaStatus('Starting...'); if (status === Media.MEDIA_STARTING) updateMediaStatus('正在启动...'); if (status === Media.MEDIA_RUNNING) updateMediaStatus('Playing...'); if (status === Media.MEDIA_RUNNING) updateMediaStatus('正在播放...'); if (status === Media.MEDIA_PAUSED) updateMediaStatus('Paused.'); if (status === Media.MEDIA_PAUSED) updateMediaStatus('已暂停。'); if (status === Media.MEDIA_STOPPED) { updateMediaStatus('Stopped.'); updateMediaStatus('已停止。'); // When playback finishes naturally or is stopped, release resources and reset UI // 当播放自然结束或被停止时,释放资源并重置 UI if (myMedia) myMedia.release(); myMedia = null; document.getElementById('playAudioBtn').disabled = false; document.getElementById('pauseAudioBtn').disabled = true; document.getElementById('stopAudioBtn').disabled = true; }}
function getMediaSrc() { // On Android, files in the 'www' folder are at 'file:///android_asset/www/'. // 在 Android 上,'www' 文件夹中的文件路径是 'file:///android_asset/www/'。 // On iOS, they are in the app bundle. // 在 iOS 上,它们位于应用程序 bundle 中。 // The plugin usually resolves relative paths correctly for www assets. // 插件通常会正确解析 www 资源的相对路径。 // If playing from other locations (e.g., cordova.file.dataDirectory), provide the full native path. // 如果从其他位置播放(例如,cordova.file.dataDirectory),请提供完整的原生路径。 if (device.platform === "Android") { return '/android_asset/www/' + audioFilePath; } return audioFilePath; // For iOS and browser, relative path often works // 对于 iOS 和浏览器,相对路径通常有效}
function playAudio() { if (myMedia === null) { const src = getMediaSrc(); myMedia = new Media(src, mediaSuccess, mediaError, mediaStatusCallback); console.log(`Playing: ${src}`); console.log(`正在播放: ${src}`); } else { // If paused, resume from current position // 如果已暂停,从当前位置恢复播放 console.log('Resuming playback.'); console.log('正在恢复播放。'); } myMedia.play(); document.getElementById('playAudioBtn').disabled = true; document.getElementById('pauseAudioBtn').disabled = false; document.getElementById('stopAudioBtn').disabled = false;}
function pauseAudio() { if (myMedia) { myMedia.pause(); updateMediaStatus('Paused'); updateMediaStatus('已暂停'); document.getElementById('playAudioBtn').disabled = false; document.getElementById('pauseAudioBtn').disabled = true; }}
function stopAudio() { if (myMedia) { myMedia.stop(); // This will trigger MEDIA_STOPPED status, which handles release. // 这将触发 MEDIA_STOPPED 状态,该状态会处理资源释放。 // No need to call myMedia.release() here if mediaStatusCallback handles it. // 如果 mediaStatusCallback 处理了资源释放,这里无需调用 myMedia.release()。 // UI update is also handled by mediaStatusCallback. // UI 更新也由 mediaStatusCallback 处理。 updateMediaStatus('Stopping...'); // Immediate feedback before async stop completes updateMediaStatus('正在停止...'); // 在异步停止完成前提供即时反馈 }}
function setVolume() { if (myMedia) { const volume = document.getElementById('volumeRange').value; myMedia.setVolume(volume); updateMediaStatus(`Volume set to ${volume}`); updateMediaStatus(`音量设置为 ${volume}`); }}关键 Media 对象方法和概念
Section titled “关键 Media 对象方法和概念”new Media(src, mediaSuccess, mediaError, mediaStatus): 创建一个新的 Media 对象。-
src: 音频文件的 URL。可以是相对路径(从www文件夹开始)、绝对本地文件路径(例如,来自cordova.file.dataDirectory)或远程 URL。
-
mediaSuccess: 可选的回调函数,在操作(播放、暂停、停止、录制)成功完成时执行。
-
mediaError: 可选的回调函数,在发生错误时执行。接收一个包含code和message的MediaError对象。
-
mediaStatus: 可选的回调函数,在媒体播放器状态改变时(例如,正在启动、正在运行、已暂停、已停止)执行。接收一个状态码。
media.play(): 开始或恢复播放音频文件。media.pause(): 暂停播放音频文件。media.stop(): 停止播放音频文件。播放位置通常会被重置。media.release(): 释放底层的操作系统音频资源。当不再需要 Media 对象时,务必调用此方法以释放资源,特别是在播放完成或用户导航离开后。示例中的mediaStatusCallback在处理MEDIA_STOPPED状态时会调用此方法。media.seekTo(milliseconds): 移动播放位置(以毫秒为单位)。media.setVolume(value): 设置音量(0.0 到 1.0)。media.getCurrentPosition(successCallback, errorCallback): 获取当前播放位置(以秒为单位)。media.getDuration(): 获取音频文件的时长(以秒为单位)。如果时长未知,则返回 -1。media.startRecord(): 开始录制音频文件。media.stopRecord(): 停止录制音频文件。
MediaError 错误码
Section titled “MediaError 错误码”mediaError 回调函数接收一个包含 code 属性的对象:
MediaError.MEDIA_ERR_ABORTED (1)MediaError.MEDIA_ERR_NETWORK (2)MediaError.MEDIA_ERR_DECODE (3)MediaError.MEDIA_ERR_NONE_SUPPORTED (4)
最佳实践和注意事项
Section titled “最佳实践和注意事项”- 资源管理: 当您使用完一个
Media对象时,务必调用myMedia.release()以释放原生音频资源。这对于长时间运行的应用程序或播放多个声音的应用程序尤为重要。 - 文件路径: 对文件路径要小心。从
www文件夹开始的相对路径通常很简单。对于www之外的文件(例如,录制的音频、下载的文件),请使用从cordova-plugin-file获取的完整原生 URI(例如,fileEntry.toURL())。 - 错误处理: 鲁棒地实现
mediaError回调函数。 - 状态回调: 使用
mediaStatus回调函数响应播放状态的变化(例如,在播放完成时更新 UI)。 - 多个声音: 如果您需要同时播放多个声音或管理复杂的音频,请考虑此插件是否足够,或者是否需要更高级的音频引擎/库。此插件通常用于更简单、单流的播放/录制。
- 后台播放: 默认情况下,当应用程序进入后台时,音频可能会停止播放。如果需要后台音频,Android 和 iOS 有特定的平台指南和 Cordova 插件选项(如
cordova-plugin-background-mode或特定的媒体播放器配置)。 - 权限: 录制音频需要麦克风权限。插件通常会处理提示用户授权的过程。
有关所有方法、属性和平台特性差异的详细信息,请参阅Cordova Media 插件文档。