Téléchargement de fichier dans WebView

J’ai eu du mal à télécharger des fichiers depuis WebView depuis quelques jours et il n’y a pas de progrès. J’ai googlé et implémenté toutes les solutions suggérées mais aucune ne fonctionne, comme: les solutions suggérées ici – Webview Android, le champ de saisie de fichier filechooser ne s’affiche pas …, http://blog.tourizo.com/2009/02/how-to -display-local-file-in-android …. et ainsi de suite.

Problème: j’ai une page HTML avec le code suivant pour télécharger un fichier. Cela fonctionne très bien dans un navigateur de bureau comme Firefox et navigateur intégré de l’émulateur / AVD, c’est-à-dire que lorsque je clique sur le bouton “Parcourir …” rendu par élément, le navigateur ouvre une boîte de dialog dans laquelle je peux choisir

Cependant, dans l’émulateur Android 3.0 / AVD, lorsque je clique sur “Choisir un fichier”, rien ne se passe, aucune boîte de dialog de fichier ne s’ouvre!

File to upload:    to upload the file!

Quelqu’un pourrait-il suggérer une solution possible au plus tôt?

Ceci est une solution complète pour toutes les versions Android, j’ai eu un moment difficile avec cela aussi.

 public class MyWb extends Activity { /** Called when the activity is first created. */ WebView web; ProgressBar progressBar; private ValueCallback mUploadMessage; private final static int FILECHOOSER_RESULTCODE=1; @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { if(requestCode==FILECHOOSER_RESULTCODE) { if (null == mUploadMessage) return; Uri result = intent == null || resultCode != RESULT_OK ? null : intent.getData(); mUploadMessage.onReceiveValue(result); mUploadMessage = null; } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); web = (WebView) findViewById(R.id.webview01); progressBar = (ProgressBar) findViewById(R.id.progressBar1); web = new WebView(this); web.getSettings().setJavaScriptEnabled(true); web.loadUrl("http://www.script-tutorials.com/demos/199/index.html"); web.setWebViewClient(new myWebClient()); web.setWebChromeClient(new WebChromeClient() { //The undocumented magic method override //Eclipse will swear at you if you try to put @Override here // For Android 3.0+ public void openFileChooser(ValueCallback uploadMsg) { mUploadMessage = uploadMsg; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("image/*"); MyWb.this.startActivityForResult(Intent.createChooser(i,"File Chooser"), FILECHOOSER_RESULTCODE); } // For Android 3.0+ public void openFileChooser( ValueCallback uploadMsg, Ssortingng acceptType ) { mUploadMessage = uploadMsg; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("*/*"); MyWb.this.startActivityForResult( Intent.createChooser(i, "File Browser"), FILECHOOSER_RESULTCODE); } //For Android 4.1 public void openFileChooser(ValueCallback uploadMsg, Ssortingng acceptType, Ssortingng capture){ mUploadMessage = uploadMsg; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("image/*"); MyWb.this.startActivityForResult( Intent.createChooser( i, "File Chooser" ), MyWb.FILECHOOSER_RESULTCODE ); } }); setContentView(web); } public class myWebClient extends WebViewClient { @Override public void onPageStarted(WebView view, Ssortingng url, Bitmap favicon) { // TODO Auto-generated method stub super.onPageStarted(view, url, favicon); } @Override public boolean shouldOverrideUrlLoading(WebView view, Ssortingng url) { // TODO Auto-generated method stub view.loadUrl(url); return true; } @Override public void onPageFinished(WebView view, Ssortingng url) { // TODO Auto-generated method stub super.onPageFinished(view, url); progressBar.setVisibility(View.GONE); } } //flipscreen not loading again @Override public void onConfigurationChanged(Configuration newConfig){ super.onConfigurationChanged(newConfig); } // To handle "Back" key press event for WebView to go back to previous screen. /*@Override public boolean onKeyDown(int keyCode, KeyEvent event) { if ((keyCode == KeyEvent.KEYCODE_BACK) && web.canGoBack()) { web.goBack(); return true; } return super.onKeyDown(keyCode, event); }*/ } 

Je tiens également à append que la “page de téléchargement” comme celle de cet exemple, ne fonctionnera pas sur <4 versions, car il a une fonctionnalité de prévisualisation d'image, si vous voulez le faire fonctionner, utilisez un simple téléchargement PHP sans prévisualisation.

Mise à jour :

S’il vous plaît trouver la solution pour les dispositifs de sucette ici et merci pour gauntface

Mise à jour 2 :

Une solution complète pour tous les appareils Android jusqu’à ici, et cette version est plus avancée , vous devriez y jeter un coup d’œil, peut-être que cela peut vous aider.

Méthode de travail de HONEYCOMB (API 11) à Marshmallow (API 23)

 static WebView mWebView; private ValueCallback mUploadMessage; public ValueCallback uploadMessage; public static final int REQUEST_SELECT_FILE = 100; private final static int FILECHOOSER_RESULTCODE = 1; 

Modifié onActivityResult()

 @Override public void onActivityResult(int requestCode, int resultCode, Intent intent) { if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (requestCode == REQUEST_SELECT_FILE) { if (uploadMessage == null) return; uploadMessage.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, intent)); uploadMessage = null; } } else if (requestCode == FILECHOOSER_RESULTCODE) { if (null == mUploadMessage) return; // Use MainActivity.RESULT_OK if you're implementing WebView inside Fragment // Use RESULT_OK only if you're implementing WebView inside an Activity Uri result = intent == null || resultCode != MainActivity.RESULT_OK ? null : intent.getData(); mUploadMessage.onReceiveValue(result); mUploadMessage = null; } else Toast.makeText(getActivity().getApplicationContext(), "Failed to Upload Image", Toast.LENGTH_LONG).show(); } 

Maintenant dans onCreate() ou onCreateView() collez le code suivant

  WebSettings mWebSettings = mWebView.getSettings(); mWebSettings.setJavaScriptEnabled(true); mWebSettings.setSupportZoom(false); mWebSettings.setAllowFileAccess(true); mWebSettings.setAllowFileAccess(true); mWebSettings.setAllowContentAccess(true); mWebView.setWebChromeClient(new WebChromeClient() { // For 3.0+ Devices (Start) // onActivityResult attached before constructor protected void openFileChooser(ValueCallback uploadMsg, Ssortingng acceptType) { mUploadMessage = uploadMsg; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("image/*"); startActivityForResult(Intent.createChooser(i, "File Browser"), FILECHOOSER_RESULTCODE); } // For Lollipop 5.0+ Devices public boolean onShowFileChooser(WebView mWebView, ValueCallback filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) { if (uploadMessage != null) { uploadMessage.onReceiveValue(null); uploadMessage = null; } uploadMessage = filePathCallback; Intent intent = fileChooserParams.createIntent(); try { startActivityForResult(intent, REQUEST_SELECT_FILE); } catch (ActivityNotFoundException e) { uploadMessage = null; Toast.makeText(getActivity().getApplicationContext(), "Cannot Open File Chooser", Toast.LENGTH_LONG).show(); return false; } return true; } //For Android 4.1 only protected void openFileChooser(ValueCallback uploadMsg, Ssortingng acceptType, Ssortingng capture) { mUploadMessage = uploadMsg; Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("image/*"); startActivityForResult(Intent.createChooser(intent, "File Browser"), FILECHOOSER_RESULTCODE); } protected void openFileChooser(ValueCallback uploadMsg) { mUploadMessage = uploadMsg; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("image/*"); startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE); } }); 

c’est la seule solution que j’ai trouvée qui fonctionne!

 WebView webview; private ValueCallback mUploadMessage; private final static int FILECHOOSER_RESULTCODE = 1; @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { if (requestCode == FILECHOOSER_RESULTCODE) { if (null == mUploadMessage) return; Uri result = intent == null || resultCode != RESULT_OK ? null : intent.getData(); mUploadMessage.onReceiveValue(result); mUploadMessage = null; } } // Next part class MyWebChromeClient extends WebChromeClient { // The undocumented magic method override // Eclipse will swear at you if you try to put @Override here public void openFileChooser(ValueCallback uploadMsg) { mUploadMessage = uploadMsg; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("image/*"); Cv5appActivity.this.startActivityForResult( Intent.createChooser(i, "Image Browser"), FILECHOOSER_RESULTCODE); } } 

Dans 5.0 Lollipop, Google a ajouté une méthode officielle, WebChromeClient.onShowFileChooser . Ils fournissent même un moyen de générer automatiquement l’intention du sélecteur de fichier afin qu’il utilise les types MIME acceptant l’entrée.

 public class MyWebChromeClient extends WebChromeClient { // reference to activity instance. May be unnecessary if your web chrome client is member class. private MyActivity activity; public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, FileChooserParams fileChooserParams) { // make sure there is no existing message if (myActivity.uploadMessage != null) { myActivity.uploadMessage.onReceiveValue(null); myActivity.uploadMessage = null; } myActivity.uploadMessage = filePathCallback; Intent intent = fileChooserParams.createIntent(); try { myActivity.startActivityForResult(intent, MyActivity.REQUEST_SELECT_FILE); } catch (ActivityNotFoundException e) { myActivity.uploadMessage = null; Toast.makeText(myActivity, "Cannot open file chooser", Toast.LENGTH_LONG).show(); return false; } return true; } } public class MyActivity extends ... { public static final int REQUEST_SELECT_FILE = 100; public ValueCallback uploadMessage; protected void onActivityResult(int requestCode, int resultCode, Intent data){ if (requestCode == REQUEST_SELECT_FILE) { if (uploadMessage == null) return; uploadMessage.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, data)); uploadMessage = null; } } } } 

Pour les versions Android antérieures à KitKat, les méthodes privées mentionnées dans les autres réponses fonctionnent. Je n’ai pas trouvé de solution de contournement pour KitKat (4.4).

J’ai trouvé que j’avais besoin de 3 définitions d’interface pour gérer différentes versions d’Android.

 public void openFileChooser(ValueCallback < Uri > uploadMsg) { mUploadMessage = uploadMsg; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("image/*"); FreeHealthTrack.this.startActivityForResult(Intent.createChooser(i, "Image Chooser"), FILECHOOSER_RESULTCODE); } public void openFileChooser(ValueCallback < Uri > uploadMsg, Ssortingng acceptType) { openFileChooser(uploadMsg); } public void openFileChooser(ValueCallback < Uri > uploadMsg, Ssortingng acceptType, Ssortingng capture) { openFileChooser(uploadMsg); } 

Cette solution fonctionne également pour Honeycomb et Ice Cream Sandwich. On dirait que Google a introduit une nouvelle fonctionnalité intéressante (atsortingbut accept) et a oublié de mettre en œuvre une surcharge pour assurer la rétrocompatibilité.

 protected class CustomWebChromeClient extends WebChromeClient { // For Android 3.0+ public void openFileChooser( ValueCallback uploadMsg, Ssortingng acceptType ) { context.mUploadMessage = uploadMsg; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("image/*"); context.startActivityForResult( Intent.createChooser( i, "File Chooser" ), MainActivity.FILECHOOSER_RESULTCODE ); } // For Android < 3.0 public void openFileChooser( ValueCallback uploadMsg ) { openFileChooser( uploadMsg, "" ); } } 

La solution complète de hifarrer est très utile pour moi.

mais, j’ai rencontré beaucoup d’autres problèmes – supportant d’autres types de mimes, listant les périphériques de capture (appareil photo, vidéo, enregistreur audio), ouvrant immédiatement le périphérique de capture (ex: ) …

J’ai donc conçu une solution qui fonctionne exactement comme une application de navigateur Web par défaut.

J’ai utilisé android-4.4.3_r1 / src / com / android / browser / UploadHandler.java. (merci à Rupert Rawnsley)

 package org.mospi.agatenativewebview; import java.io.File; import java.lang.reflect.Method; import java.net.URL; import android.app.Activity; import android.app.AlertDialog; import android.content.ActivityNotFoundException; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.view.View; import android.webkit.JsResult; import android.webkit.ValueCallback; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebSettings.PluginState; import android.widget.Toast; public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); WebView webView = (WebView) findViewById(R.id.webView1); initWebView(webView); webView.loadUrl("http://google.com"); // TODO input your url } private final static Object methodInvoke(Object obj, Ssortingng method, Class< ?>[] parameterTypes, Object[] args) { try { Method m = obj.getClass().getMethod(method, new Class[] { boolean.class }); m.invoke(obj, args); } catch (Exception e) { e.printStackTrace(); } return null; } private void initWebView(WebView webView) { WebSettings settings = webView.getSettings(); settings.setJavaScriptEnabled(true); settings.setAllowFileAccess(true); settings.setDomStorageEnabled(true); settings.setCacheMode(WebSettings.LOAD_NO_CACHE); settings.setLoadWithOverviewMode(true); settings.setUseWideViewPort(true); settings.setSupportZoom(true); // settings.setPluginsEnabled(true); methodInvoke(settings, "setPluginsEnabled", new Class[] { boolean.class }, new Object[] { true }); // settings.setPluginState(PluginState.ON); methodInvoke(settings, "setPluginState", new Class[] { PluginState.class }, new Object[] { PluginState.ON }); // settings.setPluginsEnabled(true); methodInvoke(settings, "setPluginsEnabled", new Class[] { boolean.class }, new Object[] { true }); // settings.setAllowUniversalAccessFromFileURLs(true); methodInvoke(settings, "setAllowUniversalAccessFromFileURLs", new Class[] { boolean.class }, new Object[] { true }); // settings.setAllowFileAccessFromFileURLs(true); methodInvoke(settings, "setAllowFileAccessFromFileURLs", new Class[] { boolean.class }, new Object[] { true }); webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY); webView.clearHistory(); webView.clearFormData(); webView.clearCache(true); webView.setWebChromeClient(new MyWebChromeClient()); // webView.setDownloadListener(downloadListener); } UploadHandler mUploadHandler; @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { if (requestCode == Controller.FILE_SELECTED) { // Chose a file from the file picker. if (mUploadHandler != null) { mUploadHandler.onResult(resultCode, intent); } } super.onActivityResult(requestCode, resultCode, intent); } class MyWebChromeClient extends WebChromeClient { public MyWebChromeClient() { } private Ssortingng getTitleFromUrl(Ssortingng url) { Ssortingng title = url; try { URL urlObj = new URL(url); Ssortingng host = urlObj.getHost(); if (host != null && !host.isEmpty()) { return urlObj.getProtocol() + "://" + host; } if (url.startsWith("file:")) { Ssortingng fileName = urlObj.getFile(); if (fileName != null && !fileName.isEmpty()) { return fileName; } } } catch (Exception e) { // ignore } return title; } @Override public boolean onJsAlert(WebView view, Ssortingng url, Ssortingng message, final JsResult result) { Ssortingng newTitle = getTitleFromUrl(url); new AlertDialog.Builder(MainActivity.this).setTitle(newTitle).setMessage(message).setPositiveButton(android.R.ssortingng.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { result.confirm(); } }).setCancelable(false).create().show(); return true; // return super.onJsAlert(view, url, message, result); } @Override public boolean onJsConfirm(WebView view, Ssortingng url, Ssortingng message, final JsResult result) { Ssortingng newTitle = getTitleFromUrl(url); new AlertDialog.Builder(MainActivity.this).setTitle(newTitle).setMessage(message).setPositiveButton(android.R.ssortingng.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { result.confirm(); } }).setNegativeButton(android.R.ssortingng.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { result.cancel(); } }).setCancelable(false).create().show(); return true; // return super.onJsConfirm(view, url, message, result); } // Android 2.x public void openFileChooser(ValueCallback uploadMsg) { openFileChooser(uploadMsg, ""); } // Android 3.0 public void openFileChooser(ValueCallback uploadMsg, Ssortingng acceptType) { openFileChooser(uploadMsg, "", "filesystem"); } // Android 4.1 public void openFileChooser(ValueCallback uploadMsg, Ssortingng acceptType, Ssortingng capture) { mUploadHandler = new UploadHandler(new Controller()); mUploadHandler.openFileChooser(uploadMsg, acceptType, capture); } // Android 4.4, 4.4.1, 4.4.2 // openFileChooser function is not called on Android 4.4, 4.4.1, 4.4.2, // you may use your own java script interface or other hybrid framework. // Android 5.0.1 public boolean onShowFileChooser( WebView webView, ValueCallback filePathCallback, FileChooserParams fileChooserParams) { Ssortingng acceptTypes[] = fileChooserParams.getAcceptTypes(); Ssortingng acceptType = ""; for (int i = 0; i < acceptTypes.length; ++ i) { if (acceptTypes[i] != null && acceptTypes[i].length() != 0) acceptType += acceptTypes[i] + ";"; } if (acceptType.length() == 0) acceptType = "*/*"; final ValueCallback finalFilePathCallback = filePathCallback; ValueCallback vc = new ValueCallback() { @Override public void onReceiveValue(Uri value) { Uri[] result; if (value != null) result = new Uri[]{value}; else result = null; finalFilePathCallback.onReceiveValue(result); } }; openFileChooser(vc, acceptType, "filesystem"); return true; } }; class Controller { final static int FILE_SELECTED = 4; Activity getActivity() { return MainActivity.this; } } // copied from android-4.4.3_r1/src/com/android/browser/UploadHandler.java ////////////////////////////////////////////////////////////////////// /* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * dissortingbuted under the License is dissortingbuted on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // package com.android.browser; // // import android.app.Activity; // import android.content.ActivityNotFoundException; // import android.content.Intent; // import android.net.Uri; // import android.os.Environment; // import android.provider.MediaStore; // import android.webkit.ValueCallback; // import android.widget.Toast; // // import java.io.File; // import java.util.Vector; // // /** // * Handle the file upload callbacks from WebView here // */ // public class UploadHandler { class UploadHandler { /* * The Object used to inform the WebView of the file to upload. */ private ValueCallback mUploadMessage; private Ssortingng mCameraFilePath; private boolean mHandled; private boolean mCaughtActivityNotFoundException; private Controller mController; public UploadHandler(Controller controller) { mController = controller; } Ssortingng getFilePath() { return mCameraFilePath; } boolean handled() { return mHandled; } void onResult(int resultCode, Intent intent) { if (resultCode == Activity.RESULT_CANCELED && mCaughtActivityNotFoundException) { // Couldn't resolve an activity, we are going to try again so skip // this result. mCaughtActivityNotFoundException = false; return; } Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData(); // As we ask the camera to save the result of the user taking // a picture, the camera application does not return anything other // than RESULT_OK. So we need to check whether the file we expected // was written to disk in the in the case that we // did not get an intent returned but did get a RESULT_OK. If it was, // we assume that this result has came back from the camera. if (result == null && intent == null && resultCode == Activity.RESULT_OK) { File cameraFile = new File(mCameraFilePath); if (cameraFile.exists()) { result = Uri.fromFile(cameraFile); // Broadcast to the media scanner that we have a new photo // so it will be added into the gallery for the user. mController.getActivity().sendBroadcast( new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, result)); } } mUploadMessage.onReceiveValue(result); mHandled = true; mCaughtActivityNotFoundException = false; } void openFileChooser(ValueCallback uploadMsg, Ssortingng acceptType, Ssortingng capture) { final Ssortingng imageMimeType = "image/*"; final Ssortingng videoMimeType = "video/*"; final Ssortingng audioMimeType = "audio/*"; final Ssortingng mediaSourceKey = "capture"; final Ssortingng mediaSourceValueCamera = "camera"; final Ssortingng mediaSourceValueFileSystem = "filesystem"; final Ssortingng mediaSourceValueCamcorder = "camcorder"; final Ssortingng mediaSourceValueMicrophone = "microphone"; // According to the spec, media source can be 'filesystem' or 'camera' or 'camcorder' // or 'microphone' and the default value should be 'filesystem'. Ssortingng mediaSource = mediaSourceValueFileSystem; if (mUploadMessage != null) { // Already a file picker operation in progress. return; } mUploadMessage = uploadMsg; // Parse the accept type. Ssortingng params[] = acceptType.split(";"); Ssortingng mimeType = params[0]; if (capture.length() > 0) { mediaSource = capture; } if (capture.equals(mediaSourceValueFileSystem)) { // To maintain backwards compatibility with the previous implementation // of the media capture API, if the value of the 'capture' atsortingbute is // "filesystem", we should examine the accept-type for a MIME type that // may specify a different capture value. for (Ssortingng p : params) { Ssortingng[] keyValue = p.split("="); if (keyValue.length == 2) { // Process key=value parameters. if (mediaSourceKey.equals(keyValue[0])) { mediaSource = keyValue[1]; } } } } //Ensure it is not still set from a previous upload. mCameraFilePath = null; if (mimeType.equals(imageMimeType)) { if (mediaSource.equals(mediaSourceValueCamera)) { // Specified 'image/*' and requested the camera, so go ahead and launch the // camera directly. startActivity(createCameraIntent()); return; } else { // Specified just 'image/*', capture=filesystem, or an invalid capture parameter. // In all these cases we show a traditional picker filetered on accept type // so launch an intent for both the Camera and image/* OPENABLE. Intent chooser = createChooserIntent(createCameraIntent()); chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(imageMimeType)); startActivity(chooser); return; } } else if (mimeType.equals(videoMimeType)) { if (mediaSource.equals(mediaSourceValueCamcorder)) { // Specified 'video/*' and requested the camcorder, so go ahead and launch the // camcorder directly. startActivity(createCamcorderIntent()); return; } else { // Specified just 'video/*', capture=filesystem or an invalid capture parameter. // In all these cases we show an intent for the traditional file picker, filtered // on accept type so launch an intent for both camcorder and video/* OPENABLE. Intent chooser = createChooserIntent(createCamcorderIntent()); chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(videoMimeType)); startActivity(chooser); return; } } else if (mimeType.equals(audioMimeType)) { if (mediaSource.equals(mediaSourceValueMicrophone)) { // Specified 'audio/*' and requested microphone, so go ahead and launch the sound // recorder. startActivity(createSoundRecorderIntent()); return; } else { // Specified just 'audio/*', capture=filesystem of an invalid capture parameter. // In all these cases so go ahead and launch an intent for both the sound // recorder and audio/* OPENABLE. Intent chooser = createChooserIntent(createSoundRecorderIntent()); chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(audioMimeType)); startActivity(chooser); return; } } // No special handling based on the accept type was necessary, so sortinggger the default // file upload chooser. startActivity(createDefaultOpenableIntent()); } private void startActivity(Intent intent) { try { mController.getActivity().startActivityForResult(intent, Controller.FILE_SELECTED); } catch (ActivityNotFoundException e) { // No installed app was able to handle the intent that // we sent, so fallback to the default file upload control. try { mCaughtActivityNotFoundException = true; mController.getActivity().startActivityForResult(createDefaultOpenableIntent(), Controller.FILE_SELECTED); } catch (ActivityNotFoundException e2) { // Nothing can return us a file, so file upload is effectively disabled. Toast.makeText(mController.getActivity(), R.ssortingng.uploads_disabled, Toast.LENGTH_LONG).show(); } } } private Intent createDefaultOpenableIntent() { // Create and return a chooser with the default OPENABLE // actions including the camera, camcorder and sound // recorder where available. Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("*/*"); Intent chooser = createChooserIntent(createCameraIntent(), createCamcorderIntent(), createSoundRecorderIntent()); chooser.putExtra(Intent.EXTRA_INTENT, i); return chooser; } private Intent createChooserIntent(Intent... intents) { Intent chooser = new Intent(Intent.ACTION_CHOOSER); chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents); chooser.putExtra(Intent.EXTRA_TITLE, mController.getActivity().getResources() .getSsortingng(R.ssortingng.choose_upload)); return chooser; } private Intent createOpenableIntent(Ssortingng type) { Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType(type); return i; } private Intent createCameraIntent() { Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); File externalDataDir = Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_DCIM); File cameraDataDir = new File(externalDataDir.getAbsolutePath() + File.separator + "browser-photos"); cameraDataDir.mkdirs(); mCameraFilePath = cameraDataDir.getAbsolutePath() + File.separator + System.currentTimeMillis() + ".jpg"; cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mCameraFilePath))); return cameraIntent; } private Intent createCamcorderIntent() { return new Intent(MediaStore.ACTION_VIDEO_CAPTURE); } private Intent createSoundRecorderIntent() { return new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION); } } } 

resoruce de res / values ​​/ ssortingng.xml:

 File uploads are disabled. Choose file for upload 

Si vous utilisez proguard, vous pouvez avoir besoin de l’option ci-dessous dans proguard-project.txt:

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

MISE À JOUR # 1 (2015.09.09)

ajoute le code pour la compatibilité Android 5.0.1.

J’ai trouvé qu’il était nécessaire de définir public void openFileChooser(ValueCallback uploadMsg, Ssortingng acceptType, Ssortingng capture) dans Android 4.1. Puis j’ai suivi la solution de Michel Olivier.

J’ai réussi à faire apparaître le sélecteur de fichiers dans Kitkat, à sélectionner une image et à obtenir le chemin du fichier dans le résultat de l’activité, mais la seule chose que je ne peux pas “réparer” est de remplir l’entrée avec des données de fichier.

Est-ce que quelqu’un sait comment accéder au champ de saisie d’une activité? J’utilise cet exemple de commentaire . Est-ce juste ce dernier morceau, la dernière brique dans le mur que je dois juste mettre au bon endroit (mais je pourrais déclencher le téléchargement du fichier image directement à partir du code.

MISE À JOUR # 1

Je ne suis pas un hardcore Android, alors je vais montrer le code au niveau newbie. Im créer une nouvelle activité dans une activité déjà existante

Partie manifeste

      

Je crée ma classe BrowseActivity à partir de cet exemple de réponse . L’instance WebChromeClient () ressemble fondamentalement, sauf à la dernière pièce, qui déclenche le composant d’interface utilisateur du sélecteur …

 private final static int FILECHOOSER_RESULTCODE=1; private final static int KITKAT_RESULTCODE = 2; ... // The new WebChromeClient() looks pretty much the same, except one piece... WebChromeClient chromeClient = new WebChromeClient(){ // For Android 3.0+ public void openFileChooser(ValueCallback uploadMsg) { /* Default code */ } // For Android 3.0+ public void openFileChooser( ValueCallback uploadMsg, Ssortingng acceptType ) { /* Default code */ } //For Android 4.1, also default but it'll be as example public void openFileChooser(ValueCallback uploadMsg, Ssortingng acceptType, Ssortingng capture){ mUploadMessage = uploadMsg; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("*/*"); BrowseActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), BrowseActivity.FILECHOOSER_RESULTCODE); } // The new code public void showPicker( ValueCallback uploadMsg ){ // Here is part of the issue, the uploadMsg is null since it is not sortingggered from Android mUploadMessage = uploadMsg; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("*/*"); BrowseActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), BrowseActivity.KITKAT_RESULTCODE); }} 

And some more stuff

 web = new WebView(this); // Notice this part, setting chromeClient as js interface is just lazy web.getSettings().setJavaScriptEnabled(true); web.addJavascriptInterface(chromeClient, "jsi" ); web.getSettings().setAllowFileAccess(true); web.getSettings().setAllowContentAccess(true); web.clearCache(true); web.loadUrl( "http://as3breeze.com/upload.html" ); web.setWebViewClient(new myWebClient()); web.setWebChromeClient(chromeClient); @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { Log.d("Result", "("+requestCode+ ") - (" +resultCode + ") - (" + intent + ") - " + mUploadMessage); if (null == intent) return; Uri result = null; if(requestCode==FILECHOOSER_RESULTCODE) { Log.d("Result","Old android"); if (null == mUploadMessage) return; result = intent == null || resultCode != RESULT_OK ? null : intent.getData(); mUploadMessage.onReceiveValue(result); mUploadMessage = null; } else if (requestCode == KITKAT_RESULTCODE) { Log.d("Result","Kitkat android"); result = intent.getData(); final int takeFlags = intent.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); Ssortingng path = getPath( this, result); File selectedFile = new File(path); //I used you example with a bit of editing so thought i would share, here i added a method to upload the file to the webserver File selectedFile = new File(path); UploadFile(selectedFile); //mUploadMessage.onReceiveValue( Uri.parse(selectedFile.toSsortingng()) ); // Now we have the file but since mUploadMessage was null, it gets errors } } public void UploadFile(File selectedFile) { Random rnd = new Random(); Ssortingng sName = "File" + rnd.nextInt(999999) + selectedFile.getAbsolutePath().subssortingng(selectedFile.getAbsolutePath().lastIndexOf(".")); UploadedFileName = sName; uploadFile = selectedFile; if (progressBar != null && progressBar.isShowing()) { progressBar.dismiss(); } // prepare for a progress bar dialog progressBar = new ProgressDialog(mContext); progressBar.setCancelable(true); progressBar.setMessage("Uploading File"); progressBar.setProgressStyle(ProgressDialog.STYLE_SPINNER); progressBar.show(); new Thread() { public void run() { int serverResponseCode; Ssortingng serverResponseMessage; HttpURLConnection connection = null; DataOutputStream outputStream = null; DataInputStream inputStream = null; Ssortingng pathToOurFile = uploadFile.getAbsolutePath(); Ssortingng urlServer = "http://serveraddress/Scripts/UploadHandler.php?name" + UploadedFileName; Ssortingng lineEnd = "\r\n"; Ssortingng twoHyphens = "--"; Ssortingng boundary = "*****"; int bytesRead, bytesAvailable, bufferSize; byte[] buffer; int maxBufferSize = 1*1024*1024; try { FileInputStream fileInputStream = new FileInputStream(uploadFile); URL url = new URL(urlServer); connection = (HttpURLConnection) url.openConnection(); Log.i("File", urlServer); // Allow Inputs & Outputs. connection.setDoInput(true); connection.setDoOutput(true); connection.setUseCaches(false); // Set HTTP method to POST. connection.setRequestMethod("POST"); connection.setRequestProperty("Connection", "Keep-Alive"); connection.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary); Log.i("File", "Open conn"); outputStream = new DataOutputStream( connection.getOutputStream() ); outputStream.writeBytes(twoHyphens + boundary + lineEnd); outputStream.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\";filename=\"" + pathToOurFile +"\"" + lineEnd); outputStream.writeBytes(lineEnd); Log.i("File", "write bytes"); bytesAvailable = fileInputStream.available(); bufferSize = Math.min(bytesAvailable, maxBufferSize); buffer = new byte[bufferSize]; Log.i("File", "available: " + fileInputStream.available()); // Read file bytesRead = fileInputStream.read(buffer, 0, bufferSize); Log.i("file", "Bytes Read: " + bytesRead); while (bytesRead > 0) { outputStream.write(buffer, 0, bufferSize); bytesAvailable = fileInputStream.available(); bufferSize = Math.min(bytesAvailable, maxBufferSize); bytesRead = fileInputStream.read(buffer, 0, bufferSize); } outputStream.writeBytes(lineEnd); outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd); // Responses from the server (code and message) serverResponseCode = connection.getResponseCode(); serverResponseMessage = connection.getResponseMessage(); Log.i("file repsonse", serverResponseMessage); //once the file is uploaded call a javascript function to verify the user wants to save the image progressBar.dismiss(); runOnUiThread(new Runnable() { @Override public void run() { Log.i("start", "File name: " + UploadedFileName); WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.loadUrl("javascript:CheckImage('" + UploadedFileName + "')"); } }); fileInputStream.close(); outputStream.flush(); outputStream.close(); } catch (Exception ex) { Log.i("exception", "Error: " + ex.toSsortingng()); } } }.start(); 

}

Lastly, some more code to get the actual file path, code found on SO, ive added post url in comments as well so the author gets credits for his work.

 /** * Get a file path from a Uri. This will get the the path for Storage Access * Framework Documents, as well as the _data field for the MediaStore and * other file-based ContentProviders. * * @param context The context. * @param uri The Uri to query. * @author paulburke * @source https://stackoverflow.com/a/20559175 */ @TargetApi(Build.VERSION_CODES.KITKAT) public static Ssortingng getPath(final Context context, final Uri uri) { final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; // DocumentProvider if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) { // ExternalStorageProvider if (isExternalStorageDocument(uri)) { final Ssortingng docId = DocumentsContract.getDocumentId(uri); final Ssortingng[] split = docId.split(":"); final Ssortingng type = split[0]; if ("primary".equalsIgnoreCase(type)) { return Environment.getExternalStorageDirectory() + "/" + split[1]; } // TODO handle non-primary volumes } // DownloadsProvider else if (isDownloadsDocument(uri)) { final Ssortingng id = DocumentsContract.getDocumentId(uri); final Uri contentUri = ContentUris.withAppendedId( Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); return getDataColumn(context, contentUri, null, null); } // MediaProvider else if (isMediaDocument(uri)) { final Ssortingng docId = DocumentsContract.getDocumentId(uri); final Ssortingng[] split = docId.split(":"); final Ssortingng type = split[0]; Uri contentUri = null; if ("image".equals(type)) { contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; } else if ("video".equals(type)) { contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; } else if ("audio".equals(type)) { contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; } final Ssortingng selection = "_id=?"; final Ssortingng[] selectionArgs = new Ssortingng[] { split[1] }; return getDataColumn(context, contentUri, selection, selectionArgs); } } // MediaStore (and general) else if ("content".equalsIgnoreCase(uri.getScheme())) { return getDataColumn(context, uri, null, null); } // File else if ("file".equalsIgnoreCase(uri.getScheme())) { return uri.getPath(); } return null; } /** * Get the value of the data column for this Uri. This is useful for * MediaStore Uris, and other file-based ContentProviders. * * @param context The context. * @param uri The Uri to query. * @param selection (Optional) Filter used in the query. * @param selectionArgs (Optional) Selection arguments used in the query. * @return The value of the _data column, which is typically a file path. * @source https://stackoverflow.com/a/20559175 */ public static Ssortingng getDataColumn(Context context, Uri uri, Ssortingng selection, Ssortingng[] selectionArgs) { Cursor cursor = null; final Ssortingng column = "_data"; final Ssortingng[] projection = { column }; try { cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); if (cursor != null && cursor.moveToFirst()) { final int column_index = cursor.getColumnIndexOrThrow(column); return cursor.getSsortingng(column_index); } } finally { if (cursor != null) cursor.close(); } return null; } /** * @param uri The Uri to check. * @return Whether the Uri authority is ExternalStorageProvider. * @source https://stackoverflow.com/a/20559175 */ public static boolean isExternalStorageDocument(Uri uri) { return "com.android.externalstorage.documents".equals(uri.getAuthority()); } /** * @param uri The Uri to check. * @return Whether the Uri authority is DownloadsProvider. * @source https://stackoverflow.com/a/20559175 */ public static boolean isDownloadsDocument(Uri uri) { return "com.android.providers.downloads.documents".equals(uri.getAuthority()); } /** * @param uri The Uri to check. * @return Whether the Uri authority is MediaProvider. * @source https://stackoverflow.com/a/20559175 */ public static boolean isMediaDocument(Uri uri) { return "com.android.providers.media.documents".equals(uri.getAuthority()); } 

Lastly, the HTML page needs to sortinggger that new method of showPicker (specificaly when on A4.4)

 

Google’s own browser offers such a comprehensive solution to this problem that it warrants it’s own class:

openFileChooser implementation in Android 4.0.4

UploadHandler class in Android 4.0.4

Found a SOLUTION which works for me! Add one more rule in the file proguard-android.txt :

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

C’est du travail pour moi. Also work for Nougat and Marshmallow [ 2] [ 3]

 import android.Manifest; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.support.annotation.NonNull; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.webkit.ValueCallback; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.Toast; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; public class MainActivity extends AppCompatActivity { private static final Ssortingng TAG = MainActivity.class.getSimpleName(); private final static int FCR = 1; WebView webView; private Ssortingng mCM; private ValueCallback mUM; private ValueCallback mUMA; @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { super.onActivityResult(requestCode, resultCode, intent); if (Build.VERSION.SDK_INT >= 21) { Uri[] results = null; //Check if response is positive if (resultCode == Activity.RESULT_OK) { if (requestCode == FCR) { if (null == mUMA) { return; } if (intent == null) { //Capture Photo if no image available if (mCM != null) { results = new Uri[]{Uri.parse(mCM)}; } } else { Ssortingng dataSsortingng = intent.getDataSsortingng(); if (dataSsortingng != null) { results = new Uri[]{Uri.parse(dataSsortingng)}; } } } } mUMA.onReceiveValue(results); mUMA = null; } else { if (requestCode == FCR) { if (null == mUM) return; Uri result = intent == null || resultCode != RESULT_OK ? null : intent.getData(); mUM.onReceiveValue(result); mUM = null; } } } @SuppressLint({"SetJavaScriptEnabled", "WrongViewCast"}) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (Build.VERSION.SDK_INT >= 23 && (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)) { ActivityCompat.requestPermissions(MainActivity.this, new Ssortingng[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA}, 1); } webView = (WebView) findViewById(R.id.ifView); assert webView != null; WebSettings webSettings = webView.getSettings(); webSettings.setJavaScriptEnabled(true); webSettings.setAllowFileAccess(true); if (Build.VERSION.SDK_INT >= 21) { webSettings.setMixedContentMode(0); webView.setLayerType(View.LAYER_TYPE_HARDWARE, null); } else if (Build.VERSION.SDK_INT >= 19) { webView.setLayerType(View.LAYER_TYPE_HARDWARE, null); } else if (Build.VERSION.SDK_INT < 19) { webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); } webView.setWebViewClient(new Callback()); webView.loadUrl("https://infeeds.com/"); webView.setWebChromeClient(new WebChromeClient() { //For Android 3.0+ public void openFileChooser(ValueCallback uploadMsg) { mUM = uploadMsg; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("*/*"); MainActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), FCR); } // For Android 3.0+, above method not supported in some android 3+ versions, in such case we use this public void openFileChooser(ValueCallback uploadMsg, Ssortingng acceptType) { mUM = uploadMsg; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("*/*"); MainActivity.this.startActivityForResult( Intent.createChooser(i, "File Browser"), FCR); } //For Android 4.1+ public void openFileChooser(ValueCallback uploadMsg, Ssortingng acceptType, Ssortingng capture) { mUM = uploadMsg; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("*/*"); MainActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), MainActivity.FCR); } //For Android 5.0+ public boolean onShowFileChooser( WebView webView, ValueCallback filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) { if (mUMA != null) { mUMA.onReceiveValue(null); } mUMA = filePathCallback; Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (takePictureIntent.resolveActivity(MainActivity.this.getPackageManager()) != null) { File photoFile = null; try { photoFile = createImageFile(); takePictureIntent.putExtra("PhotoPath", mCM); } catch (IOException ex) { Log.e(TAG, "Image file creation failed", ex); } if (photoFile != null) { mCM = "file:" + photoFile.getAbsolutePath(); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile)); } else { takePictureIntent = null; } } Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT); contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE); contentSelectionIntent.setType("*/*"); Intent[] intentArray; if (takePictureIntent != null) { intentArray = new Intent[]{takePictureIntent}; } else { intentArray = new Intent[0]; } Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER); chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent); chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser"); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray); startActivityForResult(chooserIntent, FCR); return true; } }); } // Create an image file private File createImageFile() throws IOException { @SuppressLint("SimpleDateFormat") Ssortingng timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); Ssortingng imageFileName = "img_" + timeStamp + "_"; File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); return File.createTempFile(imageFileName, ".jpg", storageDir); } @Override public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN) { switch (keyCode) { case KeyEvent.KEYCODE_BACK: if (webView.canGoBack()) { webView.goBack(); } else { finish(); } return true; } } return super.onKeyDown(keyCode, event); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); } public class Callback extends WebViewClient { public void onReceivedError(WebView view, int errorCode, Ssortingng description, Ssortingng failingUrl) { Toast.makeText(getApplicationContext(), "Failed loading app!", Toast.LENGTH_SHORT).show(); } } } 

Kotlin solution for Android 8:

 private var mUploadMessage: ValueCallback? = null private var uploadMessage: ValueCallback>? = null 

Constants:

 const val FILECHOOSER_RESULTCODE = 1 const val REQUEST_SELECT_FILE = 100 

WebView setup:

 webView.webChromeClient = object : WebChromeClient() { override fun onPermissionRequest(request: PermissionRequest?) { Log.d("MainActivity", "onPermissionRequest") requestPermission(request) } // For Android 3.0+ fun openFileChooser(uploadMsg: ValueCallback< *>, acceptType: Ssortingng) { mUploadMessage = uploadMsg as ValueCallback val i = Intent(Intent.ACTION_GET_CONTENT) i.addCategory(Intent.CATEGORY_OPENABLE) i.type = "*/*" this@MainActivity.startActivityForResult( Intent.createChooser(i, "File Browser"), FILECHOOSER_RESULTCODE) } //For Android 4.1 fun openFileChooser(uploadMsg: ValueCallback, acceptType: Ssortingng, capture: Ssortingng) { mUploadMessage = uploadMsg val i = Intent(Intent.ACTION_GET_CONTENT) i.addCategory(Intent.CATEGORY_OPENABLE) i.type = "image/*" this@MainActivity.startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE) } protected fun openFileChooser(uploadMsg: ValueCallback) { mUploadMessage = uploadMsg val intent = Intent(Intent.ACTION_GET_CONTENT) intent.addCategory(Intent.CATEGORY_OPENABLE) intent.type = "*/*" startActivityForResult(Intent.createChooser(intent, "File Chooser"), FILECHOOSER_RESULTCODE) } override fun onShowFileChooser(webView: WebView?, filePathCallback: ValueCallback>?, fileChooserParams: FileChooserParams?): Boolean { uploadMessage?.onReceiveValue(null) uploadMessage = null uploadMessage = filePathCallback val intent = fileChooserParams!!.createIntent() try { startActivityForResult(intent, REQUEST_SELECT_FILE) } catch (e: ActivityNotFoundException) { uploadMessage = null Toast.makeText(applicationContext, "Cannot Open File Chooser", Toast.LENGTH_LONG).show() return false } return true } } 

And the onAcrtivityResult part:

 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (requestCode === REQUEST_SELECT_FILE) { if (uploadMessage == null) return print("result code = " + resultCode) var results: Array? = WebChromeClient.FileChooserParams.parseResult(resultCode, data) uploadMessage?.onReceiveValue(results) uploadMessage = null } } else if (requestCode === FILECHOOSER_RESULTCODE) { if (null == mUploadMessage) return // Use MainActivity.RESULT_OK if you're implementing WebView inside Fragment // Use RESULT_OK only if you're implementing WebView inside an Activity val result = if (intent == null || resultCode !== RESULT_OK) null else intent.data mUploadMessage?.onReceiveValue(result) mUploadMessage = null } else Toast.makeText(applicationContext, "Failed to Upload Image", Toast.LENGTH_LONG).show() } 

Please, pay attention that our intent variable called “data”.

In KitKat you can use the Storage Access Framework.

Storage Access Framework / Writing a Client App

Webview – Single & Multiple files choose

you needs two minutes to implement this code:

build.gradle

 implementation 'com.github.angads25:filepicker:1.1.1' 

java code:

 import android.annotation.SuppressLint; import android.app.Activity; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.webkit.ValueCallback; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.ProgressBar; import android.widget.Toast; import com.bivoiclient.utils.Constants; import com.github.angads25.filepicker.controller.DialogSelectionListener; import com.github.angads25.filepicker.model.DialogConfigs; import com.github.angads25.filepicker.model.DialogProperties; import com.github.angads25.filepicker.view.FilePickerDialog; import java.io.File; public class WebBrowserScreen extends Activity { private WebView webView; private ValueCallback mUploadMessage; private FilePickerDialog dialog; private Ssortingng LOG_TAG = "DREG"; private Uri[] results; @SuppressLint("SetJavaScriptEnabled") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_complain); webView = findViewById(R.id.webview); WebSettings webSettings = webView.getSettings(); webSettings.setAppCacheEnabled(true); webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); webSettings.setJavaScriptEnabled(true); webSettings.setLoadWithOverviewMode(true); webSettings.setAllowFileAccess(true); webView.setWebViewClient(new PQClient()); webView.setWebChromeClient(new PQChromeClient()); if (Build.VERSION.SDK_INT >= 19) { webView.setLayerType(View.LAYER_TYPE_HARDWARE, null); } else { webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); } webView.loadUrl(Constants.COMPLAIN_URL); } private void openFileSelectionDialog() { if (null != dialog && dialog.isShowing()) { dialog.dismiss(); } //Create a DialogProperties object. final DialogProperties properties = new DialogProperties(); //Instantiate FilePickerDialog with Context and DialogProperties. dialog = new FilePickerDialog(WebBrowserScreen.this, properties); dialog.setTitle("Select a File"); dialog.setPositiveBtnName("Select"); dialog.setNegativeBtnName("Cancel"); properties.selection_mode = DialogConfigs.MULTI_MODE; // for multiple files // properties.selection_mode = DialogConfigs.SINGLE_MODE; // for single file properties.selection_type = DialogConfigs.FILE_SELECT; //Method handle selected files. dialog.setDialogSelectionListener(new DialogSelectionListener() { @Override public void onSelectedFilePaths(Ssortingng[] files) { results = new Uri[files.length]; for (int i = 0; i < files.length; i++) { String filePath = new File(files[i]).getAbsolutePath(); if (!filePath.startsWith("file://")) { filePath = "file://" + filePath; } results[i] = Uri.parse(filePath); Log.d(LOG_TAG, "file path: " + filePath); Log.d(LOG_TAG, "file uri: " + String.valueOf(results[i])); } mUploadMessage.onReceiveValue(results); mUploadMessage = null; } }); dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialogInterface) { if (null != mUploadMessage) { if (null != results && results.length >= 1) { mUploadMessage.onReceiveValue(results); } else { mUploadMessage.onReceiveValue(null); } } mUploadMessage = null; } }); dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialogInterface) { if (null != mUploadMessage) { if (null != results && results.length >= 1) { mUploadMessage.onReceiveValue(results); } else { mUploadMessage.onReceiveValue(null); } } mUploadMessage = null; } }); dialog.show(); } public class PQChromeClient extends WebChromeClient { @Override public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, FileChooserParams fileChooserParams) { // Double check that we don't have any existing callbacks if (mUploadMessage != null) { mUploadMessage.onReceiveValue(null); } mUploadMessage = filePathCallback; openFileSelectionDialog(); return true; } } //Add this method to show Dialog when the required permission has been granted to the app. @Override public void onRequestPermissionsResult(int requestCode, @NonNull Ssortingng permissions[], @NonNull int[] grantResults) { switch (requestCode) { case FilePickerDialog.EXTERNAL_READ_PERMISSION_GRANT: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (dialog != null) { openFileSelectionDialog(); } } else { //Permission has not been granted. Notify the user. Toast.makeText(WebBrowserScreen.this, "Permission is Required for getting list of files", Toast.LENGTH_SHORT).show(); } } } } public boolean onKeyDown(int keyCode, KeyEvent event) { // Check if the key event was the Back button and if there's history if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) { webView.goBack(); return true; } // If it wasn't the Back key or there's no web page history, bubble up to the default // system behavior (probably exit the activity) return super.onKeyDown(keyCode, event); } public class PQClient extends WebViewClient { ProgressBar progressDialog; public boolean shouldOverrideUrlLoading(WebView view, Ssortingng url) { // If url contains mailto link then open Mail Intent if (url.contains("mailto:")) { // Could be cleverer and use a regex //Open links in new browser view.getContext().startActivity( new Intent(Intent.ACTION_VIEW, Uri.parse(url))); // Here we can open new activity return true; } else { // Stay within this webview and load url view.loadUrl(url); return true; } } // Show loader on url load public void onPageStarted(WebView view, Ssortingng url, Bitmap favicon) { // Then show progress Dialog // in standard case YourActivity.this if (progressDialog == null) { progressDialog = findViewById(R.id.progressBar); progressDialog.setVisibility(View.VISIBLE); } } // Called when all page resources loaded public void onPageFinished(WebView view, Ssortingng url) { webView.loadUrl("javascript:(function(){ " + "document.getElementById('android-app').style.display='none';})()"); try { // Close progressDialog progressDialog.setVisibility(View.GONE); } catch (Exception exception) { exception.printStackTrace(); } } } } 

I’m new to Andriod and struggled with this also. According to Google Reference Guide WebView.

By default, a WebView provides no browser-like widgets, does not enable JavaScript and web page errors are ignored. If your goal is only to display some HTML as a part of your UI, this is probably fine; the user won’t need to interact with the web page beyond reading it, and the web page won’t need to interact with the user. If you actually want a full-blown web browser, then you probably want to invoke the Browser application with a URL Intent rather than show it with a WebView.

Example code I executed in MainActvity.java.

  Uri uri = Uri.parse("https://www.example.com"); Intent intent = new Intent(Intent.ACTION_VIEW, uri); startActivity(intent); 

Excuted

 package example.com.myapp; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.webkit.WebView; import android.webkit.WebViewClient; import android.content.Intent; import android.net.Uri; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Uri uri = Uri.parse("http://www.example.com/"); Intent intent = new Intent(Intent.ACTION_VIEW, uri); startActivity(intent); getSupportActionBar().hide(); }}