修改cordova底层以支持input直接打开摄像机或视频库

  • Post author:
  • Post category:其他




修改cordova底层以支持input直接打开摄像机或视频库



需求背景

cordova环境下,调用摄像机或视频库的代码与纯h5环境下不一致,这使得我们要写很多额外代码。本文用以解决这个问题。

相关照片和相册问题已经有另一篇文档:

修改cordova底层以支持input直接打开照相机或图片库

当前时间:20210111

cordova版本: v.9.0+

android sdk: >=24



改造过程

最终目标是兼容摄像和照相的处理。



增加操作类型判断函数getActType

private int getActType(Intent selectIntent){
    if (selectIntent != null) {
        String intent_type = selectIntent.getType();
        if (intent_type != null) {
            if (intent_type.indexOf("image/") == 0) {
                return 1;
            } else if (intent_type.indexOf("video/") == 0) {
                return 2;
            }
        }
    }
    return 0;
}



增加返回值处理函数__getFileUrisByIntent

处理选择相册文件之后数据处理。此外摄像的返回值也会经过这里的

intent.getData()

部分

private Uri[] __getFileUrisByIntent(Intent intent){
    Uri[] result = null;
    if (intent != null) {
        选择文件
        if (intent.getClipData() != null) {
            // handle multiple-selected files
            final int numSelectedFiles = intent.getClipData().getItemCount();
            result = new Uri[numSelectedFiles];
            for (int i = 0; i < numSelectedFiles; i++) {
                result[i] = intent.getClipData().getItemAt(i).getUri();
                LOG.d(LOG_TAG, "getFilesResultByIntent Receive file chooser URL: " + result[i]);
            }
        } else if (intent.getData() != null) {
            // handle single-selected file
            result = WebChromeClient.FileChooserParams.parseResult(Activity.RESULT_OK, intent);
            LOG.d(LOG_TAG, "getFilesResultByIntent Receive file chooser URL: " + result);
        }
    }
    return result;
}



修改函数onShowFileChooser

@Override
public boolean onShowFileChooser(WebView webView, 
	final ValueCallback<Uri[]> filePathsCallback, 
	final WebChromeClient.FileChooserParams fileChooserParams) {
    // Check if multiple-select is specified
    Boolean selectMultiple = false;
    if (fileChooserParams.getMode() == WebChromeClient.FileChooserParams.MODE_OPEN_MULTIPLE) {
        selectMultiple = true;
    }
    Intent intent = fileChooserParams.createIntent();
    intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, selectMultiple);

    boolean isCapture = fileChooserParams.isCaptureEnabled();
    
    // Uses Intent.EXTRA_MIME_TYPES to pass multiple mime types.
    String[] acceptTypes = fileChooserParams.getAcceptTypes();
    if (acceptTypes.length > 1) {
        intent.setType("*/*"); // Accept all, filter mime types by Intent.EXTRA_MIME_TYPES.
        intent.putExtra(Intent.EXTRA_MIME_TYPES, acceptTypes);
    }
    try {
        if (getActType(intent)> 0){
            showCameraSelectIntent(isCapture, filePathsCallback, intent);
        }else{
            //正常筛选
            parentEngine.cordova.startActivityForResult(new CordovaPlugin() {
                @Override
                public void onActivityResult(int requestCode, int resultCode, Intent intent) {
                    Uri[] result = null;
                    if (resultCode ==  Activity.RESULT_OK && intent != null) {
                        result = __getFileUrisByIntent(intent);
                    }
                    filePathsCallback.onReceiveValue(result);
                }
            }, intent, FILECHOOSER_RESULTCODE);
        }
    } catch (ActivityNotFoundException e) {
        LOG.w("No activity found to handle file chooser intent.", e);
        filePathsCallback.onReceiveValue(null);
    }
    return true;
}



调整函数showCameraSelectIntent

上篇博文中,原函数是showImageSelectIntent,修改函数名称,调整内容

