Загрузите изображение с камеры или галереи в WebView

WebView в этом приложении открывает страницу с кнопкой загрузки.

Страница в веб-браузере с кнопкой загрузки

Ниже приведен код, который позволяет открыть диалоговое окно для загрузки изображения из галереи или камеры.

В рамках моей деятельности у меня есть:

private WebView wv; //make HTML upload button work in 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; } } 

Внутри onCreate у меня есть следующее:

  wv.setWebChromeClient(new WebChromeClient() { private Uri imageUri; public void openFileChooser(ValueCallback uploadMsg, String acceptType ) { File imageStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyApp"); // Create the storage directory if it does not exist if (! imageStorageDir.exists()){ imageStorageDir.mkdirs(); } File file = new File(imageStorageDir + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg"); imageUri = Uri.fromFile(file); final List cameraIntents = new ArrayList(); final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); final PackageManager packageManager = getPackageManager(); final List listCam = packageManager.queryIntentActivities(captureIntent, 0); for(ResolveInfo res : listCam) { final String packageName = res.activityInfo.packageName; final Intent i = new Intent(captureIntent); i.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name)); i.setPackage(packageName); i.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); cameraIntents.add(i); } mUploadMessage = uploadMsg; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("image/*"); Intent chooserIntent = Intent.createChooser(i,"Image Chooser"); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[]{})); MainActivity.this.startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE); } 

Я могу увидеть вариант для камеры, галереи изображений и проводника файлов при нажатии кнопки «Загрузить». Вариант загрузки камеры, галереи и файла

Файл-проводник и Галерея работают должным образом. Проблема в том, что, когда я делаю снимок с помощью камеры, он не загружается в опцию «выбрать файл», которая показывает статус «Нет выбранного файла».

НА ВЫБОР КАМЕРЫ:

камера

ПО ПРИНИМАНИЮ СНАБЖЕНИЯ С ПОМОЩЬЮ КАМЕРЫ: появляются опции возврата и проверки.

моментальный снимок с использованием камеры

НА ВЫБОРЕ ПРОВЕРКИ:

