【问题标题】:Cordova video / audio won't play from cdvfile:// urls after update to 3.3.0更新到 3.3.0 后,Cordova 视频/音频将无法从 cdvfile:// url 播放
【发布时间】:2014-02-18 06:35:56
【问题描述】:

我的 Cordova 应用程序从服务器下载音频文件,并在设备离线时让它们可供播放。这一切正常,直到昨天我升级到最新版本。

最初,下载(通过文件传输插件)和播放(通过媒体插件)都不起作用。进一步研究我发现fileSystem.root.fullPath 现在返回一个相对于应用程序本地 Web 根文件夹的路径,但它曾经返回一个完全限定的路径。 Cordova 现在建议改用 fileSystem.root.toURL() (http://cordova.apache.org/news/2014/02/10/plugins-release.html)。这确实解决了文件传输问题。

但是,使用新的 URL 方案不适用于音频文件。尝试播放文件时,我收到一条错误消息 "Cannot use audio file from resource 'cdvfile://localhost/persistent/path/to/file'"

检查 Cordova 问题跟踪器,我发现有人报告了视频文件的相同问题 (https://issues.apache.org/jira/browse/CB-6051)。

Cordova 似乎没有更新 CDVSound 插件来处理新的文件名格式,但如果我可以像以前一样访问完全限定的路径,它可能仍然有效。我查看了新的代码和文档,但没有找到方法。

有没有人设法从文件插件中获得完全合格的路径?

【问题讨论】:

    标签: android ios audio cordova


    【解决方案1】:

    我使用 dev 分支进行文件和文件传输,使其适用于视频。他们在 Entry 类中添加了一个名为 toNativeURL 的函数,您需要从 github 项目中下载 zip 文件:

    https://github.com/apache/cordova-plugin-file-transfer/tree/dev

    https://github.com/apache/cordova-plugin-file/tree/dev

    https://github.com/apache/cordova-plugin-media/tree/dev

    然后将它们安装到您的项目中:

    cordova plugin rm org.apache.cordova.file-transfer
    cordova plugin rm org.apache.cordova.file
    cordova plugin rm org.apache.cordova.media
    
    cordova plugin add <path_to_unzipped_dev_branch_of_file_plugin>
    cordova plugin add <path_to_unzipped_dev_branch_of_file-transfer_plugin>
    cordova plugin add <path_to_unzipped_dev_branch_of_media_plugin>
    

    这是我开始工作的一个例子:

    <!DOCTYPE html>
    <!--
        Licensed to the Apache Software Foundation (ASF) under one
        or more contributor license agreements.  See the NOTICE file
        distributed with this work for additional information
        regarding copyright ownership.  The ASF licenses this file
        to you under the Apache License, Version 2.0 (the
        "License"); you may not use this file except in compliance
        with the License.  You may obtain a copy of the License at
    
        http://www.apache.org/licenses/LICENSE-2.0
    
        Unless required by applicable law or agreed to in writing,
        software distributed under the License is distributed on an
        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
         KIND, either express or implied.  See the License for the
        specific language governing permissions and limitations
        under the License.
    -->
    <html>
        <head>
            <meta charset="utf-8" />
            <meta name="format-detection" content="telephone=no" />
            <!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 -->
            <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
            <link rel="stylesheet" type="text/css" href="css/index.css" />
            <title>Hello World</title>
        </head>
        <body>
            <div id="main" class="app">
                <h1>Apache Cordova</h1>
                <div id="deviceready" class="blink">
                    <p class="event listening">Connecting to Device</p>
                    <p class="event received">Device is Ready</p>
                </div>
                <div id="messages">
                    Loading Video...
                </div>
                <video width="320px" height="240px" controls></video>
            </div>
            <script type="text/javascript" src="cordova.js"></script>
            <script type="text/javascript" src="js/index.js"></script>
            <script type="text/javascript">
                app.initialize();
    
                document.addEventListener("deviceready", onDeviceReady, false);
    
                // device APIs are available
                //
                function onDeviceReady() {
                    console.log('Requesting file system');
                    window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFS, fail);
                }
    
                function gotFS(fileSystem) {
                    fileSystem.root.getDirectory("vids", {create: true}, gotDir);
                }
    
                function gotDir(dirEntry) {
                    dirEntry.getFile("video.mp4", {create: true, exclusive: false}, gotFile);
                }
    
                function gotFile(fileEntry) {
                    var localPath = fileEntry.fullPath;
                    var localUrl = fileEntry.toURL();
    
                    console.log('Loaded local path: ' + localPath);
                    console.log('Loaded local url: ' + localUrl);
    
                    var fileTransfer = new FileTransfer();
                    var uri = encodeURI('http://<url_to_video>.mp4');
                    console.log('Downloading ' + uri + ' to ' + localPath);
    
                    fileTransfer.download(
                        uri,
                        localUrl,
                        function(entry) {
                            console.log('download complete (path): ' + entry.fullPath);
                            console.log('download complete (url): ' + entry.toURL());
                            console.log('download complete (native): ' + entry.toNativeURL());
                            document.getElementById('messages').innerHTML = 
                            'Downloaded Video path: ' + entry.fullPath + '<br />'
                            + 'Downloaded Video url: ' + entry.toURL() + '<br />'
                            + 'Downloaded Video Native url: ' + entry.toNativeURL() + '<br />';
                            var videoNode = document.querySelector('video');
                            videoNode.src = entry.toNativeURL();
                        },
                        function(error) {
                            console.log('download error source ' + error.source);
                            console.log('download error target ' + error.target);
                        }
                    );
                }
    
                function fail(error) {
                    console.log('Error creating file [' + error.name + ']: ' + error.message);
                }
            </script>
        </body>
    </html>
    

    如果它适用于视频,它肯定适用于音频。

    【讨论】:

    • 谢谢大卫。这很有帮助,因为我不确定如何构建新插件。我会接受这个作为答案并对其进行编辑以包含媒体插件。
    • 这很快 :) 当你写这篇文章时,我刚刚合并了该代码。 .toNativeURL 可能是目前
    • 截至今天(2014-03-04),您提到的开发版本已经发布。 File-transfer 0.4.2、File 1.0.1 和 Media 0.2.9 包含这些修复。
    【解决方案2】:

    [Media][1] 和 File 插件的开发分支现在解决了这个问题。如果您可以从 git 安装这些插件,那么从 cdvfile:// URL 播放应该就可以了。

    此代码发布后,我也会在这里发布。

    更新 -- 自 2014 年 3 月 4 日起,媒体和文件的修复程序已发布。文件 1.0.1 和媒体 0.2.9 协同工作以播放来自 cdvfile URL 的音频。

    【讨论】:

    【解决方案3】:

    我仍然没有获得完全合格路径的答案,但我决定破解 iOS 插件,直到 Cordova 提供适当的修复。 (至少我现在可以继续开发。)

    以下代码取自 file-transfer 插件,可以添加到 CDVSound.m 以允许媒体插件使用新的 cdvfile:// 路径播放音频文件,仅限 iOS。 请注意,我之前从未写过一行 ObjC,而且代码几乎没有经过测试。在 Cordova 修补当前插件之前,这是一个临时修复。

    #import "CDVSound.h"
    #import "CDVFile.h"    <-- add
    #import <Cordova/NSArray+Comparisons.h>
    ...
    #define RECORDING_WAV @"wav"
    #define CDVFILE_PREFIX @"cdvfile://"  <-- add
    
    extern CDVFile *filePlugin;   <-- add
    
    @implementation CDVSound
    ...
        filePath = [resourcePath stringByReplacingOccurrencesOfString:DOCUMENTS_SCHEME_PREFIX withString:[NSString stringWithFormat:@"%@/", docsPath]];
        NSLog(@"Will use resource '%@' from the documents folder with path = %@", resourcePath, filePath); 
    <--- insert this block here --->
    } else if ([resourcePath hasPrefix:CDVFILE_PREFIX]) {
        CDVFilesystemURL *fsURL = [CDVFilesystemURL fileSystemURLWithString:resourcePath];
        if (fsURL && fsURL.fileSystemName != nil) {
            // This requires talking to the current CDVFile plugin
            NSObject<CDVFileSystem> *fs = [filePlugin filesystemForURL:fsURL];
            if ([fs respondsToSelector:@selector(filesystemPathForURL:)]) {
                filePath = [fs filesystemPathForURL:fsURL];
                NSLog(@"Will use resource '%@' from the documents folder with path = %@", resourcePath, filePath);
            }
            else {
                resourceURL = fsURL.url;
            }
        }
        else {
            NSLog(@"Unknown resource '%@'", resourcePath);
        }
    <--- to here --->
    } else {
        // attempt to find file path in www directory or LocalFileSystem.TEMPORARY directory
    

    【讨论】:

    • 我同意将其视为黑客和临时修复;媒体插件绝对应该更新以使用新版本的文件。
    • 另外,如果你要使用这样的东西,那么我会保护[fs filesystemPathForURL:fsURL] 调用并检查if ([fs respondsToSelector:@selector(filesystemPathForURL:)]),因为它是文件系统协议的可选方法。并非所有文件 url 都映射到磁盘上的物理位置。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多