现象描述:
在android的webview中,如果web页面中带有< input type=”file” …>的控件,在webview中虽然能正常显示这个上传控件,但是在部分手机上点击却没有任何反应。
查找原因
经过大量机型验证发现5.0以下的可以正常显示出来,5.0及以上的手机点击无反应。初步可以判定是Webview的兼容性问题。
正常情况下在有上传控件的webview点击上传按钮的流程应该是:WebView加载包含上传文件的表单按钮,HTML定义了input标签,同时input的type类型为file,手指点击该按钮,回调openFileChooser这个方法(5.0及以上系统回调onShowFileChooser),然后打开文件选择器选择照片或者文件。
通过查阅sdk对比分析了解到,Android 5.0以下的系统回调openFileChooser方法,而5.0及以上的系统回调onShowFileChooser方法,而由于系统并没有实现onShowFileChooser方法,因而造成了在5.0及以上系统没有反应的现象。
解决方案
因此我们需要重写webchromeClient中的onShowFileChooser,实现5.0及以上系统的兼容。
首先查看一下openFileChooser和onShowFileChooser的系统源码
openFileChooser
/**
* Tell the client to open a file chooser.
* @param uploadFile A ValueCallback to set the URI of the file to upload.
* onReceiveValue must be called to wake up the thread.a
* @param acceptType The value of the 'accept' attribute of the input tag
* associated with this file picker.
* @param capture The value of the 'capture' attribute of the input tag
* associated with this file picker.
*
* @deprecated Use {@link #showFileChooser} instead.
* @hide This method was not published in any SDK version.
*/
@SystemApi
@Deprecated
public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType, String capture) {
uploadFile.onReceiveValue(null);
}
onShowFileChooser
/**
1. Tell the client to show a file chooser.
2.
3. This is called to handle HTML forms with 'file' input type, in response to the
4. user pressing the "Select File" button.
5. To cancel the request, call <code>filePathCallback.onReceiveValue(null)</code> and
6. return true.
7.
8. @param webView The WebView instance that is initiating the request.
9. @param filePathCallback Invoke this callback to supply the list of paths to files to upload,
10. or NULL to cancel. Must only be called if the
11. <code>showFileChooser</code> implementations returns true.
12. @param fileChooserParams Describes the mode of file chooser to be opened, and options to be
13. used with it.
14. @return true if filePathCallback will be invoked, false to use default handling.
15.
16. @see FileChooserParams
*/
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
FileChooserParams fileChooserParams) {
return false;
}
通过对比这两个方法可以看出它们的区别,openFileChooser中传入的参数ValueCallback接口回传一个Uri的对象,而onShowFileChooser回传一个Uri[]数组,因此在onActivityResult回调方法中调用ValueCallback接口方法onReceiveValue传入参数需特别注意对于这两种方法的回调要区别对待。
/**
*回调onShowFileChooser方法,onReceiveValue传入Uri对象数组
*/
mFilePathCallback.onReceiveValue(new Uri[]{uri});
/**
*回调openFileChooser方法,onReceiveValue传入一个Uri对象
*/
mFilePathCallback4.onReceiveValue(uri);
代码实例
1. 重写openFileChooser和onShowFileChooser方法,兼容各版本
webview.setWebChromeClient(new WebChromeClient() {
// For Android < 3.0
public void openFileChooser(ValueCallba