Android webview点击<input type=“file“>选择文件的实现

从安卓5.0开始(之前的版本没有测试过,只是从一些资料中得知此信息),webview中<input type="file">的打开文件实现已经改变,点击没有任何反应,需要重载WebChromeClient,处理打开文件的操作。

因为版本不断更新迭代,网上的一些实现中会用到deprecated的函数,以下给出“2023/4”我的实现,里面用到registerForActivityResult。相对于startActivityForResult,它更好一些,它使用回调,使得不用在多个函数中配合实现一个功能。

首先,注册一个ActivityResultLauncher,用于打开文件浏览器选择文件:

//解决安卓5及以上版本html<input type="file">无响应问题
private ValueCallback<Uri[]> checkedFile;
private ActivityResultLauncher<String[]> explorer;

//在Activity.onCreate中实现以下内容,实现打开文件浏览器选择文件的功能
protected void onCreate(Bundle savedInstanceState) {
    ........
    explorer = registerForActivityResult(new ActivityResultContracts.OpenDocument(),
	result -> {
		LOG.debug("Open file `{}`", result);
		if(checkedFile != null) {
			if(result == null) {
				checkedFile.onReceiveValue(null); //result没选择时为null
			} else {
				checkedFile.onReceiveValue(new Uri[]{result});
			}
			checkedFile = null;
		}
	});
    ........
}

其次,安卓5或以上版本,重载WebChromeClient.onShowFileChoose(老版本需要重载其他函数,可以参照网上其他介绍,我认为5以下没必要兼容了,所以不实现)。

WebChromeClient chromeClient = new WebChromeClient() {
	@Override
	public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
		if (checkedFile != null) {
			//防止上一次没选文件,直接退出的情况,导致后面选择无法正常工作
			checkedFile.onReceiveValue(null);
		}
		checkedFile = filePathCallback;
		String[] acceptTypes = fileChooserParams.getAcceptTypes();
		LOG.debug("fileChooserParams:{},sdk_int:{}", Arrays.stream(acceptTypes).toArray(), Build.VERSION.SDK_INT);
		if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.N){
			explorer.launch(new String[]{"*/*"});
		} else {
			explorer.launch(acceptTypes);
		}
		return true;
	}
};
........
//设置到webview中
webview.setWebChromeClient(chromeClient);

注意,代码中判断了安卓7及以前版本,不能使用fileChooserParams参数来限制选择的文件类型,否则点击没有响应,也无错误信息,原因未知,所以这里传"*/*"。

一个关键点:在onShowFileChooser中获得checkedFile,这是一个回调。在explorer选中文件后,调用checkedFile.onReceiveValue将结果传递给webview。

在html中的处理与普通web浏览器完全相同,以下是获取图片文件并裁剪的例子,完整内容见此连接serverui/file/settings/home.js · master · 至简网格 / 至简网格企业服务 · GitCode,在startCropLogo函数中。

  var file = e.target.files[0];
  if (!/\.(gif|jpg|jpeg|png|bmp|GIF|JPG|PNG)$/.test(e.target.value)) {
    this.$refs.alertDlg.show(this.tags.invalidImg);
    return false
  }
  var reader = new FileReader()
  reader.onload = (e) => {
    var data
    if (typeof e.target.result === 'object') {
      // 把Array Buffer转化为blob 如果是base64不需要
      data = window.URL.createObjectURL(new Blob([e.target.result]))
    } else {
      data = e.target.result
    }
    this.logoOpts.img = data
	this.loading=false;
  }
  // reader.readAsDataURL(file)// 转化为base64
  reader.readAsArrayBuffer(file)// 转化为blob

猜你喜欢

转载自blog.csdn.net/flyinmind/article/details/130194217
今日推荐