ФАЙЛ НЕ ЗАГРУЖЕН: (В “ВЫБОР ФАЙЛА” ВАРИАНТ

введите описание изображения здесь

ЧТО ОЖИДАЕТСЯ:

изображение загружено

Я проверил, что у меня есть надлежащее разрешение на запись, и, следовательно, создается каталог с именем «MyApp», и изображение сохраняется внутри него (если оно вызывается вызовом камеры после нажатия кнопки загрузки на веб-странице).

Как запрограммировать приложение для выбора снимка, снятого с камеры (которая была сохранена в каталоге MyApp) после нажатия галочки?

    Я полагаю, что метод onActivityResult фактически вызывается, но 3-й параметр Intent intent имеет значение null. Кажется, что это ошибка телефонов Nexus.

    Но вы можете сохранить выходное изображение uri в приватную переменную и использовать его вместо намерения:

     private Uri imageUri; private void showAttachmentDialog(ValueCallback uploadMsg) { this.mUploadMessage = uploadMsg; File imageStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "TestApp"); if (!imageStorageDir.exists()) { imageStorageDir.mkdirs(); } File file = new File(imageStorageDir + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg"); this.imageUri = Uri.fromFile(file); // save to the private variable final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("image/*"); Intent chooserIntent = Intent.createChooser(i, "Image Chooser"); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Parcelable[] { captureIntent }); this.startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { if (requestCode == FILECHOOSER_RESULTCODE) { if (null == this.mUploadMessage) { return; } Uri result; if (resultCode != RESULT_OK) { result = null; } else { result = intent == null ? this.imageUri : intent.getData(); // retrieve from the private variable if the intent is null } this.mUploadMessage.onReceiveValue(result); this.mUploadMessage = null; } } 

    В этом коде я добавил переменную imageUri в действие и использовал ее в обоих методах.

    Обновление 6/18: похоже, это не работает на Samsung Galaxy S2 с Android 4.2.1. Это отлично работает на HTC One X + с 4.1.2. Будьте осторожны.


    Я столкнулся с такой же проблемой. Вот проблема и как я ее решил.

    Проблема:

    Когда вызывается openFileChooser , ValueCallback объект ValueCallback вызова ValueCallback . Это фактический обратный вызов веб-представления, когда у нас есть готовый файл. Мы сохраняем этот объект в mUploadMessage и используем mUploadMessage.onReceiveValue() в onActivityResult чтобы вернуть файл в Webview. Когда вы выбираете камеру, щелкните изображение, сохраните его и вернитесь в активность веб-просмотра, наша деятельность может быть переработана, что означает, что мы фактически теряем объект mUploadMessage вызова mUploadMessage . И, следовательно, файл не может быть передан в webview для загрузки.

    Fix:

    Исправление включает выполнение javascript, поэтому включите javascript в webview. В принципе, мы получим еще один объект обратного вызова, если мы потеряем предыдущий.

    Нам нужно создать логическое поле « mUploadFileOnLoad » и три поля.

      private int mReturnCode; private int mResultCode; private Intent mResultIntent; private boolean mUploadFileOnLoad = false; 

    Когда мы вернемся к нашей деятельности с камеры, будет вызван onActivityResult . Если активность реконструирована, mUploadMessage имеет значение NULL. Итак, мы сохраним параметры в полях и установим mUploadFileOnLoad в true и return. Другая часть очень важна.

      @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { //if the callback object has been recycled if(null==mUploadMessage) { //Save the result mReturnCode = requestCode; mResultCode = resultCode; mResultIntent = intent; //remember to invoke file upload using Javascript mUploadFileOnLoad = true; return; }else mUploadFileOnLoad = false; //rest of the code } 

    Важными частями этого решения являются WebViewClient и WebChromeClient

      new WebChromeClient() { //Other overloaded functions //See http://stackoverflow.com/a/15423907/375093 for full explanation //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) { //If we lost the callback object if(mUploadFileOnLoad) { mUploadMessage = uploadMsg; //use the saved result objects to invoke onActivityResult onActivityResult(mReturnCode, mResultCode, mResultIntent); return; } //Rest of the code.... } 

    а также

      new WebViewClient() { @Override public void onPageFinished(WebView view, String url) { if(mUploadFileOnLoad) { webview.loadUrl("javascript:document.getElementById('my_file').click()"); } } 

    В приведенном выше my_file является идентификатором элемента на веб-странице.

      

    Итак, в общем, что мы сделали – когда у нас нет объекта обратного вызова, мы сохраняем данные, полученные от другого действия, и устанавливаем mUploadFileOnLoad в true и mUploadFileOnLoad загрузки страницы. Когда страница загружается, мы используем Javascript для вызова выбора файла, чтобы мы получили объект обратного вызова. Поскольку у нас уже есть результаты, мы вызываем onActivityResult и возвращаем. onActivityResult теперь имеет обратный вызов из webview.

    После многого боя я нашел код, который работает для приема файлов с камбуза и камеры из 5.0+ устройств

      private ValueCallback mUploadMessage; private Uri mCapturedImageURI = null; private ValueCallback mFilePathCallback; private String mCameraPhotoPath; private static final int INPUT_FILE_REQUEST_CODE = 1; private static final int FILECHOOSER_RESULTCODE = 1; private File createImageFile() throws IOException { // Create an image file name String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = "JPEG_" + timeStamp + "_"; File storageDir = Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES); File imageFile = File.createTempFile( imageFileName, /* prefix */ ".jpg", /* suffix */ storageDir /* directory */ ); return imageFile; } 

    это инициализация и настройка webview

      mWebView= (WebView) findViewById(R.id.webview); mWebView.getSettings().setJavaScriptEnabled(true); mWebView.getSettings().setPluginState(WebSettings.PluginState.OFF); mWebView.getSettings().setLoadWithOverviewMode(true); mWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE); mWebView.getSettings().setUseWideViewPort(true); mWebView.getSettings().setUserAgentString("Android Mozilla/5.0 AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30"); mWebView.getSettings().setAllowFileAccess(true); mWebView.getSettings().setAllowFileAccess(true); mWebView.getSettings().setAllowContentAccess(true); mWebView.getSettings().supportZoom(); mWebView.loadUrl(Common.adPostUrl); mWebView.setWebViewClient(new WebViewClient() { public boolean shouldOverrideUrlLoading(WebView view, String url) { // do your handling codes here, which url is the requested url // probably you need to open that url rather than redirect: if ( url.contains(".pdf")){ Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.parse(url), "application/pdf"); try{ view.getContext().startActivity(intent); } catch (ActivityNotFoundException e) { //user does not have a pdf viewer installed } } else { mWebView.loadUrl(url); } return false; // then it is not handled by default action } @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { Log.e("error",description); } @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { //show progressbar here super.onPageStarted(view, url, favicon); } @Override public void onPageFinished(WebView view, String url) { //hide progressbar here } }); mWebView.setWebChromeClient(new ChromeClient()); 

    и вот мой метод ChomeClient ()

     public class ChromeClient extends WebChromeClient { // For Android 5.0 public boolean onShowFileChooser(WebView view, ValueCallback filePath, WebChromeClient.FileChooserParams fileChooserParams) { // Double check that we don't have any existing callbacks if (mFilePathCallback != null) { mFilePathCallback.onReceiveValue(null); } mFilePathCallback = filePath; Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (takePictureIntent.resolveActivity(getPackageManager()) != null) { // Create the File where the photo should go File photoFile = null; try { photoFile = createImageFile(); takePictureIntent.putExtra("PhotoPath", mCameraPhotoPath); } catch (IOException ex) { // Error occurred while creating the File Log.e(Common.TAG, "Unable to create Image File", ex); } // Continue only if the File was successfully created if (photoFile != null) { mCameraPhotoPath = "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("image/*"); 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, INPUT_FILE_REQUEST_CODE); return true; } // openFileChooser for Android 3.0+ public void openFileChooser(ValueCallback uploadMsg, String acceptType) { mUploadMessage = uploadMsg; // Create AndroidExampleFolder at sdcard // Create AndroidExampleFolder at sdcard File imageStorageDir = new File( Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES) , "AndroidExampleFolder"); if (!imageStorageDir.exists()) { // Create AndroidExampleFolder at sdcard imageStorageDir.mkdirs(); } // Create camera captured image file path and name File file = new File( imageStorageDir + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg"); mCapturedImageURI = Uri.fromFile(file); // Camera capture image intent final Intent captureIntent = new Intent( android.provider.MediaStore.ACTION_IMAGE_CAPTURE); captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, mCapturedImageURI); Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("image/*"); // Create file chooser intent Intent chooserIntent = Intent.createChooser(i, "Image Chooser"); // Set camera intent to file chooser chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS , new Parcelable[] { captureIntent }); // On select image call onActivityResult method of activity startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE); } // openFileChooser for Android < 3.0 public void openFileChooser(ValueCallback uploadMsg) { openFileChooser(uploadMsg, ""); } //openFileChooser for other Android versions public void openFileChooser(ValueCallback uploadMsg, String acceptType, String capture) { openFileChooser(uploadMsg, acceptType); } } 

    // здесь мой метод onActivityResult для обработки данных из галереи или цели камеры

     @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (requestCode != INPUT_FILE_REQUEST_CODE || mFilePathCallback == null) { super.onActivityResult(requestCode, resultCode, data); return; } Uri[] results = null; // Check that the response is a good one if (resultCode == Activity.RESULT_OK) { if (data == null) { // If there is not data, then we may have taken a photo if (mCameraPhotoPath != null) { results = new Uri[]{Uri.parse(mCameraPhotoPath)}; } } else { String dataString = data.getDataString(); if (dataString != null) { results = new Uri[]{Uri.parse(dataString)}; } } } mFilePathCallback.onReceiveValue(results); mFilePathCallback = null; } else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) { if (requestCode != FILECHOOSER_RESULTCODE || mUploadMessage == null) { super.onActivityResult(requestCode, resultCode, data); return; } if (requestCode == FILECHOOSER_RESULTCODE) { if (null == this.mUploadMessage) { return; } Uri result = null; try { if (resultCode != RESULT_OK) { result = null; } else { // retrieve from the private variable if the intent is null result = data == null ? mCapturedImageURI : data.getData(); } } catch (Exception e) { Toast.makeText(getApplicationContext(), "activity :" + e, Toast.LENGTH_LONG).show(); } mUploadMessage.onReceiveValue(result); mUploadMessage = null; } } return; } 

    и вот разрешения, необходимые для открытия камеры

       // for new versions api 21+    

    Примечание. В моем коде также содержится код для устройств с версии 3.0+, но я их никогда не тестировал, этот код работал на эмуляторах Lolipop, Marshmallow и Nougat. Еще одна вещь, если вы видите и иконку Android System вместо Camera, это означает, что у вас есть много приложений, доступных на вашем устройстве для работы с камерой.

    Мне жаль, мой английский.

    Это решение.

    Во-первых, вы определяете член файла следующим образом.

    public File mTempFile;

    ваш openFileChooser в порядке.

    onActivityResult так важно.

    приложение камеры не возвращает URL-адрес, но ValueCallback должен иметь URL-адрес.

    Получить uri из mTempFile.

    это работа.

    Я так использую.

     if ( mTempFile.exists() ) { mUploadMessage.onReceiveValue(Uri.fromFile(mTempFile)); mUploadMessage = null; } else { mUploadMessage.onReceiveValue(result); mUploadMessage = null; } 

    Если существует mTempFile, который был вызван камерой, другой случай из галереи.

    Убедитесь, что у вас нет android:launchMode="singleInstance" в файле манифеста

    Давайте будем гением компьютера.