Загрузка файлов в WebView

Вопрос: Я изо всех сил пытался загрузить файлы из WebView с последних нескольких дней, и нет никакого прогресса. Я погуглил и реализовал все предложенные решения, но ни одно из них не работает, например: предлагаемые здесь решения и так далее. Проблема: у меня есть HTML-страница со следующим кодом для загрузки файла. Он отлично работает в настольном

Вопрос:

Я изо всех сил пытался загрузить файлы из WebView с последних нескольких дней, и нет никакого прогресса. Я погуглил и реализовал все предложенные решения, но ни одно из них не работает, например: предлагаемые здесь решения и так далее.

Проблема: у меня есть HTML-страница со следующим кодом для загрузки файла. Он отлично работает в настольном браузере, таком как Firefox и во встроенном браузере эмулятора /AVD, т.е. когда я нажимаю кнопку “Обзор…”, отображаемую элементом, браузер открывает диалоговое окно, в котором я могу выбрать файл для загрузки.

Однако в эмуляторе android 3.0/AVD, когда я нажимаю “Выбрать файл”, ничего не происходит, ни один файл не открывается !!!

<form method=»POST» enctype=»multipart/form-data»> File to upload: <input type=»file» name=»uploadfile»>&nbsp;&nbsp; <input type=»submit» value=»Press to Upload…»> to upload the file! </form>

Может ли кто-нибудь, пожалуйста, предложить возможное решение в ближайшее время.

Ответ №1

Это полное решение для всех версий Android, мне тоже было трудно с этим.

public class MyWb extends Activity { /** Called when the activity is first created. */ WebView web; ProgressBar progressBar; private ValueCallback<Uri> 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<Uri> 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, String 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<Uri> uploadMsg, String acceptType, String 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, String url, Bitmap favicon) { // TODO Auto-generated method stub super.onPageStarted(view, url, favicon); } @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { // TODO Auto-generated method stub view.loadUrl(url); return true; } @Override public void onPageFinished(WebView view, String 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); }*/ }

Также я хочу добавить, что “страница загрузки”, подобная той, что в этом примере, не будет работать в <4 версиях, так как она имеет функцию предварительного просмотра изображения, если вы хотите, чтобы она работала, используйте простую загрузку php без предварительного просмотра.

Обновление:

Пожалуйста, найдите решение для устройств леденец здесь и спасибо за изможденное лицо

Обновление 2:

Полное решение для всех устройств Android до Oreo здесь, и это более продвинутая версия, вы должны изучить его, может быть, это может помочь.

Ответ №2

Рабочий метод от HONEYCOMB (API 11) до Oreo (API 27)
[Не проверено на пироге 9.0]

static WebView mWebView; private ValueCallback<Uri> mUploadMessage; public ValueCallback<Uri[]> uploadMessage; public static final int REQUEST_SELECT_FILE = 100; private final static int FILECHOOSER_RESULTCODE = 1;

Изменено 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(); }

Теперь в onCreate() или onCreateView() вставьте следующий код

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, String 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<Uri[]> 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<Uri> uploadMsg, String acceptType, String 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<Uri> 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); } }); Ответ №3

Это единственное решение, которое я нашел, что работает!

WebView webview; private ValueCallback<Uri> 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<Uri> 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); } } Ответ №4

В 5.0 Lollipop Google добавил официальный метод WebChromeClient.onShowFileChooser. Они даже предоставляют способ автоматически генерировать намерение выбора файла, так что он использует типы ввода accept mime.

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<Uri[]> 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<Uri[]> 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; } } } }

В версиях Android до KitKat работают частные методы, упомянутые в других ответах. Я не нашел хорошего обходного пути для KitKat (4.4).

Ответ №5

Я обнаружил, что мне нужны 3 определения интерфейса для обработки различных версий 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, String acceptType) { openFileChooser(uploadMsg); } public void openFileChooser(ValueCallback < Uri > uploadMsg, String acceptType, String capture) { openFileChooser(uploadMsg); } Ответ №6

Это решение также работает для сотового и мороженого сэндвич. Похоже, что Google представил новую новую функцию (признавать атрибут) и забыл реализовать перегрузку для обратной совместимости.

