最近因为公司有个小程序的项目需求是让用户上传本地文件(使用uni-app开发),查阅了小程序的api,发现小程序只开放了两个相应的api

API

wx.chooseImage(Object object)

从本地相册选择图片或使用相机拍照

wx.chooseMessageFile(Object object)

从客户端会话选择文件(注意:从客户端会话选择文件是指从微信聊天里选择对应的文件)

因为这两个API都不能实现项目需求,所以在查阅了相应的资料后,发现目前只能走一条路:使用webview实现文件上传

强烈推荐:如果要把文件上传到七牛云或者自有服务服务器的话,可以直接在webview链接的html里直接将文件上传的七牛云(通过七牛云JSSDK上传)或自有服务器(通过axios上传),再把返回的key,hash值或者后端返回的链接传递给小程序,没有必要再去把文件转base64,具体可参考以下两篇文章

uni-app使用webview上传文件(自有服务器版本)uni-app 使用webview上传文件(七牛云版本)

注意点:微信小程序的webview是不支持加载本地的html,所以只能将html文件部署在服务器上来加载(页面可以先本地写好,然后使用vscode的ssh连接服务器,一边修改一边调试)

微信小程序 如何上传图片到springboot 微信小程序webview上传图片_html页面

整体的思路

微信小程序 如何上传图片到springboot 微信小程序webview上传图片_uni-app_02

webview使用过程中的注意点

基础库版本

选择2.16.0 ,选择2.14版本会报错

微信小程序 如何上传图片到springboot 微信小程序webview上传图片_uni-app_03

小程序跳转到webview页面会造成本地存储丢失

因为在跳转到webview页面的时候,小程序会关闭,这个时候是会清空本地存储的,所以在webview跳转回小程序的时候,是无法调用到之前存储在本地的数据的,而且小程序是无法使用cookie的,所以只能把数据传递到webview链接的html页面,然后再从html页面中传递回来

webview链接的hmtl页面传递回来的数据类型

webview链接的html页面使用 uni.postMessage API传递数据的时候只能传递字符串

webview的使用

关于webview的使用以及通信,uni-app官方有对应的文档,可以查看:

webvie官方文档

在web-view加载的本地及远程HTML中调用uni的API及网页和vue页面通讯

引入sdk

<!-- 微信 JS-SDK 如果不需要兼容小程序,则无需引用此 JS 文件。 -->  
<script type="text/javascript" src="//res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>  
<!-- uni 的 SDK,必须引用。 -->  
<script type="text/javascript" src="//js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.0.1.52.js"></script>

调用时机

document.addEventListener('UniAppJSBridgeReady', function() {  
    uni.getEnv(function(res) {  
        console.log('当前环境:' + JSON.stringify(res));  
    });  
});

传递信息

uni.postMessage 中的参数格式,必须是 data: {}。也就是说,传递的消息信息必须在 data 这个对象中。

document.addEventListener('UniAppJSBridgeReady', function() {  
    uni.postMessage({  
        data: {  
            action: 'postMessage'  
        }  
    });  
});

vue页面(小程序)向html页面(webview)传递数据

通过url传参 : http://www.yemengshen.cn/main?id=123&token=jakdjfjkjad89jjdkk

html页面解析参数

// 获取小程序传递过来的参数
function getUrlParam(name) {
   var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)")
   var r = window.location.search.substr(1).match(reg)
   if (r != null) return unescape(r[2])
   return null
}

// 调用
var id = getUrlParam('id')
var token = getUrlParam('token')

html页面(webview)向vue页面(小程序)发送数据

因为只能传递字符串所以需要对文件对象转换成base64

// 需要传递多个参数可以进行字符串拼接或者多次调用该api
 uni.postMessage({  
        data: {  
            action: 'postMessage'  
        }  
 });

// 文件转base64
function fileToBase64(file) {
    return new Promise(function(resolve, reject) {
        var reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = function() {
            typeof reader.result === 'string' && resolve(reader.result) || reject();
        };
        reader.onerror = function(error) { return reject(error); };
    });
};

关于文件转换成base64格式的包(公司的大佬封装好的):文件转base64包

vue页面(小程序)接收 html页面(webview)传递的数据

每次执行 postMessage 后,传递的消息会以数组的形式存放。因此,在 web-view 的 message 事件回调中,接收到的 event.detail.data 的值是一个数组。

另外需要注意的是 @message事件的触发时机:网页向小程序 postMessage 时,会在特定时机(小程序后退、组件销毁、分享)触发并收到消息。在执行postMessage时,@message的事件是不会马上执行的,也就是说它不是实时通讯,只有在触发了小程序后退、组件销毁、分享这三种情况之一才会接收到postMessage传递过来的参数

处理思路

以后退为例(后退是指小程序的页面后退)

微信小程序 如何上传图片到springboot 微信小程序webview上传图片_uni-app_04

<template>  
    <view>  
        <web-view src="http://192.168.1.1:3000/test.html" @message="handleMessage"></web-view>  
    </view>  
</template>  

<script>  
    export default {  
        methods: {  
            handleMessage(evt) { 
            		
                console.log('接收到的消息:' + JSON.stringify(evt.detail.data));  
            }  
        }  
    }
</script>