当前位置:网站首页>WebView brings photos and videos to the end

WebView brings photos and videos to the end

2021-01-23 18:33:31 brzhang

about iOS Environment , Two simple configurations are OK La

That is, you only need to add the permission of camera and microphone in the configuration . The specific way is to App Of info.plist Add :

.NSMicrophoneUsageDescription
.NSCameraUsageDescription

Just a matter of !

about Android Environmental Science , It's a little bit more complicated :

step1、 We need to achieve our own WebChromeClient, Its main purpose is to intercept FileChooser This action of selecting a file :

here , The user is in h5 Click on the file , We have achieved the following WebChromeClient in , Based on the difference Android Of api The callback function in this version will be triggered :

public class EssWebChromeClient extends WebChromeClient {

     private Activity mActivity;

    public EssWebChromeClient(Activity activity) {
        mActivity = activity;
    }
    /// Omitted code 
    // For Android >= 3.0
    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
        EssH5Sdk.getInstance().recordVideoForApiBelow21(uploadMsg, acceptType, mActivity);
    }
    // For Android >= 4.1
    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
        EssH5Sdk.getInstance().recordVideoForApiBelow21(uploadMsg, acceptType, mActivity);
    }

    @Override
    public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
        if(EssH5Sdk.getInstance().recordVideoForApi21(webView, filePathCallback, mActivity,fileChooserParams)){
            return true;
        }else{
            return super.onShowFileChooser(webView, filePathCallback, fileChooserParams);
        }
    }
}

Here we notice the following ,openFileChooser There will be one in the function acceptType Parameters of ;

This parameter actually corresponds to us H5 that input In the box accept attribute , We need to pay attention to :

accept  Property is a string , It defines the file  input The type of file that should be accepted . It means that  file  Type of <input> The file type that the user can choose from in the element . Each unique file type specifier can take one of the following forms :

  • A full stop in English (".") Legal case insensitive file name extension starting with . for example : .jpg,.pdf or  .doc.
  • A... Without an extension MIME Type string .
  • character string  audio/*, Express “ Any audio file ”.
  • character string video/*, Express “ Any video file ”.
  • character string image/*, Express “ Any image file ”.

Here's another attribute that we should pay attention to :

capture  Property is a string , If accept  Attributes point to input It's a picture or video type , It specifies which camera to use to access the data .

value  :user  Indicates that the front camera and / Or a microphone .

value : environment  Indicates that the rear camera and / Or a microphone .

step2、 Okay , When the user clicks select File , Has triggered our WebChromeClient Select File callback in , Next , We realize the original pull-up of thinking of taking pictures or :

  public void recordVideoForApiBelow21(ValueCallback<Uri> uploadCallback, String acceptType, Activity activity) {
        if("image/*".equals(acceptType)){
            setUploadMessage(uploadMsg);
            startCamera(activity);
        }else if ("video/*".equals(acceptType)) {
            setUploadCallback(uploadCallback);
            recordVideo(activity);
        }
   }
   
  @TargetApi(21)
  public boolean recordVideoForApi21(WebView webView, ValueCallback<Uri[]> filePathCallback, Activity activity, WebChromeClient.FileChooserParams fileChooserParams){
        String acceptType = fileChooserParams.getAcceptTypes()[0];
        if("image/*".equals(acceptType)){
            setUploadCallbackV21(filePathCallback);
            startCamera(activity);
            return true;
        }
        if ("video/*".equals(acceptType) ){ 
            setUploadCallbackV21(filePathCallback);
            recordVideo(activity);
            return true;
        }
        return false;
  }

Here we notice two versions of api In fact, the form of callback is different ,21 The above is to accept a Uri[] Of callback, And below 21 It's about receiving one Url Of callback, Just pay attention here , then , Let's see startCamera and recordVideo How to realize :

Here's a simple one , How to record a video :

private void recordVideo(Activity activity){
        try {
            Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
            intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.putExtra("android.intent.extras.CAMERA_FACING", 1); //  Call the front camera 

            activity.startActivityForResult(intent, VIDEO_REQUEST);
        } catch (Exception e) {
            e.printStackTrace();
        }
}

It's easier to record video , Of course, I configured the default pull up front camera , Based on specific business scenarios , For example, face recognition , Sometimes it helps .

that , Record and play video , This startActivityForResult, There will be one onActivityResult The callback , Let's go get him Intent data, So the result and call the corresponding callback, You should remember the above settings callback Well :

if (requestCode == VIDEO_REQUEST) { // According to the request code to determine whether the return is h5 Face brushing results 
     Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
     Uri[] uris = result == null ? null : new Uri[]{result};
     if (mUploadCallbackAboveL != null) {
            mUploadCallbackV21.onReceiveValue(uris);
            setUploadCallbackAboveL(null);
     } else {
            mUploadMessage.onReceiveValue(result);
            setUploadMessage(null);
     }
}

therefore , We see that , It's just based on different api To use the callback function .

therefore , The same is coming , Photography is also such a routine :

private void takeCamera(Activity activity) {
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        takePictureIntent.putExtra("android.intent.extras.CAMERA_FACING", 0); //  Call the rear camera 
        //https://ptyagicodecamp.github.io/accessing-pictures-using-fileprovider.html
        if (takePictureIntent.resolveActivity(activity.getPackageManager()) != null) {
            File photoFile = null;
            try {
                photoFile = createImageFile(activity);
                takePictureIntent.putExtra("PhotoPath", mCameraFilePath);
            } catch (IOException ex) {
                Log.e("TAG", "Unable to create Image File", ex);
            }
            // adapter 7.0
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
                if (photoFile != null) {
                    Uri photoURI = FileProvider.getUriForFile(activity,
                             "com.tencent.xxx.fileprovider", photoFile);
                    takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
                }
            } else {
                if (photoFile != null) {
                    mCameraFilePath = "file:" + photoFile.getAbsolutePath();
                    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
                            Uri.fromFile(photoFile));
                } else {
                    takePictureIntent = null;
                }
            }
        }
        activity.startActivityForResult(takePictureIntent, TAKE_PHOTO_REQUEST);

    }
    
    
    private File createImageFile(Activity activity) throws IOException {
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(new Date());
        String imageFileName = "JPEG_" + timeStamp + "_";
        File storageDir = activity.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        File image = File.createTempFile(
                imageFileName,  /*  Prefix  */
                ".jpg",         /*  suffix  */
                storageDir      /*  Folder  */
        );
        mCameraFilePath = image.getAbsolutePath();
        return image;
    }

