博客 RSS Feed

停止使用 cordova-plugin-file-transfer
作者:Fil Maj
2017 年 10 月 18 日

在 Cordova 早期,创建了 file-transfer 插件来解决下载二进制文件的问题。当时,没有很好的方法可以使用符合标准的 Web API 来解决这个问题。Web 经历了一段曲折的道路才找到解决方案(参见 Firefox 的 sendAsBinary 和现已废弃的 FileSystem APIBlobBuilder 等),但是现在你可以使用我们的好朋友 XMLHttpRequest 的最新功能,结合一些较新的 JavaScript 类型和对象,来解决这个问题。对于 Cordova 来说,这是一个令人兴奋的时刻,因为该项目的梦想一直是最终减少项目维护的 API 表面积,而是看到常规的 Web API 能够处理这些用例。

因此,Cordova 正在逐步淘汰 file-transfer 插件。“逐步淘汰”是什么意思?总结一下:

  • Cordova 开发社区将不再对 file-transfer 插件进行任何工作。
  • 如果你愿意,可以继续使用 file-transfer 插件 - 在可预见的未来,它应该可以正常工作。
  • 我们强烈建议 Cordova 用户过渡到使用符合标准的发送和接收二进制数据的方式

我们 Apache Cordova 的所有人都希望帮助大家,因此我们认为展示如何使用这些较新的 XHR 功能来完成 file-transfer 允许你执行的操作,并且以一种可以在任何现代 Web 浏览器中启动的方式,这将是一个好主意!

要求

根据你与底层设备文件系统的交互深度以及在哪些平台上,你可能仍然需要依赖Cordova File 插件。如果你的应用程序的 JavaScript 中仍然引用了 requestFileSystemroot.fs,那么你肯定需要 File 插件,因为这些不是符合标准的 API。请注意并小心!

平台支持

JavaScript 中的二进制类型以及扩展的 XHR 功能可在以下 Cordova 支持的平台上使用,而无需任何额外的插件:

  • Android 4.4 或更高版本。
  • iOS 10 或更高版本。
  • Windows UWP(8.1、10 或更高版本均可)。
  • Windows Phone 8 或更高版本。

与往常一样,请查看 caniuse.com 以获取所需位的详细支持,例如 BlobTyped Arrays扩展的 XHR 功能

总结

标准很好,但是你实际上必须复制粘贴什么来替换以前的 FileTransfer 示例?我们为您准备好了

这是对 FileTransfer 的“将二进制文件下载到应用程序缓存”示例的替换

window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {
    console.log('file system open: ' + fs.name);
    fs.root.getFile('bot.png', { create: true, exclusive: false }, function (fileEntry) {
        console.log('fileEntry is file? ' + fileEntry.isFile.toString());
        var oReq = new XMLHttpRequest();
        // Make sure you add the domain name to the Content-Security-Policy <meta> element.
        oReq.open("GET", "https://cordova.net.cn/static/img/cordova_bot.png", true);
        // Define how you want the XHR data to come back
        oReq.responseType = "blob";
        oReq.onload = function (oEvent) {
            var blob = oReq.response; // Note: not oReq.responseText
            if (blob) {
                // Create a URL based on the blob, and set an <img> tag's src to it.
                var url = window.URL.createObjectURL(blob);
                document.getElementById('bot-img').src = url;
                // Or read the data with a FileReader
                var reader = new FileReader();
                reader.addEventListener("loadend", function() {
                   // reader.result contains the contents of blob as text
                });
                reader.readAsText(blob);
            } else console.error('we didnt get an XHR response!');
        };
        oReq.send(null);
    }, function (err) { console.error('error getting file! ' + err); });
}, function (err) { console.error('error getting persistent fs! ' + err); });

这是对 FileTransfer 的“上传文件”示例的类似替换

window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {
    console.log('file system open: ' + fs.name);
    fs.root.getFile('bot.png', { create: true, exclusive: false }, function (fileEntry) {
        fileEntry.file(function (file) {
            var reader = new FileReader();
            reader.onloadend = function() {
                // Create a blob based on the FileReader "result", which we asked to be retrieved as an ArrayBuffer
                var blob = new Blob([new Uint8Array(this.result)], { type: "image/png" });
                var oReq = new XMLHttpRequest();
                oReq.open("POST", "http://mysweeturl.com/upload_handler", true);
                oReq.onload = function (oEvent) {
                    // all done!
                };
                // Pass the blob in to XHR's send method
                oReq.send(blob);
            };
            // Read the file as an ArrayBuffer
            reader.readAsArrayBuffer(file);
        }, function (err) { console.error('error getting fileentry file!' + err); });
    }, function (err) { console.error('error getting file! ' + err); });
}, function (err) { console.error('error getting persistent fs! ' + err); });

请注意,以上两个示例都依赖于 File 插件,因此如果从你的应用程序中删除 FileTransfer 插件,请确保添加 File 插件!

长版本

如果你想了解一些实现二进制数据传输的细节,你需要掌握两个(可能三个)概念。MDN 有一篇非常精彩的文章,值得快速阅读,但我也将在此处提供摘要。

JavaScript 中的二进制类型

长期以来,没有办法在 JavaScript 中直接表示二进制数据并访问内存中的底层字节。我们可以使用不同的格式(base64,有人吗?)对这些数据进行编码,这很酷,但是让我直接操作字节。就我们的目的而言,我们特别关注两个对象:ArrayBufferBlob。为什么我们关心这两个?因为我们可以让 XHR 将下载的数据作为这些类型返回,或者将这些类型直接传递给 XHR 的 send 方法。

XHR

我们需要利用两个较新的 XHR 功能,最初是作为“XHR2”的一部分,在其开发期间,以将所有这些结合在一起。

对于下载二进制数据,我们需要将 responseType 属性设置为 arraybufferblob - 这告诉 XHR 我们希望返回的数据类型。设置 responseType 后,我们可以访问只读的 response 属性,以获取表示 XHR 检索的数据的 ArrayBufferBlob 对象。

对于上传二进制数据,它更简单:将 BlobArrayBuffer 直接传递给 XHR 的 send 方法。就是这样。

总结

二进制类型和扩展的 XHR 功能在现代桌面浏览器以及最近的移动浏览器(和 WebView)中得到很好的支持。对于现有的 Cordova 用户,只要你的应用程序的目标平台和操作系统版本组合在上面“平台支持”下列出,你就可以顺利使用!请记住,如果你依赖某些 File 插件 API(例如 requestFileSystemrootgetFile),则需要确保将 File 插件添加到你的应用程序中。

祝你使用符合标准的编码愉快!