【原】Framework7下打包后的APP支持图片上传(支持七牛)

前言:

Framework7确实是一个不错的框架,接合Cordova写跨平台应用方便快捷,但其中难免会遇到一些问题,比如:如何支持图片上传。

本文涉及的APP用的是七牛的JS-SDK上传图片,生成、获取七牛对象存储的UPTOKEN不在本文讨论范围之内,需要自己参照官方文档

准备工作:

  1. 去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/

  2. 引入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并未尝试)。据查资料得知,可能是因为布局或版本导致,只不过解决方案并不想深究。