You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cordova安卓应用播放内部存储Music目录音频文件问题求助

版本信息

  • Cordova版本:12.0.0
  • cordova-media-plugin版本:7.0.0
  • cordova-plugin-file版本:8.1.0
  • cordova-plugin-file-transfer版本:2.0.0
  • cordova-plugin-wkwebview-file-xhr版本:3.1.1
  • Android目标SDK:34

问题与疑问

我正在尝试让基于Cordova的安卓应用播放下载到设备内部存储/Music目录的音频文件,downloadAudio函数可以正常将文件保存到该目录(尽管文件插件文档称该位置为SD卡,但实际设备并非如此),存在以下疑问:

  1. media插件能否从file:///storage/emulated/0/Music/[file].mp3路径播放音频?似乎需要cdvfile格式路径,但不确定cdvfile是否支持该外部位置,怀疑它仅适用于应用内部路径?
    编辑: 若引用无效路径会提示文件不存在,无此错误说明media插件可识别文件,但修正语法错误后出现“Code 1, Prepare failed.: status=0x1”错误,相关讨论虽有关联但无法理解。
  2. 无法使用URL转换方法(如toURL返回TypeError: fileTransferInternalUrl.toURL is not a function)生成适用于media插件的cdvfile路径,均报错。
    编辑: 尽管toURL无效,但文件URL似乎可正常工作。
  3. 若media插件不支持播放应用外部路径的音频,能否使用copyTo(覆盖已有文件)将外部文件复制到media插件可访问的应用临时内部目录?(新版文件插件文档中copyTo的文档缺失,使用时也报错,若可行可提供更多细节)
    尝试过相关方案及官方示例均无效。
    未收到权限相关错误,若存在权限问题,下载功能应无法正常工作(了解安卓权限有变更)。

更新(2024/10/8)

按建议修改toURL后可返回URL,但出现以下错误,似乎media播放器无法使用该URL:
Media播放器错误:Code 1, AudioPlayer.onError(1, -2147483648) [未知错误]
控制台错误:

java.net.ConnectException: Failed to connect to localhost/127.0.0.1:443
at com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:147)
at com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:116)
at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:186)
at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:128)
at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:97)
at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:289)
at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:232)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:465)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:411)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:542)
at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getResponseCode(DelegatingHttpsURLConnection.java:106)
at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:30)
at android.media.MediaHTTPConnection.seekTo(MediaHTTPConnection.java:306)
at android.media.MediaHTTPConnection.getMIMEType(MediaHTTPConnection.java:499)
at android.media.IMediaHTTPConnection$Stub.onTransact(IMediaHTTPConnection.java:161)
at android.os.Binder.execTransactInternal(Binder.java:1220)
at android.os.Binder.execTransact(Binder.java:1179)

附带函数代码:

function downloadAudio (fileTransferWebUrl,thisElement) {
    fileTransferWebUrl = encodeURI(fileTransferWebUrl);
    if (isAndroidApp == true) {
        var fileNameMP3Array = fileTransferWebUrl.split("/");
        var fileNameMP3 = fileNameMP3Array[fileNameMP3Array.length-1]; //get file name from web URL
        fileTransferInternalUrl = cordova.file.externalRootDirectory + 'Music/' + fileNameMP3; //  file:///storage/emulated/0/Music/[file].mp3
    }
    try {
        fileTransfer.download(
            fileTransferWebUrl, 
            fileTransferInternalUrl, 
            function (entry) {
                alert('Download complete to Music/' + fileNameMP3);
            },
            function(error){ //error
                alert("Download error source " + error.source + " download error target " + error.target + " download error code " + error.code + " http_status " + error.http_status + " body " + error.body + " exception " + error.exception);
            },
            true, //trust all hosts. safer to be false, set to true accepts all security certificates, not recommended for production use
        );
    }
    catch (e) {
        alert(e);
    }
}

