Android 的WebView有一個(gè)坑贬派,當(dāng)接入的H5當(dāng)中如果有上傳圖片或者其他文件的時(shí)候,點(diǎn)擊添加按鈕是沒(méi)有任何反應(yīng)的量愧,但是IOS不會(huì)有這個(gè)問(wèn)題
問(wèn)題根因:H5訪(fǎng)問(wèn)本地文件的時(shí)候蔓纠,使用的是標(biāo)簽<input type="file">,WebView處于安全性的考慮限制了這個(gè)操作羞反,所以H5是無(wú)法直接訪(fǎng)問(wèn)到安卓的本地文件的布朦。
解決辦法:重寫(xiě)WebviewChromeClient 中的WebviewChromeClient openFileChooser() 和onShowFileChooser()方法響應(yīng)<input type="file">,然后通過(guò)本地代碼調(diào)起圖庫(kù)昼窗,拍照或者本地文件夾選擇的功能是趴,左后在最后在 onActivityResult 把選擇的圖片 URI 回傳WebviewChromeClient
注意點(diǎn):
1. 在Activity中加載H5
2.Fragment中加載H5
代碼示例:
var uploadMessage: ValueCallback<Uri?>? = null
var uploadMessageAboveL: ValueCallback<Array<Uri?>?>? = null
webView.webChromeClient = object : WebChromeClient() {
// For Android < 3.0
fun openFileChooser(valueCallback: ValueCallback<Uri?>?) {
uploadMessage = valueCallback
// 自己實(shí)現(xiàn)的打卡圖庫(kù)和調(diào)起攝像頭的方法
openImageChooserActivity()
}
// For Android >= 3.0
fun openFileChooser(valueCallback: ValueCallback<*>?, acceptType: String?) {
uploadMessage = valueCallback as ValueCallback<Uri?>?
// 自己實(shí)現(xiàn)的打卡圖庫(kù)和調(diào)起攝像頭的方法
openImageChooserActivity()
}
//For Android >= 4.1
fun openFileChooser(
valueCallback: ValueCallback<Uri?>?,
acceptType: String?,
capture: String?
) {
uploadMessage = valueCallback
// 自己實(shí)現(xiàn)的打卡圖庫(kù)和調(diào)起攝像頭的方法
openImageChooserActivity()
}
// For Android >= 5.0
override fun onShowFileChooser(
webView: WebView,
filePathCallback: ValueCallback<Array<Uri?>?>,
fileChooserParams: FileChooserParams
): Boolean {
uploadMessageAboveL = filePathCallback
// 自己實(shí)現(xiàn)的打卡圖庫(kù)和調(diào)起攝像頭的方法
openImageChooserActivity()
return true
}
}
在Activity中加載H5
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK) {
when (requestCode) {
CHOOSE_CERTIFICATE_IMAGE_ALBUM_REQUEST_CODE -> { //相簿
if (null == uploadMessage && null == uploadMessageAboveL) return
val pictures: java.util.ArrayList<PictureInfo>? = data?.getParcelableArrayListExtra<PictureInfo>("pictures")
var uri : Uri? = null
pictures?.takeIf { pictures.size > 0 }?.let {
if(!pictures[0].path.isNullOrEmpty()){
uri = Uri.fromFile(File( pictures[0].path))
}
}
if (uploadMessageAboveL != null) {
if(uri == null){
uploadMessageAboveL?.onReceiveValue(null)
}else{
uploadMessageAboveL?.onReceiveValue(arrayOf(uri))
}
uploadMessageAboveL = null
} else if (uploadMessage != null) {
uploadMessage?.onReceiveValue(uri)
uploadMessage = null
}
}
SetImgUtil.CODE_CAMERA_REQUEST -> { //拍照
val file = SetImgUtil.getOutputMediaFile(this, mCameraCacheFileName)
val uri = Uri.fromFile(file)
if (null == uploadMessage && null == uploadMessageAboveL) return
if (uploadMessageAboveL != null) {
if(uri == null){
uploadMessageAboveL?.onReceiveValue(null)
}else{
uploadMessageAboveL?.onReceiveValue(arrayOf(uri))
}
uploadMessageAboveL = null
} else if (uploadMessage != null) {
uploadMessage?.onReceiveValue(uri)
uploadMessage = null
}
}
else->{
//這里uploadMessage跟uploadMessageAboveL在不同系統(tǒng)版本下分別持有了
//WebView對(duì)象,在用戶(hù)取消文件選擇器的情況下澄惊,需給onReceiveValue傳null返回值
//否則WebView在未收到返回值的情況下唆途,無(wú)法進(jìn)行任何操作富雅,文件選擇器會(huì)失效
if (uploadMessage != null) {
uploadMessage?.onReceiveValue(null)
uploadMessage = null
} else if (uploadMessageAboveL != null) {
uploadMessageAboveL?.onReceiveValue(null)
uploadMessageAboveL = null
}
}
}
}else{
//這里uploadMessage跟uploadMessageAboveL在不同系統(tǒng)版本下分別持有了
//WebView對(duì)象,在用戶(hù)取消文件選擇器的情況下肛搬,需給onReceiveValue傳null返回值
//否則WebView在未收到返回值的情況下吹榴,無(wú)法進(jìn)行任何操作,文件選擇器會(huì)失效
if (uploadMessage != null) {
uploadMessage?.onReceiveValue(null)
uploadMessage = null
} else if (uploadMessageAboveL != null) {
uploadMessageAboveL?.onReceiveValue(null)
uploadMessageAboveL = null
}
}
}
在Fragment中加載H5
在Fragment加載H5需要在Fragment所在的Activity中的onActivityResult中接收數(shù)據(jù)滚婉,接收到到的數(shù)據(jù)可以通過(guò)廣播或者EventBus等方式傳遞到Fragment图筹,數(shù)據(jù)解析和回傳給H5的方式和上面的onActivityResult中處理方式一樣