最近在做的 h5 应用主要在原生 APP 的 WebView 中运行,测试中发现以下两个问题在在 web 端难以解决,所以由原生 APP 提供接口处理:
- 安卓系统中,调用相册选择图片时偶现触发 WebView 崩溃,进而导致 App 闪退
- 安卓系统中,拉起键盘时页面没有上移,导致底部输入框被遮挡,无法看到输入内容
相册图片选择处理
对于图片选择,web 端使用的 vant ui 的 uploader 组件,内部实现即为
<input type=file>
决定改为调用外部 App 提供的接口,由 App 调用系统原生相册选择图片并返回。这里因为 h5 接入了公司多个不同的项目,针对 App 提供接口的方式主要有两种接入方法(实现相同,都是通过与 App 通信,调用原生获取权限选择图片,再通过回调返回图片数据给 h5)
方法1:
- App 提供的接口调用函数和 h5 需要回调函数都注入 window 对象里;
- 在 h5 里调用接口函数,并将回调函数名作为参数传入;
- App 收到后拉起相册选择图片,将图片二进制流作为参数调用回调函数;
- h5 等待回调函数被调用后拿到图片数据,生成 url 在页面展示,生成 file 对象作为参数调用 web 后端图片上传接口。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const fn = () => { // 等待外部 App 选择图片后在调用回调函数,放在 Promise 中
return new Promise((resolve) => {
window._uploadCallback = (data) => { // 外部 App 调用回调函数时将图片数据作为参数传入
resolve(data)
}
window?.cocos?.someFunctionProvideByApp( // 该方法由 App 提供,用来拉起系统原生相册选择图片
'_uploadCallback'
)
})
}
const onImageUpload = async () => {
const b = await fn() // 触发图片选择后,调用外部 App 提供的接口,并等待返回图片数据
const array = []
for (let i in b) {
array[i] = b[i]
}
const buffer = new ArrayBuffer(array.length)
const buffer2 = new Uint8Array(buffer)
for (let i = 0; i < array.length; i++) {
buffer2[i] = array[i]
}
const data = new Blob([buffer2])
const imgUrl = window.URL.createObjectURL(data) // 图片链接,在页面中展示
const file = new window.File([data], 'name') // file 对象,可作为参数调用 web 后端接口
const form = new FormData()
form.append('file', file)
}
...
<template>
<div @click="onImageUpload">上传按钮</div>
</template>
方法2:公司部分项目使用 flutter 开发,对 h5 接入比较友好,接口封装程度更高一点,直接提供异步接口返回数据
1
2
3
4
5
6// 1. 引入bridge.js,其中导出 appUploadImg 方法用于调用相册获取图片
// 2.
import Bridge from './bridge'
const imageData = await Bridge.appUploadImg()
// 获取二进制数据后同方法1相同处理方式
...
键盘遮挡输入框处理
- 首先尝试使用
scrollIntoView
处理,未生效 - 调用键盘时由外部 App 获取键盘高度,并触发 h5 定义在 window 上的事件,传入键盘高度;h5 拿到键盘高度后调整输入框位置
- h5 内在输入框 focus 时开始等待返回值,在 blur 时把输入框移回原位
- 要注意系统键盘可能自带关闭按钮,关闭键盘后 h5 内输入框仍处于 focus 状态,没有恢复位置,这就需要 App 在关闭键盘时通知到 h5
1 | window._getKeyboardTimerid = null // 若存在重复调用问题,可加防抖 |