Android关于第三方h5在webview调用摄像头及相机的处理

参考资料:
深坑之Webview,解决H5调用android相机拍照和录像
除了没有适配6.0以上的动态申请以及拦截h5的方法不同,其余均参考以上文章

因为app和银行合作,在banner页投放了银行调用摄像进行人脸识别的功能,发现点击拉起摄像的功能无效,但是在内置浏览器却可以,由此怀疑需要对webview进行相关适配处理。后来查阅多方文档,发现上述文档比较详尽,同时总结下我自己的理解:

  • 在h5页面调用原生的相机,自己的产品开发过程平时一般都是和前端沟通好,会在本地进行url的拦截,根据url判断。但是如果前端页面链接不含有特定字段同时都是js调用怎么办呢?所以如果业务需要,是要在webview里进行适配操作,就是复写下面提到的几个方法,说白了就是前端调用完相机,我们要复写下面的方法,并将原生相机的回调,图片的回调通过ValueCallback回调给webview,然后前端才可以通过方法接收到回调的参数进行校验。这样我们要做的事情就很简单了。根据版本不同复写方法,并且传入获取图片以后的回调即可。

这种问题解决办法在于复写openFileChoosers和onShowFileChoosers的方法:
可以先看下介绍
[Android开发深入理解WebChromeClient之onShowFileChooser或openFileChooser使用说明]
(http://teachcourse.cn/2224.html)
在所有发布的SDK版本中,openFileChooser是一个隐藏的方法,使用onShowFileChooser代替,但是最好同时复写WebChromeClient类里的showFileChooser和openFileChooser方法,Android 4.4.X以上的系统回调onShowFileChooser方法,低于或等于Android 4.4.X的系统回调openFileChooser方法,只重写onShowFileChooser或openFileChooser造成在有的系统可以正常回调,在有的系统点击没有反应。
1、前端调用摄像头的代码

前端调用摄像头拍照
<input type="file" accept="image/*" capture="camera">
前端调用摄像头录像
<input type="file" accept="video/*" capture="camera">

一般第三方的h5调用原生的摄像都是这两个方法,我们可以通过拦截accept字段来进行判断(openFileChooser的复写方法里提供了),当然,如果链接里有其他字段,也可以通过onShouldOverrideUrlLoading进行链接的字段拦截。
2、复写方法

 @Override
    protected void openFileChoosers(ValueCallback<Uri> valueCallback) {
        LogUtil.e("czz", "运行方法 onShowFileChooser");
        mUploadMessage = valueCallback;
        take();
    }

    @Override
    protected void openFileChoosers(ValueCallback<Uri> valueCallback, String acceptType) {
        LogUtil.e("czz", "运行方法 onShowFileChooser2");
        mUploadMessage = valueCallback;
        mAcceptType = acceptType;
        take();
    }

    @Override
    protected void openFileChoosers(ValueCallback<Uri> valueCallback, String acceptType, String capture) {
        LogUtil.e("czz", "运行方法 onShowFileChooser3");
        mUploadMessage = valueCallback;
        mAcceptType = acceptType;
        take();
    }

    @Override
    protected void onShowFileChoosers(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
        LogUtil.e("czz", "运行方法 onShowFileChooser4");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            if (fileChooserParams.getAcceptTypes().length > 0) {
                mAcceptType = fileChooserParams.getAcceptTypes()[0];
            }
        }
        mUploadCallbackAboveL = filePathCallback;
        take();
    }
    
    /**
     * 拍照
     */
    private void take() {
        /*打开摄像头拍照通水进行动态权限申请,权限判定是自己封装的方法,仅供参考。*/
        RxPermissions rxPermissions = new RxPermissions(this);
        rxPermissions.request(Manifest.permission.CAMERA,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.READ_EXTERNAL_STORAGE)
                .subscribe(aBoolean -> {
                    if (aBoolean) {
                        try {
                            if ("image/*".equals(mAcceptType)) {
                                takePhoto();
                            }
                            /*打开摄像头录像*/
                            if ("video/*".equals(mAcceptType)) {
                                recordVideo();
                            }
                        } catch (Exception e) {
                            ApToast.showLong(mContext, mContext.getString(R.string.run_camera_error));
                        }
                    }
                });
    }
     /**
     * 摄像
     */
    private void takePhoto() {
        File fileUri = new File(Environment.getExternalStorageDirectory().getPath() + "/" + SystemClock.currentThreadTimeMillis() + ".jpg");
        imageUri = Uri.fromFile(fileUri);
        if (Build.VERSION.SDK_INT >= 24) {
            imageUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", fileUri);//通过FileProvider创建一个content类型的Uri
        }
        takePicture(this, imageUri, PHOTO_REQUEST);
    }

    /**
     * 录像
     */
    private void recordVideo() {
        Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
        intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
        //限制时长
        intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 10);
        //开启摄像机
        startActivityForResult(intent, VIDEO_REQUEST);
    }
       public static void takePicture(Activity activity, Uri imageUri, int requestCode) {
        //调用系统相机
        Intent intentCamera = new Intent();
        if (Build.VERSION.SDK_INT >= 24) {
            intentCamera.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加这一句表示对目标应用临时授权该Uri所代表的文件
        }
        intentCamera.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
        //将拍照结果保存至photo_file的Uri中,不保留在相册中
        intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
        if (activity != null) {
            activity.startActivityForResult(intentCamera, requestCode);
        }
    }

