您的当前位置:首页关于Webview中H5调起原生相册的问题

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

2024-12-14 来源:哗拓教育
前言:

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(…); 
}
显示全文