WebView加载H5界面无法调用手机本地图库和相机

Android 的WebView有一个坑,当接入的H5当中如果有上传图片或者其他文件的时候,点击添加按钮是没有任何反应的,但是IOS不会有这个问题

问题根因:H5访问本地文件的时候,使用的是标签<input type="file">,WebView处于安全性的考虑限制了这个操作,所以H5是无法直接访问到安卓的本地文件的。

解决办法:重写WebviewChromeClient 中的WebviewChromeClient openFileChooser() 和onShowFileChooser()方法响应<input type="file">,然后通过本地代码调起图库,拍照或者本地文件夹选择的功能,左后在最后在 onActivityResult 把选择的图片 URI 回传WebviewChromeClient

注意点:
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
     // 自己实现的打卡图库和调起摄像头的方法
                openImageChooserActivity()
            }

            // For Android  >= 3.0
            fun openFileChooser(valueCallback: ValueCallback<*>?, acceptType: String?) {
                uploadMessage = valueCallback as ValueCallback<Uri?>?
     // 自己实现的打卡图库和调起摄像头的方法
                openImageChooserActivity()
            }

            //For Android  >= 4.1
            fun openFileChooser(
                valueCallback: ValueCallback<Uri?>?,
                acceptType: String?,
                capture: String?
            ) {
                uploadMessage = valueCallback
      // 自己实现的打卡图库和调起摄像头的方法
                openImageChooserActivity()
            }

            // For Android >= 5.0
            override fun onShowFileChooser(
                webView: WebView,
                filePathCallback: ValueCallback<Array<Uri?>?>,
                fileChooserParams: FileChooserParams
            ): Boolean {
                uploadMessageAboveL = filePathCallback
         // 自己实现的打卡图库和调起摄像头的方法   
                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在不同系统版本下分别持有了
                    //WebView对象,在用户取消文件选择器的情况下,需给onReceiveValue传null返回值
                    //否则WebView在未收到返回值的情况下,无法进行任何操作,文件选择器会失效
                    if (uploadMessage != null) {
                        uploadMessage?.onReceiveValue(null)
                        uploadMessage = null
                    } else if (uploadMessageAboveL != null) {
                        uploadMessageAboveL?.onReceiveValue(null)
                        uploadMessageAboveL = null
                    }
                }
            }
        }else{
            //这里uploadMessage跟uploadMessageAboveL在不同系统版本下分别持有了
            //WebView对象,在用户取消文件选择器的情况下,需给onReceiveValue传null返回值
            //否则WebView在未收到返回值的情况下,无法进行任何操作,文件选择器会失效
            if (uploadMessage != null) {
                uploadMessage?.onReceiveValue(null)
                uploadMessage = null
            } else if (uploadMessageAboveL != null) {
                uploadMessageAboveL?.onReceiveValue(null)
                uploadMessageAboveL = null
            }
        }
    }

在Fragment中加载H5

在Fragment加载H5需要在Fragment所在的Activity中的onActivityResult中接收数据,接收到到的数据可以通过广播或者EventBus等方式传递到Fragment,数据解析和回传给H5的方式和上面的onActivityResult中处理方式一样

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容