最近在开发中遇到一个问题,要在APP内嵌的H5页面中实现拍照录像并上传到后端服务器。

刚开始我直接想到:

<input type="file" accept="image/*" capture="camera">

由于项目用vant UI,于是用了Uploader文件上传组件,大家可自行查看实现方法:https://youzan.github.io/vant/#/zh-CN/uploader。这种方法在浏览器上使用没有毛病,可是嵌入APP后却出现只能打开相册不能打开相机的问题,加上产品经理想拍照后还可以对照片进行编辑,这是H5直接调用相机所不具备的。于是与原生APP开发的同事沟通后,决定采用调用安卓相机的方案。

首先在页面上写一个按钮,

<van-button icon="photograph" type="primary" @click="appPhotograph" native-type="button" />

点击按钮去调用安卓的方法,实现打开摄像头:

methods: {
    appPhotograph() {
         window.Android.takePicture() // 安卓提供的打开摄像头方法,此方法要安卓开发提供
    },
}

这个时候实现了打开摄像头并拍照,对图片进行编辑等功能,下一步就是要解决H5这边如何进行图片上传。

我们知道通过input  type=file 实现的拍照我们是可以拿到文件流的,然后再把这个文件流传给后端,就实现了文件上传,所以接着我们就要拿到安卓那边的文件流。于是安卓那边又提供了一个返回文件的方法: takePictureCallBack(),直接上代码吧:
 

takePictureCallBack(content, name, path, size) { // 获取base64图片,安卓开发提供
    let src = `data:image/jpeg;base64,${content}` // 由于content内容没有data:image/jpeg;base64,所以拼接上,如果你的已经有了就无需拼接
    let file = this.base64toFile(src)
    let fileData = new FormData()
    fileData.append('file', file)
    fileData.append('tenantId', 'prosCenter') // 上传文件附带的参数,请根据你的业务需求而定,若无请忽略
    upLoadFileApi(fileData).then(res => { // 调用文件上传接口,请自行封装
        // 这里放上传成功的业务处理
        Notify({ type: 'success', message: '上传成功' });
        let fileObj = res.datas
        this.forms.attachmentsList.push(fileObj) // 将上传后的文件显示在页面上,请根据你的业务需求而定,this.forms.attachmentsList数组请自行定义
    }).catch(error => {
        Notify({ type: 'warning', message: '上传失败' });
    })
},
base64toFile (dataurl, filename = 'file') { // 将base64格式转为file文件流
    let arr = dataurl.split(',')
    let mime = arr[0].match(/:(.*?);/)[1]
    let suffix = mime.split('/')[1]
    let bstr = atob(arr[1])
    let n = bstr.length
    let u8arr = new Uint8Array(n)
    while (n--) {
        u8arr[n] = bstr.charCodeAt(n)
    }

    return new File([u8arr], `${filename}.${suffix}`, {
        type: mime
    })
},

解释一下以上代码,由于安卓开发同事那边说无法直接将文件通过file格式传过来,于是通过base64格式传,所以我们拿到的base64格式还要转成file格式,才能上传到服务器上。

       这里有一点要注意,这种没有通过类似点击这样的动作调用的方法,我们要把它挂载在window下面,否则会无法调用:

mounted() {
    window.takePictureCallBack = this.takePictureCallBack;
}

磕磕碰碰了许久,终于实现了产品想要的功能,在此分享给遇到同样问题的前端开发工程狮们。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