protected class CustomWebChromeClient extends WebChromeClient { // For Android 3.0+ public void openFileChooser( ValueCallback<Uri> uploadMsg, String 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<Uri> uploadMsg ) { openFileChooser( uploadMsg, «» ); } } Ответ №7

hifarrer полное решение очень полезно для меня.

но я столкнулся со многими другими проблемами, поддерживая другой тип mime, перечисляя устройства захвата (камеру, видео, аудио-рекодер), сразу открывая устройство захвата (например: < input accept = “image/*; capture” > );…

Итак, я сделал решение, которое работает точно так же, как и приложение для веб-браузера по умолчанию.

Я использовал android-4.4.3_r1/src/com/android/browser/UploadHandler.java. (благодаря Руперту Раунсли)

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, String 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 String getTitleFromUrl(String url) { String title = url; try { URL urlObj = new URL(url); String host = urlObj.getHost(); if (host != null && !host.isEmpty()) { return urlObj.getProtocol() + «://» + host; } if (url.startsWith(«file:»)) { String fileName = urlObj.getFile(); if (fileName != null && !fileName.isEmpty()) { return fileName; } } } catch (Exception e) { // ignore } return title; } @Override public boolean onJsAlert(WebView view, String url, String message, final JsResult result) { String newTitle = getTitleFromUrl(url); new AlertDialog.Builder(MainActivity.this).setTitle(newTitle).setMessage(message).setPositiveButton(android.R.string.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, String url, String message, final JsResult result) { String newTitle = getTitleFromUrl(url); new AlertDialog.Builder(MainActivity.this).setTitle(newTitle).setMessage(message).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { result.confirm(); } }).setNegativeButton(android.R.string.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<Uri> uploadMsg) { openFileChooser(uploadMsg, «»); } // Android 3.0 public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) { openFileChooser(uploadMsg, «», «filesystem»); } // Android 4.1 public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String 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<Uri[]> filePathCallback, FileChooserParams fileChooserParams) { String acceptTypes[] = fileChooserParams.getAcceptTypes(); String 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<Uri[]> finalFilePathCallback = filePathCallback; ValueCallback<Uri> vc = new ValueCallback<Uri>() { @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 * distributed under the License is distributed 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<Uri> mUploadMessage; private String mCameraFilePath; private boolean mHandled; private boolean mCaughtActivityNotFoundException; private Controller mController; public UploadHandler(Controller controller) { mController = controller; } String 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<Uri> uploadMsg, String acceptType, String capture) { final String imageMimeType = «image/*»; final String videoMimeType = «video/*»; final String audioMimeType = «audio/*»; final String mediaSourceKey = «capture»; final String mediaSourceValueCamera = «camera»; final String mediaSourceValueFileSystem = «filesystem»; final String mediaSourceValueCamcorder = «camcorder»; final String mediaSourceValueMicrophone = «microphone»; // According to the spec, media source can be ‘filesystem’ or ‘camera’ or ‘camcorder’ // or ‘microphone’ and the default value should be ‘filesystem’. String mediaSource = mediaSourceValueFileSystem; if (mUploadMessage != null) { // Already a file picker operation in progress. return; } mUploadMessage = uploadMsg; // Parse the accept type. String params[] = acceptType.split(«;»); String 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’ attribute is // «filesystem», we should examine the accept-type for a MIME type that // may specify a different capture value. for (String p : params) { String[] 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 trigger 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.string.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() .getString(R.string.choose_upload)); return chooser; } private Intent createOpenableIntent(String 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 res/values ​​/string.xml:

<string name=»uploads_disabled»>File uploads are disabled.</string> <string name=»choose_upload»>Choose file for upload</string>

Если вы используете proguard, вам может понадобиться параметр ниже в proguard-project.txt:

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

ОБНОВЛЕНИЕ # 1 (2015.09.09)

добавляет код для совместимости с Android 5.0.1.

Ответ №8

Мне было необходимо определить public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture), в Android 4.1. Затем я последовал за решением Мишеля Оливье.

Ответ №9

Мне действительно удалось заставить сборщик файлов появиться в Kitkat, выбрать изображение и получить путь к файлу в результате действия, но единственное, что им не удалось “исправить” (из-за этого обходного пути), – это сделать ввод для заполнения файлами данных.

Кто-нибудь знает, как получить доступ к поля ввода из активности? Я использую этот пример комментарий. Это только последний кусок, последний кирпич в стене, который мне просто нужно положить в нужное место (я могу вызвать загрузку файла изображения непосредственно из кода.

ОБНОВЛЕНИЕ # 1

Мне не нужен хардкор для Android, поэтому я покажу код на уровне новичка. Im создает новую активность в уже существующей деятельности.

Часть манифеста

<uses-permission android:name=»android.permission.INTERNET»/> <uses-permission android:name=»android.permission.READ_EXTERNAL_STORAGE»/> <application android:label=»TestApp»> <activity android:name=».BrowseActivity»></activity> </application>

Создаем класс BrowseActivity из этого примера answer. Экземпляр WebChromeClient() в основном выглядит одинаково, кроме последней части, запускающей часть пользовательского интерфейса…

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<Uri> uploadMsg) { /* Default code */ } // For Android 3.0+ public void openFileChooser( ValueCallback uploadMsg, String acceptType ) { /* Default code */ } //For Android 4.1, also default but it’ll be as example public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String 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<Uri> uploadMsg ){ // Here is part of the issue, the uploadMsg is null since it is not triggered 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); }}

И еще несколько вещей

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); String 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.toString()) ); // Now we have the file but since mUploadMessage was null, it gets errors } } public void UploadFile(File selectedFile) { Random rnd = new Random(); String sName = «File» + rnd.nextInt(999999) + selectedFile.getAbsolutePath().substring(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; String serverResponseMessage; HttpURLConnection connection = null; DataOutputStream outputStream = null; DataInputStream inputStream = null; String pathToOurFile = uploadFile.getAbsolutePath(); String urlServer = «http://serveraddress/Scripts/UploadHandler.php?name» + UploadedFileName; String lineEnd = «rn»; String twoHyphens = «—«; String 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 &amp; 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.toString()); } } }.start();

}

