对于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>>? = null
override fun onShowFileChooser(webView: WebView, filePathCallback: ValueCallback<Array<Uri>>, fileChooserParams: FileChooserParams): Boolean {
mFilePathCallBack = filePathCallback
val 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>
这个下载是在通知栏显示下载进度。