SoFunction
Updated on 2025-04-05

Examples of uploading files in Android WebView

Recently, the company's project needs to call the mobile phone system album on WebView to upload pictures. During the development process, it was found that the system album could not be called normally on many machines to select pictures.

Before solving the problem, let’s talk about the logic of uploading files in WebView: When we click the control (<input type="file">) of the selected file on the web page, openFileChooser() under WebChromeClient will be called back (onShowFileChooser() system callback 5.0 and above). At this time, we use the Intent to open the system album or a third-party application that supports the Intent to select images. like this:

public void openFileChooser(ValueCallback<Uri> valueCallback, String acceptType, String capture) {
 uploadMessage = valueCallback;
  openImageChooserActivity();
}

private void openImageChooserActivity() {
 Intent i = new Intent(Intent.ACTION_GET_CONTENT);
 (Intent.CATEGORY_OPENABLE);
 ("image/*");
 startActivityForResult((i, 
    "Image Chooser"), FILE_CHOOSER_RESULT_CODE);
}

Finally, in onActivityResult(), we return the selected image content to the WebView through the onReceiveValue method of ValueCallback, and then upload it through js. The code is as follows:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
 (requestCode, resultCode, data);
 if (requestCode == FILE_CHOOSER_RESULT_CODE) {
  Uri result = data == null || resultCode != RESULT_OK ? null : ();
  if (uploadMessage != null) {
   (result);
   uploadMessage = null;
  }
 }
}

PS:ValueCallbacks is provided to us by the WebView component through openFileChooser() or onShowFileChooser(). It contains one or a group of Uri. Then we pass the Uri to the onReceiveValue() method in the onActivityResult(), so that the WebView knows what file we selected.

(new WebChromeClient() {

  // For Android < 3.0
  public void openFileChooser(ValueCallback<Uri> valueCallback) {
   ***
  }

  // For Android >= 3.0
  public void openFileChooser(ValueCallback valueCallback, String acceptType) {
   ***
  }

  //For Android >= 4.1
  public void openFileChooser(ValueCallback<Uri> valueCallback, 
    String acceptType, String capture) {
   ***
  }

  // For Android >= 5.0
  @Override
  public boolean onShowFileChooser(WebView webView, 
    ValueCallback<Uri[]> filePathCallback, 
     fileChooserParams) {
   ***
   return true;
  }
 });

You may have to ask here, after saying so much, I still haven't explained why it is impossible to call up the system album or third-party app to select pictures on many models? ! This is because the Google Siege Lions have made many modifications to the openFileChooser in order to achieve the most perfection, and in 5.0, the callback method should be used for onShowFileChooser. So in order to solve this problem and be compatible with each version, we need to overload openFileChooser() and provide the onShowFileChooser() method for systems 5.0 and above:

(new WebChromeClient() {

  // For Android < 3.0
  public void openFileChooser(ValueCallback<Uri> valueCallback) {
   ***
  }

  // For Android >= 3.0
  public void openFileChooser(ValueCallback valueCallback, String acceptType) {
   ***
  }

  //For Android >= 4.1
  public void openFileChooser(ValueCallback<Uri> valueCallback, 
    String acceptType, String capture) {
   ***
  }

  // For Android >= 5.0
  @Override
  public boolean onShowFileChooser(WebView webView, 
    ValueCallback<Uri[]> filePathCallback, 
     fileChooserParams) {
   ***
   return true;
  }
 });

You should note that the ValueCallback in onShowFileChooser() contains a set of Uri(Uri[]), so for systems 5.0 and above, we also need to do a little bit of processing onActivityResult(). I won't describe it here, and I'll post the complete code in the end.

After dealing with these, do you think everything will be fine? ! I was so naive at the beginning, but when we finished the release package testing, we found that we could not choose the picture! ! ! What a scam! ! ! I had no choice but to search the source code of WebChromeClient and found that openFileChooser() is the system API, and our release package is openFileChooser(), so it is confused when packaging, which leads to the inability to call back openFileChooser().

/**
 * Tell the client to open a file chooser.
 * @param uploadFile A ValueCallback to set the URI of the file to upload.
 *  onReceiveValue must be called to wake up the 
 * @param acceptType The value of the 'accept' attribute of the input tag
 *   associated with this file picker.
 * @param capture The value of the 'capture' attribute of the input tag
 *   associated with this file picker.
 *
 * @deprecated Use {@link #showFileChooser} instead.
 * @hide This method was not published in any SDK version.
 */
@SystemApi
@Deprecated
public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType, String capture) {
 (null);
}

The solution is also very simple, just don't confuse openFileChooser().

-keepclassmembers class * extends {
  public void openFileChooser(...);
}

All pitfalls supporting uploading files have been filled out, and finally the complete source code is attached:

public class MainActivity extends AppCompatActivity {

 private ValueCallback<Uri> uploadMessage;
 private ValueCallback<Uri[]> uploadMessageAboveL;
 private final static int FILE_CHOOSER_RESULT_CODE = 10000;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  (savedInstanceState);
  setContentView(.activity_main);

  WebView webview = (WebView) findViewById(.web_view);
  assert webview != null;
  WebSettings settings = ();
  (true);
  (true);
  (true);
  (new WebChromeClient() {

   // For Android < 3.0
   public void openFileChooser(ValueCallback<Uri> valueCallback) {
    uploadMessage = valueCallback;
    openImageChooserActivity();
   }

   // For Android >= 3.0
   public void openFileChooser(ValueCallback valueCallback, String acceptType) {
    uploadMessage = valueCallback;
    openImageChooserActivity();
   }

   //For Android >= 4.1
   public void openFileChooser(ValueCallback<Uri> valueCallback, String acceptType, String capture) {
    uploadMessage = valueCallback;
    openImageChooserActivity();
   }

   // For Android >= 5.0
   @Override
   public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,  fileChooserParams) {
    uploadMessageAboveL = filePathCallback;
    openImageChooserActivity();
    return true;
   }
  });
  String targetUrl = "file:///android_asset/";
  (targetUrl);
 }

 private void openImageChooserActivity() {
  Intent i = new Intent(Intent.ACTION_GET_CONTENT);
  (Intent.CATEGORY_OPENABLE);
  ("image/*");
  startActivityForResult((i, "Image Chooser"), FILE_CHOOSER_RESULT_CODE);
 }

 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  (requestCode, resultCode, data);
  if (requestCode == FILE_CHOOSER_RESULT_CODE) {
   if (null == uploadMessage && null == uploadMessageAboveL) return;
   Uri result = data == null || resultCode != RESULT_OK ? null : ();
   if (uploadMessageAboveL != null) {
    onActivityResultAboveL(requestCode, resultCode, data);
   } else if (uploadMessage != null) {
    (result);
    uploadMessage = null;
   }
  }
 }

 @TargetApi(Build.VERSION_CODES.LOLLIPOP)
 private void onActivityResultAboveL(int requestCode, int resultCode, Intent intent) {
  if (requestCode != FILE_CHOOSER_RESULT_CODE || uploadMessageAboveL == null)
   return;
  Uri[] results = null;
  if (resultCode == Activity.RESULT_OK) {
   if (intent != null) {
    String dataString = ();
    ClipData clipData = ();
    if (clipData != null) {
     results = new Uri[()];
     for (int i = 0; i < (); i++) {
       item = (i);
      results[i] = ();
     }
    }
    if (dataString != null)
     results = new Uri[]{(dataString)};
   }
  }
  (results);
  uploadMessageAboveL = null;
 }
}

Source code address:http://xiazai./201701/yuanma/WebViewSample_jb51.rar

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.