onShowFileChooser() from android webview works only once
firstly, sorry to my english. you should return empty Uri[]{} to file receive
mUploadMessageForAndroid5.onReceiveValue(new Uri[]{});
my code can choose take photo or local image:
private static final int REQUEST_GET_THE_THUMBNAIL = 4000;private static final long ANIMATION_DURATION = 200;public final static int FILECHOOSER_RESULTCODE = 1;public final static int FILECHOOSER_RESULTCODE_FOR_ANDROID_5 = 2;//JSwebView.getSettings().setJavaScriptEnabled(true);//set ChromeClientwebView.setWebChromeClient(getChromeClient());//ChromeClinet配置private WebChromeClient getChromeClient() { return new WebChromeClient() { //3.0++ public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) { openFileChooserImpl(uploadMsg); } //3.0-- public void openFileChooser(ValueCallback<Uri> uploadMsg) { openFileChooserImpl(uploadMsg); } public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) { openFileChooserImpl(uploadMsg); } // For Android > 5.0 public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> uploadMsg, WebChromeClient.FileChooserParams fileChooserParams) { openFileChooserImplForAndroid5(uploadMsg); return true; } };}private void openFileChooserImpl(ValueCallback<Uri> uploadMsg) { mUploadMessage = uploadMsg; new AlertDialog.Builder(mActivity) .setItems(items, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (items[which].equals(items[0])) { Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("image/*"); startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE); } else if (items[which].equals(items[1])) { dispatchTakePictureIntent(); } dialog.dismiss(); } }) .setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { Log.v(TAG, TAG + " # onCancel"); mUploadMessage = null; dialog.dismiss(); }}) .show();}private void openFileChooserImplForAndroid5(ValueCallback<Uri[]> uploadMsg) { mUploadMessageForAndroid5 = uploadMsg; new AlertDialog.Builder(mActivity) .setItems(items, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (items[which].equals(items[0])) { Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT); contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE); contentSelectionIntent.setType("image/*"); Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER); chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent); chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser"); startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE_FOR_ANDROID_5); } else if (items[which].equals(items[1])) { dispatchTakePictureIntent(); } dialog.dismiss(); } }) .setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { Log.v(TAG, TAG + " # onCancel"); //important to return new Uri[]{}, when nothing to do. This can slove input file wrok for once. //InputEventReceiver: Attempted to finish an input event but the input event receiver has already been disposed. mUploadMessageForAndroid5.onReceiveValue(new Uri[]{}); mUploadMessageForAndroid5 = null; dialog.dismiss(); }}).show();}private void dispatchTakePictureIntent() { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (takePictureIntent.resolveActivity(mActivity.getPackageManager()) != null) {// File file = new File(createImageFile()); Uri imageUri = null; try { imageUri = Uri.fromFile(createImageFile()); } catch (IOException e) { e.printStackTrace(); } //temp sd card file takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); startActivityForResult(takePictureIntent, REQUEST_GET_THE_THUMBNAIL); }}private File createImageFile() throws IOException { // Create an image file name String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = "JPEG_" + timeStamp + "_"; File storageDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/don_test/"); if (!storageDir.exists()) { storageDir.mkdirs(); } File image = File.createTempFile( imageFileName, /* prefix */ ".jpg", /* suffix */ storageDir /* directory */ ); // Save a file: path for use with ACTION_VIEW intents mCurrentPhotoPath = image.getAbsolutePath(); return image;}@Overridepublic void onActivityResult(int requestCode, int resultCode, Intent intent) { Log.v(TAG, TAG + " # onActivityResult # requestCode=" + requestCode + " # resultCode=" + resultCode); if (requestCode == FILECHOOSER_RESULTCODE) { if (null == mUploadMessage) return; Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData(); mUploadMessage.onReceiveValue(result); mUploadMessage = null; } else if (requestCode == FILECHOOSER_RESULTCODE_FOR_ANDROID_5) { if (null == mUploadMessageForAndroid5) return; Uri result; if (intent == null || resultCode != Activity.RESULT_OK) { result = null; } else { result = intent.getData(); } if (result != null) { Log.v(TAG, TAG + " # result.getPath()=" + result.getPath()); mUploadMessageForAndroid5.onReceiveValue(new Uri[]{result}); } else { mUploadMessageForAndroid5.onReceiveValue(new Uri[]{}); } mUploadMessageForAndroid5 = null; } else if (requestCode == REQUEST_GET_THE_THUMBNAIL) { if (resultCode == Activity.RESULT_OK) { File file = new File(mCurrentPhotoPath); Uri localUri = Uri.fromFile(file); Intent localIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, localUri); mActivity.sendBroadcast(localIntent); Uri result = Uri.fromFile(file); mUploadMessageForAndroid5.onReceiveValue(new Uri[]{result}); mUploadMessageForAndroid5 = null; } else { File file = new File(mCurrentPhotoPath); Log.v(TAG, TAG + " # file=" + file.exists()); if (file.exists()) { file.delete(); } } }}
Faced similar problem i was returning boolean value in method onShowFileChooser, issue was fixed when i called super class method
@Override public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) { //Logic to implement return super.onShowFileChooser(webView, filePathCallback, fileChooserParams); }
In the onShowFileChooser() method you should return true
, only if you are using the filePathCallback
, which is the best way:
private ValueCallback<Uri[]> filePathCallback;@Overridepublic boolean onShowFileChooser( WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) { // do whatever you need to do, to show a file chooser/camera intent this.filePathCallback = filePathCallback; return true;}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent intent) { // Check for your correct requestCode from your intent here if (resultCode == RESULT_CANCELED) { // this is important, call the callback with null parameter this.filePathCallback.onReceiveValue(null); } else if (resultCode == RESULT_OK) { // extract the uri(s) you need here this.filePathCallback.onReceiveValue(new Uri[]{result}); }}