Наконец, еще один код, чтобы получить фактический путь к файлу, код, найденный на SO, и добавил добавленный URL-адрес в комментариях, так что автор получает кредиты за свою работу.

/** * 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 String 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 String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(«:»); final String type = split[0]; if («primary».equalsIgnoreCase(type)) { return Environment.getExternalStorageDirectory() + «/» + split[1]; } // TODO handle non-primary volumes } // DownloadsProvider else if (isDownloadsDocument(uri)) { final String 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 String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(«:»); final String 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 String selection = «_id=?»; final String[] selectionArgs = new String[] { 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 String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) { Cursor cursor = null; final String column = «_data»; final String[] 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.getString(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()); }

Наконец, HTML-страница должна вызвать этот новый метод showPicker (особенно, когда на A4.4)

<form id=»form-upload» method=»post» enctype=»multipart/form-data»> <input id=»fileupload» name=»fileupload» type=»file» onclick=»javascript:prepareForPicker();»/> </form> <script type=»text/javascript»> function getAndroidVersion() { var ua = navigator.userAgent; var match = ua.match(/Androids([0-9.]*)/); return match ? match[1] : false; }; function prepareForPicker(){ if(getAndroidVersion().indexOf(«4.4») != -1){ window.jsi.showPicker(); return false; } } function CheckImage(name) { //Check to see if user wants to save I used some ajax to save the file if necesarry } </script> Ответ №10

Это работа для меня. Также работайте на нугу и зефир [ [

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 String TAG = MainActivity.class.getSimpleName(); private final static int FCR = 1; WebView webView; private String mCM; private ValueCallback<Uri> mUM; private ValueCallback<Uri[]> 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 { String dataString = intent.getDataString(); if (dataString != null) { results = new Uri[]{Uri.parse(dataString)}; } } } } 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 String[]{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<Uri> 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, String 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<Uri> uploadMsg, String acceptType, String 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<Uri[]> 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») String timeStamp = new SimpleDateFormat(«yyyyMMdd_HHmmss»).format(new Date()); String 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, String description, String failingUrl) { Toast.makeText(getApplicationContext(), «Failed loading app!», Toast.LENGTH_SHORT).show(); } } } Ответ №11

Собственный браузер Google предлагает такое комплексное решение этой проблемы, что он гарантирует его собственный класс:

реализация openFileChooser в Android 4.0.4

класс UploadHandler в Android 4.0.4

Ответ №12

Нашел РЕШЕНИЕ, которая работает для меня! Добавьте еще одно правило в файл proguard-android.txt:

-keepclassmembers class * extends android.webkit.WebChromeClient { public void openFileChooser(…); } Ответ №13

Решение Kotlin для Android 8:

private var mUploadMessage: ValueCallback<Uri>? = null private var uploadMessage: ValueCallback<Array<Uri>>? = null

Константы:

const val FILECHOOSER_RESULTCODE = 1 const val REQUEST_SELECT_FILE = 100

Настройка WebView:

webView.webChromeClient = object : WebChromeClient() { override fun onPermissionRequest(request: PermissionRequest?) { Log.d(«MainActivity», «onPermissionRequest») requestPermission(request) } // For Android 3.0+ fun openFileChooser(uploadMsg: ValueCallback<*>, acceptType: String) { mUploadMessage = uploadMsg as ValueCallback<Uri> 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<Uri>, acceptType: String, capture: String) { 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<Uri>) { 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<Array<Uri>>?, 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 } }

И часть onAcrtivityResult:

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<Uri>? = 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() }

Пожалуйста, обратите внимание, что наша переменная намерения называется “data”.

Ответ №14

Вы посетили эти ссылки?
http://groups.google.com/group/android-developers/browse_thread/thread/dcaf8b2fdd8a90c4/62d5e2ffef31ebdb

http://moazzam-khan.com/blog/?tag=android-upload-file

http://evgenyg.wordpress.com/2010/05/01/uploading-files-multipart-post-apache/

Краткий пример загрузки файла через Java lib Apache Commons

Я думаю, вы получите помощь от этого

Ответ №15

В KitKat вы можете использовать Рамку доступа к хранилищу.

База доступа к хранилищу/Запись клиентского приложения

Ответ №16

Веб-просмотр. Один и несколько файлов выбирают

вам нужно две минуты для реализации этого кода:

build.gradle

implementation ‘com.github.angads25:filepicker:1.1.1’

код java:

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<Uri[]> mUploadMessage; private FilePickerDialog dialog; private String 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(String[] 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<Uri[]> 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 String 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 history if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) { webView.goBack(); return true; } // If it wasn’t the Back key or there 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, String 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, String 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, String url) { webView.loadUrl(«javascript:(function(){ » + «document.getElementById(‘android-app’).style.display=’none’;})()»); try { // Close progressDialog progressDialog.setVisibility(View.GONE); } catch (Exception exception) { exception.printStackTrace(); } } } } Ответ №17

Я новичок в Andriod и боролся с этим также. Согласно справочному руководству Google WebView.

По умолчанию WebView не предоставляет виджеты, подобные браузеру, не включает JavaScript и ошибки веб-страниц игнорируются. Если ваша цель – отображать только HTML как часть вашего пользовательского интерфейса, это, вероятно, хорошо; пользователю не нужно взаимодействовать с веб-страницей после ее чтения, а веб-странице не нужно взаимодействовать с пользователем. Если вам действительно нужен полноценный веб-браузер, то вы, вероятно, захотите вызвать приложение браузера с намерением URL, а не показывать его с помощью WebView.

Пример кода, который я выполнил в 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(); }} Ответ №18

Если вышеупомянутые решения почему-то не работают (я попробовал почти все из них), то вы используете код, предоставленный Гази Ханом на github. Хорошо, что это не библиотека, и она работает как с камерой, так и с уже сохраненными файлами. Я проверил в 5.x и 7.x:

код Гази Хана и Альфредо

Ответ №19

Я занимался этим вопросом почти месяц. Все не удалось. Все коды на нескольких сайтах не работают хорошо. Но здесь существует лучшее решение

https://github.com/chiclaim/android-webview-upload-file

шаги

1) Нажмите на клон или загрузите

2) Получить почтовый файл в вашем местном каталоге

3) разархивировать почтовый файл

4) Откройте Android-студию

5) Перейти к файлу → Открыть —> Перейдите в каталог, в который вы распаковали содержимое.

6) Измените необходимый веб-URL в webView.loadUrl(“ваш URL-адрес”); в MainActivity.java

7) Хорошо работает с версией Android studio 3.4.2

Оцените статью
Добавить комментарий