Android WebView supports input file enables camera and photo selection function

  • 2021-11-13 02:38:11
  • OfStack

If webview wants to adjust input-file photo or file selection function, it can rewrite the specified method in webview. setWebChromeClient method to intercept input event of webview and do our corresponding operation.

Android code


webView.setWebChromeClient(new WebChromeClient() {
      @Override
      public void onProgressChanged(WebView view, int newProgress) {
        if (newProgress == 100) {
          progressBar.setVisibility(View.GONE);// The progress bar disappears after loading the web page 
        } else {
          progressBar.setProgress(newProgress);// Setting progress values 
          progressBar.setVisibility(View.VISIBLE);// Show the progress bar when you start loading the web page 
        }
      }
 
      /**
       * 8(Android 2.2) <= API <= 10(Android 2.3) Callback this method 
       */
      private void openFileChooser(android.webkit.ValueCallback<Uri> uploadMsg) {
        Log.e("WangJ", " Operation method  openFileChooser-1");
        // (2) When this method calls back, it explains the version API < 21 At this point, assign the result to the  mUploadCallbackBelow , make it  != null
        mUploadCallbackBelow = uploadMsg;
        takePhoto();
      }
 
      /**
       * 11(Android 3.0) <= API <= 15(Android 4.0.3) Callback this method 
       */
      public void openFileChooser(android.webkit.ValueCallback<Uri> uploadMsg, String acceptType) {
        Log.e("WangJ", " Operation method  openFileChooser-2 (acceptType: " + acceptType + ")");
        //  We don't distinguish here input Parameters, take pictures directly 
        openFileChooser(uploadMsg);
      }
 
      /**
       * 16(Android 4.1.2) <= API <= 20(Android 4.4W.2) Callback this method 
       */
      public void openFileChooser(android.webkit.ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
        Log.e("WangJ", " Operation method  openFileChooser-3 (acceptType: " + acceptType + "; capture: " + capture + ")");
        //  We don't distinguish here input Parameters, take pictures directly 
        openFileChooser(uploadMsg);
      }
 
      /**
       * API >= 21(Android 5.0.1) Callback this method 
       */
      @Override
      public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> valueCallback, FileChooserParams fileChooserParams) {
        Log.e("WangJ", " Operation method  onShowFileChooser");
        // (1) When this method calls back, it explains the version API >= 21 At this point, assign the result to the  mUploadCallbackAboveL , make it  != null
        mUploadCallbackAboveL = valueCallback;
        takePhoto();
        return true;
      }
    });

The java code here is to intercept input events, which makes a lot of judgments about api versions. Different versions of api call different methods, and the following are 1 other methods:

Method of adjusting camera/selecting file: takePhoto ();


 /**
   *  Call camera 
   */
  private void takePhoto() {
    //  Turn up the camera by specifying the storage location for taking pictures 
    String filePath = Environment.getExternalStorageDirectory() + File.separator
        + Environment.DIRECTORY_PICTURES + File.separator;
    String fileName = "IMG_" + DateFormat.format("yyyyMMdd_hhmmss", Calendar.getInstance(Locale.CHINA)) + ".jpg";
    imageUri = Uri.fromFile(new File(filePath + fileName));
 
//    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//    intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
//    startActivityForResult(intent, REQUEST_CODE);
 
    //  Select pictures (excluding camera photos) , You do not need to post a broadcast that refreshes the gallery after success 
//    Intent i = new Intent(Intent.ACTION_GET_CONTENT);
//    i.addCategory(Intent.CATEGORY_OPENABLE);
//    i.setType("image/*");
//    startActivityForResult(Intent.createChooser(i, "Image Chooser"), REQUEST_CODE);
 
    Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
    captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
 
    Intent Photo = new Intent(Intent.ACTION_PICK,
        android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
 
    Intent chooserIntent = Intent.createChooser(Photo, "Image Chooser");
    chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Parcelable[]{captureIntent});
 
    startActivityForResult(chooserIntent, REQUEST_CODE);
  }
onActivityResult Callback: 
@Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_CODE) {
      //  Pass up (1) , (2) Two assignment operations, where you can decide which processing method to use according to whether their values are empty or not 
      if (mUploadCallbackBelow != null) {
        chooseBelow(resultCode, data);
      } else if (mUploadCallbackAboveL != null) {
        chooseAbove(resultCode, data);
      } else {
        Toast.makeText(this, " An error occurred ", Toast.LENGTH_SHORT).show();
      }
    }
  }

One other method:


/**
   * Android API < 21(Android 5.0) Version callback processing 
   * @param resultCode  Select the return code of the file or photo 
   * @param data  Select the return result of a file or photo 
   */
  private void chooseBelow(int resultCode, Intent data) {
    Log.e("WangJ", " Returns the calling method --chooseBelow");
 
    if (RESULT_OK == resultCode) {
      updatePhotos();
 
      if (data != null) {
        //  This is for file path processing 
        Uri uri = data.getData();
        if (uri != null) {
          Log.e("WangJ", " System return URI : " + uri.toString());
          mUploadCallbackBelow.onReceiveValue(uri);
        } else {
          mUploadCallbackBelow.onReceiveValue(null);
        }
      } else {
        //  Set up the camera in the way of specifying the image storage path, and return after success data Empty 
        Log.e("WangJ", " Customize results: " + imageUri.toString());
        mUploadCallbackBelow.onReceiveValue(imageUri);
      }
    } else {
      mUploadCallbackBelow.onReceiveValue(null);
    }
    mUploadCallbackBelow = null;
  }
 
  /**
   * Android API >= 21(Android 5.0)  Version callback processing 
   * @param resultCode  Select the return code of the file or photo 
   * @param data  Select the return result of a file or photo 
   */
  private void chooseAbove(int resultCode, Intent data) {
    Log.e("WangJ", " Returns the calling method --chooseAbove");
 
    if (RESULT_OK == resultCode) {
      updatePhotos();
 
      if (data != null) {
        //  This is the processing of selecting pictures from files 
        Uri[] results;
        Uri uriData = data.getData();
        if (uriData != null) {
          results = new Uri[]{uriData};
          for (Uri uri : results) {
            Log.e("WangJ", " System return URI : " + uri.toString());
          }
          mUploadCallbackAboveL.onReceiveValue(results);
        } else {
          mUploadCallbackAboveL.onReceiveValue(null);
        }
      } else {
        Log.e("WangJ", " Customize results: " + imageUri.toString());
        mUploadCallbackAboveL.onReceiveValue(new Uri[]{imageUri});
      }
    } else {
      mUploadCallbackAboveL.onReceiveValue(null);
    }
    mUploadCallbackAboveL = null;
  }
 
  private void updatePhotos() {
    //  It doesn't matter if the broadcast is multiple (that is, it will be sent when the photo selection is successful), just wake up the system and refresh the media file 
    Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    intent.setData(imageUri);
    sendBroadcast(intent);
  }

Related global variables:


private android.webkit.ValueCallback<Uri[]> mUploadCallbackAboveL;
private android.webkit.ValueCallback<Uri> mUploadCallbackBelow;
private Uri imageUri;
private int REQUEST_CODE = 1234;

Summarize


Related articles: