在 Cordova 早期,创建了 file-transfer 插件来解决下载二进制文件的问题。当时,没有很好的方法可以使用符合标准的 Web API 来解决这个问题。Web 经历了一段曲折的道路才找到解决方案(参见 Firefox 的 sendAsBinary
和现已废弃的 FileSystem API 的 BlobBuilder 等),但是现在你可以使用我们的好朋友 XMLHttpRequest 的最新功能,结合一些较新的 JavaScript 类型和对象,来解决这个问题。对于 Cordova 来说,这是一个令人兴奋的时刻,因为该项目的梦想一直是最终减少项目维护的 API 表面积,而是看到常规的 Web API 能够处理这些用例。
因此,Cordova 正在逐步淘汰 file-transfer 插件。“逐步淘汰”是什么意思?总结一下:
- Cordova 开发社区将不再对 file-transfer 插件进行任何工作。
- 如果你愿意,可以继续使用 file-transfer 插件 - 在可预见的未来,它应该可以正常工作。
- 我们强烈建议 Cordova 用户过渡到使用符合标准的发送和接收二进制数据的方式。
我们 Apache Cordova 的所有人都希望帮助大家,因此我们认为展示如何使用这些较新的 XHR 功能来完成 file-transfer 允许你执行的操作,并且以一种可以在任何现代 Web 浏览器中启动的方式,这将是一个好主意!
要求
根据你与底层设备文件系统的交互深度以及在哪些平台上,你可能仍然需要依赖Cordova File 插件。如果你的应用程序的 JavaScript 中仍然引用了 requestFileSystem
或 root.fs
,那么你肯定需要 File 插件,因为这些不是符合标准的 API。请注意并小心!
平台支持
JavaScript 中的二进制类型以及扩展的 XHR 功能可在以下 Cordova 支持的平台上使用,而无需任何额外的插件:
- Android 4.4 或更高版本。
- iOS 10 或更高版本。
- Windows UWP(8.1、10 或更高版本均可)。
- Windows Phone 8 或更高版本。
与往常一样,请查看 caniuse.com 以获取所需位的详细支持,例如 Blob
、Typed 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,有人吗?)对这些数据进行编码,这很酷,但是让我直接操作字节。就我们的目的而言,我们特别关注两个对象:ArrayBuffer 和 Blob。为什么我们关心这两个?因为我们可以让 XHR 将下载的数据作为这些类型返回,或者将这些类型直接传递给 XHR 的 send
方法。
XHR
我们需要利用两个较新的 XHR 功能,最初是作为“XHR2”的一部分,在其开发期间,以将所有这些结合在一起。
对于下载二进制数据,我们需要将 responseType
属性设置为 arraybuffer
或 blob
- 这告诉 XHR 我们希望返回的数据类型。设置 responseType
后,我们可以访问只读的 response
属性,以获取表示 XHR 检索的数据的 ArrayBuffer
或 Blob
对象。
对于上传二进制数据,它更简单:将 Blob
或 ArrayBuffer
直接传递给 XHR 的 send
方法。就是这样。
总结
二进制类型和扩展的 XHR 功能在现代桌面浏览器以及最近的移动浏览器(和 WebView)中得到很好的支持。对于现有的 Cordova 用户,只要你的应用程序的目标平台和操作系统版本组合在上面“平台支持”下列出,你就可以顺利使用!请记住,如果你依赖某些 File 插件 API(例如 requestFileSystem
、root
或 getFile
),则需要确保将 File 插件添加到你的应用程序中。
祝你使用符合标准的编码愉快!