回调处理


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        LogUtil.e("requestCode = " + requestCode + "\n" + "resultCode = " + resultCode);
      	
      if (requestCode == PHOTO_REQUEST) {
            LogUtil.e("PHOTO_REQUEST1");
            if (null == mUploadMessage && null == mUploadCallbackAboveL) return;
            Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
            if (mUploadCallbackAboveL != null) {
                LogUtil.e("PHOTO_REQUEST2");
                onActivityResultAboveL(requestCode, resultCode, data);
            } else if (mUploadMessage != null) {
                LogUtil.e("PHOTO_REQUEST3");
                mUploadMessage.onReceiveValue(result);
                mUploadMessage = null;
            }
        } else if (requestCode == VIDEO_REQUEST) {
            if (null == mUploadMessage && null == mUploadCallbackAboveL) return;

            Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
            if (mUploadCallbackAboveL != null) {
                if (resultCode == RESULT_OK) {
                    mUploadCallbackAboveL.onReceiveValue(new Uri[]{result});
                    mUploadCallbackAboveL = null;
                } else {
                    mUploadCallbackAboveL.onReceiveValue(new Uri[]{});
                    mUploadCallbackAboveL = null;
                }

            } else if (mUploadMessage != null) {
                if (resultCode == RESULT_OK) {
                    mUploadMessage.onReceiveValue(result);
                    mUploadMessage = null;
                } else {
                    mUploadMessage.onReceiveValue(Uri.EMPTY);
                    mUploadMessage = null;
                }

            }
        }
    }
	//这个回调主要是处理5.0以上的回调上传
    private void onActivityResultAboveL(int requestCode, int resultCode, Intent data) {
        if (requestCode != PHOTO_REQUEST || mUploadCallbackAboveL == null) {
            LogUtil.e("onActivityResultAboveL1");
            return;
        }
        Uri[] results = null;
        if (resultCode == Activity.RESULT_OK) {
            if (data == null) {
                LogUtil.e("onActivityResultAboveL2");
                results = new Uri[]{imageUri};
            } else {
                LogUtil.e("onActivityResultAboveL3");
                String dataString = data.getDataString();
                ClipData clipData = data.getClipData();
                if (clipData != null) {
                    results = new Uri[clipData.getItemCount()];
                    for (int i = 0; i < clipData.getItemCount(); i++) {
                        ClipData.Item item = clipData.getItemAt(i);
                        results[i] = item.getUri();
                    }
                }

                if (dataString != null)
                    results = new Uri[]{Uri.parse(dataString)};
            }
        }
        LogUtil.e("onActivityResultAboveL1" + results.toString());
        mUploadCallbackAboveL.onReceiveValue(results);
        mUploadCallbackAboveL = null;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章