前言:
Framework7确实是一个不错的框架,接合Cordova写跨平台应用方便快捷,但其中难免会遇到一些问题,比如:如何支持图片上传。
本文涉及的APP用的是七牛的JS-SDK上传图片,生成、获取七牛对象存储的UPTOKEN不在本文讨论范围之内,需要自己参照官方文档。
准备工作:
- 去Cordova项目路径下,先安装两个插件:
# cordova plugin add cordova-plugin-file # cordova plugin add cordova-plugin-image-picker --variable PHOTO_LIBRARY_USAGE_DESCRIPTION="获取权限时的描述信息"
插件项目主页:
https://github.com/wymsee/cordova-imagePicker
https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-file/
- 引入qiniu.min.js文件到Framework7中。
本文涉及的基本思路是:(可有其他方案,会简便很多)
点击屏幕一个a标签后,开启文件选择框(由项目cordova-imagePicker实现),选择文件后,转换,调用七牛的SDK上传文件(含AJAX请求获取UPTOKEN)。
相关主要代码:
// 以上省略 注意,下文中的app指的是 new Framework7()生成的,如果在template文件中,可由methods下定义的任何一个函数,使用 this.$app 获取该对象。 window.imagePicker.getPictures( function (results) { for (var i = 0; i < results.length; i++) { // results[i] 是本地路径,基本格式为: file:///path/fileName.jpg // key 是用于七牛对象存储的,可以理解为上传以后的文件名 var key = "users/avatar/" + app.utils.id('xxxx-xxxx-xxxx-xxxx') // 此处是用Framework7的utils生成一个ID var putExtra = { fname: "", // 原文件名,可为空 params: {}, // 附带参数 mimeType: [] || null // 允许的文件MIME类型(此处为允许所有) }; var config = { useCdnDomain: true, // 使用CDN域名 region: qiniu.region.z0 // 存储区域 }; var error = function (err) { console.log(err); // err是个对象,里面包含三个属性 app.dialog.alert(err.message, function () { }) }; var next = function (res) { // res里面包括已上传大小(res.total.loaded),总共大小(res.total.total),以及进度(res.total.percent), 详情可参考七牛JS-SDK文档 } var complete = function (response) { console.log(response) } // 上传Token,为了上传七牛服务器的时候,进行验证使用。 // 由自己服务器根据bucket,accessKey,secretKey等生成。 var uptoken = "xxxxxxxxxxxxxxxx" // 开始依据本地路径读取文件,之所以这么做,因为如果直接传入results[i]进入qiniu.upload函数的第一个参数,那么最后上传的只是一个本地路径,并非其文件。 // 此步骤的目的是,读取本地文件,并转换传入 window.resolveLocalFileSystemURL(results[i], function (entry) { entry.file(function (file) { var reader = new FileReader(); reader.onloadend = function () { // this.result 是Base64编码的图片文件,开始Base64至Blob对象。 // 此处感谢 https://www.cnblogs.com/jiujiaoyangkang/p/9396043.html 提供思路。 var arr = this.result.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } var blob = new Blob([u8arr], { type: mime }); // 转换完毕,得到blob。 // 开始调用sdk上传接口获得相应的observable,控制上传和暂停。 // 注意:如果此处函数的第一个参数直接传入this.result,那么去七牛后台查看上传数据的话,会是一个base64编码的文件。 observable = qiniu.upload(blob, key, uptoken, putExtra, config); observable.subscribe({ next: next, // 实时变动 error: error, // 发生错误的时候 complete: complete // 上传完成的时候 }) }; // 以Base64的方式读取 reader.readAsDataURL(file); }) }); } }, function (error) { console.log('Error: ' + error); app.dialog.alert('Error: ' + error) }, { maximumImagesCount: 1, // 每次运行可选择的图片 uality: 50 // 图片质量(最大为100) } ); // 以下省略
以上代码中,是从一个函数中截取出来的,这里面有较大的一部分都在做读取文件,并转换成Blob对象(花了我好长时间去找资料并测试)。
如果用input标签获取到的file对象其实并不需要做这类操作,直接传入qiniu.upload函数就好;但在调试过程中,如果直接使用input标签选择文件,iPhone SE模拟器下每次都引起闪退(Android并未尝试)。据查资料得知,可能是因为布局或版本导致,只不过解决方案并不想深究。