public void showCameraSelectIntent(boolean onlyCapture, 
	final ValueCallback<Uri[]> filePathsCallback, 
	Intent selectIntent){
    try {
        int Act_type = getActType(selectIntent);//操作类型
        Intent captureIntent = null;    //照相或者摄像,捕获用的Intent
        String mCameraPhotoPath = null;   //照相时候的Path
        String showTitle = "";
        if (Act_type == 1){
            captureIntent = getTakePictureIntent();//拍照Intent
            mCameraPhotoPath = captureIntent.getStringExtra("filepath") + "";
            showTitle = "Image Chooser";
        }else if (Act_type == 2){
            captureIntent = getTakeVideoIntent();//摄像Intent 返回值会走intent.getData()
            showTitle = "video Chooser";
        }

        Intent[] intentArray = (captureIntent != null)? new Intent[]{captureIntent} : new Intent[2];
        //发起选择
        Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
        chooserIntent.putExtra(Intent.EXTRA_INTENT, selectIntent);
        chooserIntent.putExtra(Intent.EXTRA_TITLE, showTitle);
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);

        Intent f_intent = null;
        if (onlyCapture)  f_intent = captureIntent;
        else f_intent = Intent.createChooser(chooserIntent, showTitle);

        String finalMCameraPhotoPath = mCameraPhotoPath;
        parentEngine.cordova.startActivityForResult(new CordovaPlugin() {
            @Override
            public void onActivityResult(int requestCode, int resultCode, Intent intent) {
                Uri[] result = null;
                if (resultCode == Activity.RESULT_OK) {
                    if (intent != null) {选择文件
                        result = __getFileUrisByIntent(intent);
                    } else {照片
                        添加图片到相册
                        MediaScannerConnection.scanFile(parentEngine.cordova.getContext().getApplicationContext(),
                                new String[]{finalMCameraPhotoPath}, null,
                                new MediaScannerConnection.OnScanCompletedListener() {
                                    @Override
                                    public void onScanCompleted(String path, Uri uri) {
                                    }
                                });
                        // File retFile = new File(mCameraPhotoPath);
                        result = new Uri[]{Uri.parse("file:" + finalMCameraPhotoPath)};
                    }
                }
                filePathsCallback.onReceiveValue(result);
            }
        }, f_intent, IMAGE_FILECHOOSER_RESULTCODE);
    }catch (Exception e){
        LOG.e(LOG_TAG, "showCameraSelectIntent error", e);
        e.printStackTrace();
        filePathsCallback.onReceiveValue(null);
    }
}

获取image的intent

private Intent getTakePictureIntent(){
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    if (takePictureIntent.resolveActivity(parentEngine.cordova.getActivity().getPackageManager()) != null) {
        // Create the File where the photo should go
        File photoFile = getFileForCameraCapture("IMG_", "jpg");
        Log.w(LOG_TAG, "getTakePictureIntent photoFile="+photoFile);
        // Continue only if the File was successfully created
        if (photoFile != null) {
            String mCameraPhotoPath = photoFile.getAbsolutePath();
            Log.w(LOG_TAG, "getTakePictureIntent mCameraPhotoPath="+mCameraPhotoPath);
            Uri photoUri = FileProvider.getUriForFile(
                    parentEngine.cordova.getContext(),
                    parentEngine.cordova.getActivity().getPackageName() + ".provider",
                    photoFile);
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
            takePictureIntent.putExtra(MediaStore.AUTHORITY, true);
            takePictureIntent.putExtra("return-data", true);
            takePictureIntent.putExtra("filepath", mCameraPhotoPath);
            takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        } else {
            takePictureIntent = null;
        }
    }
    return takePictureIntent;
}

获取video的Intent

private Intent getTakeVideoIntent(){
    Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
    //设置视频录制的最长时间
    intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 15);
    //设置视频录制的画质
    intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
    return intent;
}



参考文档


H5中有拍摄视频或者选择视频 onShowFileChooser



android视频录制MediaStore.ACTION_VIDEO_CAPTURE



版权声明:本文为Nicker_原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。