参考资料:
深坑之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、前端调用摄像头的代码

前端调用摄像头拍照前端调用摄像头录像

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

 @Override    protected void openFileChoosers(ValueCallback valueCallback) {        LogUtil.e("czz", "运行方法 onShowFileChooser");        mUploadMessage = valueCallback;        take();    }    @Override    protected void openFileChoosers(ValueCallback valueCallback, String acceptType) {        LogUtil.e("czz", "运行方法 onShowFileChooser2");        mUploadMessage = valueCallback;        mAcceptType = acceptType;        take();    }    @Override    protected void openFileChoosers(ValueCallback valueCallback, String acceptType, String capture) {        LogUtil.e("czz", "运行方法 onShowFileChooser3");        mUploadMessage = valueCallback;        mAcceptType = acceptType;        take();    }    @Override    protected void onShowFileChoosers(WebView webView, ValueCallback 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;    }

更多相关文章

  1. Android年终盘点:阿里程序员必备技能知识点,程序员必须收藏
  2. Android开发之模板模式初探
  3. Java中输入流的read()为阻塞式方法的相关实例
  4. Android(安卓)控制线程的暂停和恢复
  5. android studio 适配android7.0 android 6.0拍照调用系统裁剪工
  6. Android(安卓)反射调用方法并利用此方法展开android通知栏(兼容4.
  7. 这可能是最好的 Android/Kotlin日志输出方法
  8. Android(安卓)Trick 11: 对Android中的AsyncTask进行函数化的封
  9. 【SMS】android 短信接收流程分析——-拦截短信示例代码

随机推荐

  1. Android(安卓)Media Framework 总纲
  2. android截屏代码:C++实现
  3. 使用Android(安卓)Studio创建Android(安
  4. android开发--RelativeLayout用到的一些
  5. Android(安卓)获取基站信息
  6. Android预制APP第一次打开时不弹权限提示
  7. Android中WebView如何加载JavaScript脚本
  8. android手机两种方式获取IP地址
  9. Android(安卓)SDK下载和更新失败的解决方
  10. AndroidのUI布局之layout weight