对于WebView的文件上传,WebView本身是没有进行处理的,需要覆盖如下方法进行处理:
fun onShowFileChooser(webView: WebView, filePathCallback: ValueCallback<Array<Uri>>, fileChooserParams: FileChooserParams
)
其中第三个参数包装了 html
的 input
标签的一些属性,
fileChooserParams.mode
FileChooserParams.MODE_OPEN
单选FileChooserParams.MODE_OPEN_MULTIPLE
多选FileChooserParams.MODE_SAVE
保存
fileChooserParams.isCaptureEnabled
是否启用实时捕获,比如相机、麦克风。使用getAcceptTypes
来确定合适的捕获设备。fileChooserParams.acceptTypes
返回可接受的MIME类型数组,例如{"image/*", "video/*"}
,表示只允许选择图片和视频文件。如果没有指定可接受的类型,该数组将为空。
html的选择控件哪些属性对于这些属性呢,如下:
<input id="inputImage" type="file" accept="image/*" multiple capture="user">
multiple
就表示多选,不需要赋值,不写这个就是单选,capture
经测试好像也一样,只要写了它,则isCaptureEnabled
就会是true
,不论我给它赋值什么都一样。
有个简单的方式实现文件选择:
class MyWebChromeClient(private val activity: Activity) : WebChromeClient() {private var mFilePathCallBack: ValueCallback<Array<Uri>>? = nulloverride fun onShowFileChooser(webView: WebView, filePathCallback: ValueCallback<Array<Uri>>, fileChooserParams: FileChooserParams): Boolean {mFilePathCallBack = filePathCallbackval intent = fileChooserParams.createIntent()activity.startActivityForResult(intent, 100)return true}fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {if (requestCode == 100) {if (resultCode == Activity.RESULT_OK) {val results = FileChooserParams.parseResult(resultCode, data)mFilePathCallBack?.onReceiveValue(results)mFilePathCallBack = null}}}
}
但是这个方式呢,就只能是从文件管理器中选择,不会使用设备实时捕获的,而且多选也是没有的,只有单选。如何测试呢?这就需要自己写个html,然后去加载这个html进行测试了,如下:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>选择并显示图片</title><style>img {max-width: 100%;max-height: 300px;}</style></head><body><input id="inputImage" type="file" accept="image/*" multiple capture="user"><br><img id="previewImage" src="#" alt="选择的图片" style="display:none;"><script>const inputImage = document.getElementById('inputImage');const previewImage = document.getElementById('previewImage');inputImage.addEventListener('change', function(event) {const file = event.target.files[0];const reader = new FileReader();reader.onload = function(e) {previewImage.src = e.target.result;previewImage.style.display = 'block';}reader.readAsDataURL(file);});</script></body>
</html>
这里加了一段js,用于把选择的图片展示出来。把该html放到asserts
目录,然后加载这个url
即可:
val url = "file:///android_asset/index.html"
我们可以通过修改input
标签中的属性来测试Android上的文件选择效果。
使用fileChooserParams.createIntent()
创建的文件选择器效果不是很理想,所以要想实现比较好的文件选择效果的话需要自己去实现了,但是比较麻烦,所以可以使用一些第三方的库,比如AgentWeb
:
// AgentWeb
implementation("io.github.justson:agentweb-core:v5.1.1-androidx")
implementation("io.github.justson:agentweb-filechooser:v5.1.1-androidx") // 可选,用于网页中的文件选择器
但是这个也不是很完美的,比如设置了accept="image/*"
或accept="video/*"
就会弹出选项从文件中选择或者拍摄,不管你是否设置了capture
属性。而且也是没有多选的,不管你是否设置了multiple
。不过公司项目没有要求那么细,我也就懒得去找更好的实现,将就着用吧。如不满足使用可在github上搜索Android File Chooser
看看这些有无支持WebView的。或者搜索FilePicker
。
另外,AgentWeb
还有下载组件:
implementation("com.github.Justson:Downloader:v5.0.4-androidx") // (可选)
要测试WebView的下载也很简单,在html中添加一个下载连接即可,如下:
<h1>Click the link below to download the file:</h1><a href="http://codown.youdao.com/reciteword/android/reciteword_official.apk" download>Download File</a>
这个下载是在通知栏显示下载进度。