美文网首页
关于Webview中H5调起原生相册的问题

关于Webview中H5调起原生相册的问题

作者: 走在冷风中吧 | 来源:发表于2018-01-08 17:36 被阅读1747次
    前言:

    webview爬坑之路绵长慢慢, 混合开发, 当h5想调起系统原生的相机或者相册时, IOS无需做任何适配, 而Android还要苦逼的进行适配才行!

    1. 要想实现这个功能, 需要加以下代码:
    mWebView.setWebChromeClient(new WebChromeClient() {
                /**
                 * 16(Android 4.1.2) <= API <= 20(Android 4.4W.2)回调此方法
                 */
                public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
                    mUploadCallbackBelow = uploadMsg;
                    takePhoto();
                }
    
                /**
                 * API >= 21(Android 5.0.1)回调此方法
                 */
                @Override
                public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
                    // (1)该方法回调时说明版本API >= 21,此时将结果赋值给 mUploadCallbackAboveL,使之 != null
                    mUploadCallbackAboveL = filePathCallback;
                    takePhoto();
                    return true;
                }
    }
    
    注意:
    • 此处我只做了4.1以后的兼容处理, 再低的版本基本上现在市面上也很少有这样的机型了, 暂不做处理.
    • 低于5.0的调用时会走openFileChooser()方法, 这个方法在SDK中被@hide注解了, 所以没有办法override, 但是你只需要重写上就可以.
    1. takePhoto()方法的实现代码如下:
        private void takePhoto() {
            Intent i = new Intent(Intent.ACTION_GET_CONTENT);
            i.addCategory(Intent.CATEGORY_OPENABLE);
            i.setType("image/*");
            startActivityForResult(Intent.createChooser(i, "Image Chooser"), 100);
        }
    
    1. 重写onActivityResult()
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            if (requestCode == 100) {
                //针对5.0以上, 以下区分处理方法
                if (mUploadCallbackBelow != null) {
                    chooseBelow(resultCode, data);
                } else if (mUploadCallbackAboveL != null) {
                    chooseAbove(resultCode, data);
                } else {
                    Toast.makeText(this, "发生错误", Toast.LENGTH_SHORT).show();
                }
            }
        }
    
     /**
         * Android API >= 21(Android 5.0) 版本的回调处理
         *
         * @param resultCode 选取文件或拍照的返回码
         * @param data       选取文件或拍照的返回结果
         */
        private void chooseAbove(int resultCode, Intent data) {
            if (RESULT_OK == resultCode) {
                updatePhotos();
    
                if (data != null) {
                    // 这里是针对从文件中选图片的处理, 区别是一个返回的URI, 一个是URI[]
                    Uri[] results;
                    Uri uriData = data.getData();
                    if (uriData != null) {
                        results = new Uri[]{uriData};
                        mUploadCallbackAboveL.onReceiveValue(results);
                    } else {
                        mUploadCallbackAboveL.onReceiveValue(null);
                    }
                } else {
                    mUploadCallbackAboveL.onReceiveValue(new Uri[]{imageUri});
                }
            } else {
                mUploadCallbackAboveL.onReceiveValue(null);
            }
            mUploadCallbackAboveL = null;
        }
    
        private void updatePhotos() {
            // 该广播即使多发(即选取照片成功时也发送)也没有关系,只是唤醒系统刷新媒体文件
            Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
            intent.setData(imageUri);
            sendBroadcast(intent);
        }
    
        /**
         * Android API < 21(Android 5.0)版本的回调处理
         *
         * @param resultCode 选取文件或拍照的返回码
         * @param data       选取文件或拍照的返回结果
         */
        private void chooseBelow(int resultCode, Intent data) {
            if (RESULT_OK == resultCode) {
                updatePhotos();
    
                if (data != null) {
                    // 这里是针对文件路径处理
                    Uri uri = data.getData();
                    if (uri != null) {
                        mUploadCallbackBelow.onReceiveValue(uri);
                    } else {
                        mUploadCallbackBelow.onReceiveValue(null);
                    }
                } else {
                    // 以指定图像存储路径的方式调起相机,成功后返回data为空
                    mUploadCallbackBelow.onReceiveValue(imageUri);
                }
            } else {
                mUploadCallbackBelow.onReceiveValue(null);
            }
            mUploadCallbackBelow = null;
        }
    

    以上便可以打开系统自带的相册, 同理可以处理打开系统自带相机, 但是要记得处理权限问题!

    可能会遇到的问题:

    打了Release包之后又打不开相册了, 这个问题我在开发的时候并没有遇到, 因为我们的项目没有进行混淆, 只是采用了加固. 但是我看别人的帖子有提到过这个问题.
    原因: 由于项目中采用了混淆, 所以openFileChooser()由于不是重载的方法, 混淆之后找不到它了, 就没有办法调起相册,相机
    解决办法:
    混淆时做特殊处理:

    -keepclassmembers class * extends android.webkit.WebChromeClient{ 
    public void openFileChooser(…); 
    }
    

    相关文章

      网友评论

          本文标题:关于Webview中H5调起原生相册的问题

          本文链接:https://www.haomeiwen.com/subject/kibbnxtx.html