wait , What needs to be noted here is ,7.0 after ,Android The system does not allow file: The way to expose files , Need to use FileProvider, therefore , It needs to be AndroidManifest.xml In the configuration file provider:

        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="com.tencent.xxx.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

android:authorities We should pay attention to the consistency of the values of , Otherwise getUriForFile Must be crash 了 , And it's a JNI Of crash, Without rhyme or reason , It allows you to pinpoint problems that are extremely painful .

file_path.xml Is as follows :

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images" path="Android/data/com.tencent.xxx/files/Pictures" />
</paths>

Because we take pictures of the temporary files stored , Prevent from being in albums :Environment.DIRECTORY_PICTURES, So here path This is this. , Of course , This path You can debug it , Grab it photoFile The path of this variable , Naturally, I know what to fill in .

ok, It's still up to us onActivityResult link :

       if (requestCode == TAKE_PHOTO_REQUEST){
            if ( resultCode != RESULT_OK){// User cancelled , Send back an empty 
                if (mUploadCallbackAboveL != null) {
                    mUploadCallbackAboveL.onReceiveValue(null);
                    setUploadCallbackV21(null);
                } else if (mUploadMessage != null) {
                    mUploadMessage.onReceiveValue(null);
                    setUploadMessage(null);
                }
                return;
            }
            Uri result = (data == null) ? null : data.getData();

            if (result == null && hasFile(mCameraFilePath)) {
                result = Uri.fromFile(new File(mCameraFilePath));
            }
            Uri[] uris = result == null ? null : new Uri[]{result};
            if (mUploadCallbackAboveL != null) {
                mUploadCallbackAboveL.onReceiveValue(uris);
                setUploadCallbackV21(null);
            } else if (mUploadMessage != null) {
                mUploadMessage.onReceiveValue(result);
                setUploadMessage(null);
            }
        }

There's a little bit of caution here , Whether the user cancels or chooses , there data Always be null, But we can pass resultCode To distinguish whether the user cancels , If the user cancels , The callback function returns a null Just OK La .

above , Namely WebChromeClient Specific details of , When it's done , We need to and webview On the correlation :

mWebView.setWebChromeClient(new EssWebChromeClient(H5Activity.this));

thus ,webview Implemented on h5 Taking pictures , And the video function is complete .

Original statement , This article is authorized by the author + Community publication , Unauthorized , Shall not be reproduced .

If there is any infringement , Please contact the yunjia_community@tencent.com Delete .

版权声明
本文为[brzhang]所创,转载请带上原文链接,感谢
https://chowdera.com/2021/01/20210123183234379B.html

随机推荐