解决WebView文件上传无法重复选择问题

640?wx_fmt=png

今日科技快讯

近日,高德公司以不正当竞争纠纷为案由,将嘀嘀公司起诉至法院。高德认为滴滴打车采用教唆、劝诱等不正当手段,使该公司多名高管、工程师与其脱离雇佣关系,并有部分员工离职前夕大量拷贝其公司商业秘密的行为。

作者简介

又到了周五啦,提前祝大家周末愉快!

本篇来自 钊林 的投稿,分享了一个解决WebView文件上传无法重复选择问题的方案,希望能够帮助到大家。

钊林 的博客地址:

http://teachcourse.cn

正文

Android 开发使用 WebView 控件加载包含表单的 H5 网页,点击上传文件按钮,弹出对话框,选择从相册获取照片、拍照或打开手机文件管理器,从 Android 手机选取一张图片或一个文件,然后通过 ValueCallback 接口传递,在 WebView 加载的 H5网页 显示。

这里有一个问题,点击“取消”或返回按钮,无法重复回调 onShowFileChooser openFileChooser 方法,控制台打印:

Attempted to finish an input event but the input event receiver has already been disposed

一、深入理解onShowFileChooser或openFileChooser

WebChromeClient 各个方法这里不再赘述,特殊说明关于 WebChromeClient,它既不是接口也不是抽象类,但声明的方法很多方法体都是空的,这是让钊林感到疑惑之一。查看 WebView 源码,setWebChromeClient() 传入 WebChromeClient 对象,然后使用传入的对象,调用 WebChromeClient 声明的方法,再将一些参数传递返回 WebChromeClient 空方法体。在 WebView 源码里面代码也很简单,详细的处理处理逻辑看不到,这是让钊林感到疑惑之二,感觉像一个黑箱子。

然后就一直想,那么重写 WebChromeClient 的方法有什么作用呢?先看一下 onShowFileChooser,如下:

640?wx_fmt=png

该方法的作用,告诉当前APP,打开一个文件选择器,比如:打开相册、启动拍照或打开本地文件管理器,实际上更好的理解,WebView 加载包含上传文件的表单按钮,HTML 定义了 input 标签,同时 input 的 type 类型为 file,手指点击该按钮,回调 onShowFileChooser 这个方法,在这个重写的方法里面打开相册、启动照片或打开本地文件管理器,甚至做其他任何的逻辑处理,点击一次回调一次的前提是请求被取消,而取消该请求回调的方法:给 ValueCallback 接口的 onReceiveValue 抽象方法传入 null,同时 onShowFileChooser 方法返回 true

ValueCallback 的抽象方法被回调 onShowFileChooser 方法返回 true;反之返回 false;再来看一下 openFileChooser 的源码,如下:

640?wx_fmt=png

在所有发布的SDK版本中,openFileChooser 是一个隐藏的方法,使用 onShowFileChooser 代替,但是最好同时重写 showFileChooser openFileChooser 方法,Android 4.4.X 以上的系统回调 onShowFileChooser 方法,低于或等于 Android 4.4.X 的系统回调 openFileChooser 方法,只重写 onShowFileChooser openFileChooser 造成在有的系统可以正常回调,在有的系统点击没有反应。

仔细分析 onShowFileChooser openFileChooser 回调方法,这两个方法之间的区别:

第一个区别:前者 ValueCallback 接口回传一个 Uri数组,后者回传一个 Uri对象,在 onActivityResult 回调方法中调用 ValueCallback 接口方法 onReceiveValue 传入参数特别注意。

640?wx_fmt=png

第二个区别:前者 将 后者的 acceptType、capture 封装成 FileChooserParams 抽象类

二、实例展示onShowFileChooser或openFileChooser处理过程

640?wx_fmt=png

这是实例运行的效果图,H5表单写入两个上传文件的按钮,点击其中一个从底部弹出对话框,选择相册文件或拍照,点击“取消”按钮,再次点击“上传文件”按钮能够再次回调 onShowFileChooser openFileChooser 方法。

在之前的理解中,误解 onShowFileChooser openFileChooser 只能打开相册或启动相机拍照,其实不仅仅是这样,onShowFileChooser openFileChooser 既然是一个回调的方法,可以重复执行各种逻辑代码,比如:启动另一个Activity、弹窗对话框、录制视频或录音等

在上面的例子中,执行弹窗操作,将弹窗的处理代码放置 onShowFileChooser openFileChooser 方法体,如下:

640?wx_fmt=png

点击弹窗 取消按钮、点击打开相册 取消操作 取消拍照,可能无法再次回调onShowFileChooser openFileChooser 方法,如果你没有在点击弹窗取消方法中或 onActivityResult 回调方法 resultCode==RESULT_CANCELED 处理,再次点击上传按钮,打印出 log:

Attempted to finish an input event but the input event receiver has already been disposed

同时,点击没有效果。解决方案:

640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=png

在不期待回调 mFilePathCallback 的 onReceiveValue 方法时,调用 cancelFilePathCallback(),解决点击上传按钮无法重复回调的问题。

更多

每天学习累了,看些搞笑的段子放松一下吧。关注最具娱乐精神的公众号,每天都有好心情。

640?wx_fmt=gif

如果你有好的技术文章想和大家分享,欢迎向我的公众号投稿,投稿具体细节请在公众号主页点击“投稿”菜单查看。

欢迎长按下图 -> 识别图中二维码或者扫一扫关注我的公众号:

640?wx_fmt=jpeg