function playDownloadedAudio (fileTransferWebUrl, thisElement) {
    var nativePath = "";
    fileTransferWebUrl = encodeURI(fileTransferWebUrl);
    if (isAndroidApp == true) {
        var fileNameMP3Array = fileTransferWebUrl.split("/");
        var fileNameMP3 = fileNameMP3Array[fileNameMP3Array.length-1]; //get file name from web URL
        fileTransferInternalUrl = cordova.file.externalRootDirectory + 'Music/' + fileNameMP3; //cordova.file.externalRootDirectory
        alert(fileTransferInternalUrl); // file:///storage/emulated/0/Music/A_casa_vete_y_cuenta_alli.mp3
    }
    resolveLocalFileSystemURL(cordova.file.dataDirectory + fileNameMP3, function (entry) {
        nativePath = entry.toURL(); 
        console.log("cordova.file.dataDirectory + fileNameMP3 = " + cordova.file.dataDirectory + fileNameMP3 + " | nativePath = " + nativePath);
        if (my_media != null) { 
            my_media.release(); // clean up old file
        }
        my_media = new Media(nativePath,
            function () //success;
            { }, 
            function (error) //error
            { 
                alertOK(translate('Error in playback. Please contact support. \n Code: ','text') + error.code + '\n '+translate('Message:','text')+' '+error.message + '\n');
                playing = false;
            }
        );
        my_media.play();
    });
}

AndroidManifest.xml权限配置:

<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />

Config.xml配置:

<?xml version='1.0' encoding='utf-8'?>
<widget id="com.hablamedecristo.himnario2" version="6.9.0" versionCode="77" xmlns="http://www.w3.org/ns/widgets" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:cdv="http://cordova.apache.org/ns/1.0">
    <name>Himnos del Evangelio</name>
    <description>
        Himnario "Himnos del Evangelio" de cristianos congregados en el Nombre del Señor Jesucristo en Venezuela.
    </description>
    <author email="himnosdelevangelio@gmail.com" href="http://salvoxgracia.com/himnarioapp/">
        My Site Creations, AguaDeLaVida.info
    </author>
    <content src="index.html" />
    <preference name="android-installLocation" value="preferExternal" />
    <preference name="AndroidPersistentFileLocation" value="Compatibility" /> <!-- use "Internal" instead of "Compatibility" for new apps -->
    <preference name="android-targetSdkVersion" value="34" />
    <preference name="android-compileSdkVersion" value="34" />
    <preference name="android-minSdkVersion" value="23" />
    <preference name="AndroidGradlePluginVersion" value="8.5.1" />
    <preference name="loadUrlTimeoutValue" value="700000" />
    <plugin name="cordova-plugin-media" spec="7.0.0" />
    <plugin name="cordova-plugin-insomnia" />
    <plugin name="cordova-plugin-file" />
    <plugin name="cordova-plugin-email-composer" />
    <plugin name="cordova-plugin-wkwebview-file-xhr" spec="3.1.1" />
    <plugin name="cordova-plugin-file-transfer" />
    <icon src="icon.png" />
    <allow-navigation href="*" />
    <access origin="*" />
    <access origin="file:///*" />
    <access origin="cdvfile://*" />
    <allow-intent href="file:///*" />
    <allow-intent href="cdvfile://*" />
    <allow-intent href="http://*/*" />
    <allow-intent href="https://*/*" />
    <allow-intent href="mailto:*" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <!-- not sure if these are needed  https://developer.android.com/training/data-storage/shared/media#kotlin
    <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
    -->
    <platform name="android">
        <edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application">
            <application android:usesCleartextTraffic="true" />
        </edit-config>
        <allow-intent href="market:*" />
        <!-- <preference name="AndroidWindowSplashScreenAnimatedIcon" value="res/screen/android/splashscreen.xml" /> -->
        <preference name="FadeSplashScreenDuration" value="0"/>
        <preference name="SplashScreenDelay" value="0" />
        <preference name="AndroidWindowSplashScreenBackground" value="#9D9D9C" />
    </platform>
    <platform name="ios">
        <allow-intent href="itms:*" />
        <allow-intent href="itms-apps:*" />
    </platform>
</widget>

内容的提问来源于stack exchange,提问作者Nathan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 12:59:52