相关工具

  • http://debugtbs.qq.com (腾讯 x5内核调试地址)
  • chrome://inspect (Chrome 调试地址,可调试远程 WebView)
  • scrcpy (基于 adb,可在桌面上显示、操作手机)

问题描述

在上传图片的页面,页面第一次加载完后可以正常打开选择图片, 选完之后再点击上传就没反应了,或者取消选择后也不能再次选择 (后面试了下 IOS 系统,没有这种问题)

android File 文件下载后打开 androidfilechooser_webview


这是一个基于 uni-app 开发的 Web 项目, 安卓 APP 使用了腾讯的 x5 内核来代替原生的 WebView

排查思路

核对从 Web 到安卓的交互过程,先查看 Web 页面上传的逻辑

chooseTheImg() {
  uni.chooseImage({
    count: 1, //图片可选择数量
    sizeType: ['original', 'compressed'], //original 原图,compressed 压缩图,默认二者都有
    sourceType: ['album'], //album 从相册选图,camera 使用相机,默认二者都有。
    success: res => {
      let imgFiles = res.tempFilePaths //图片的本地文件路径列表
      this.uploadTheImg(imgFiles)
      this.$forceUpdate()
    }
  })
}

这里使用了 uni.chooseImage ,似乎没什么问题,再到 uni-app 源码中搜索 chooseImage,看一下它的实现

export function chooseImage ({
  count,
  // sizeType,
  sourceType
}, callbackId) {
  // TODO handle sizeType 尝试通过 canvas 压缩

  if (imageInput) {
    document.body.removeChild(imageInput)
    imageInput = null
  }

  imageInput = _createInput({
    count: count,
    sourceType: sourceType
  })
  document.body.appendChild(imageInput)
  // ignore...
  imageInput.click()
}

可以看到,它是在 body 内追加 input 框来实现的文件选择,触发方式是调用 api 时,也同步调用一次 input 的 click 方法,这个可以到 chrome://inspect 页面中操作观察一下

android File 文件下载后打开 androidfilechooser_java_02


按描述中的步骤操作,很容易复现这个问题,即使由我们自己手动再调用 click 方法,甚至再手动添加个 input 框来测试,也一样有问题。到此,确定应该是安卓端的问题,接下来就是排查一下安卓的逻辑

// For Android > 5.0
@Override
public boolean onShowFileChooser(com.tencent.smtt.sdk.WebView webView,
  com.tencent.smtt.sdk.ValueCallback<Uri[]> uploadMsg, FileChooserParams fileChooserParams) {
  //...
  if (needCallback && uploadMsg != null) {
    uploadMsg.onReceiveValue(null);
  }
  return true;
}

打一个 debug 包,断点调试,可以看到,点击上传后, 首次能进到这个方法,但后续都进不来, 结合这些关键信息,和 x5 手册里的指导,搜索一些资料做下参考


android File 文件下载后打开 androidfilechooser_webview_03


最后确认,这个问题也是上面的 ValueCallback 没有手动回调的原因,加上之后问题解决

附记

几天之后,测试人员又提了这个bug,说是在弹出授权的场景下,还会复现。 鉴于之前看过这里面的逻辑,知道其中判断条件多,比较复杂,所以猜测很可能是在授权条件里,没有手动做此回调,经过修改,和安卓人员确认之后,便简单修复了这个场景的问题。

另外,x5 内核的调试,需要先下载内核,并打开相应开关

android File 文件下载后打开 androidfilechooser_java_04

android File 文件下载后打开 androidfilechooser_java_05