赞
踩
参考资料:
深坑之Webview,解决H5调用android相机拍照和录像
除了没有适配6.0以上的动态申请以及拦截h5的方法不同,其余均参考以上文章
因为app和银行合作,在banner页投放了银行调用摄像进行人脸识别的功能,发现点击拉起摄像的功能无效,但是在内置浏览器却可以,由此怀疑需要对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; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。