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;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章