wake-up-neo.com

Laden Sie ein Bild von einer Kamera oder Galerie in WebView hoch

WebView in dieser App öffnet eine Seite mit Upload-Button.

Page in webview with upload button

Unten finden Sie den Codeblock, mit dem Sie ein Dialogfeld zum Hochladen von Bildern aus der Galerie oder Kamera öffnen können.

Innerhalb meiner Aktivität habe ich:

 private WebView wv;  

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

Innerhalb von onCreate habe ich folgendes:

    wv.setWebChromeClient(new WebChromeClient()  {
        private Uri imageUri;   

        public void openFileChooser(ValueCallback<Uri> 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<Intent> cameraIntents = new ArrayList<Intent>();
            final Intent captureIntent = new Intent(Android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
            final PackageManager packageManager = getPackageManager();
            final List<ResolveInfo> 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); 
        }

Ich kann die Option für Kamera, Bildergalerie und Datei-Explorer sehen, wenn ich auf die Schaltfläche Hochladen klicke. Camera, gallery and file Explorer upload option

Der Datei-Explorer und die Galerie funktionieren wie erwartet. Das Problem ist, dass wenn ich ein Bild mit einer Kamera aufnehme, es nicht in der Option "Datei auswählen" hochgeladen wird, die den Status "Keine Datei ausgewählt" anzeigt.

BEI AUSWAHL DER KAMERA:

camera

BEI AUFNAHME EINES SCHNAPPSCHUSSES MIT DER KAMERA: zurück, und die Optionen werden angezeigt.

snapshot using camera

BEI WAHL DES PRÜFZEICHENS:

DATEI IS NICHT HOCHGELADEN :( IN DER OPTION "DATEI AUSWÄHLEN"

enter image description here

WAS IS ERWARTET:

image uploaded

Ich habe überprüft, ob ich die richtige Schreibberechtigung habe, und daher wird ein Verzeichnis mit dem Namen "MyApp" erstellt und das Bild darin gespeichert (wenn Sie die Kamera aufrufen, nachdem Sie auf die Schaltfläche "Hochladen" auf der Webseite geklickt haben).

Wie kann ich die Anwendung programmgesteuert anweisen, ein von der Kamera (die im MyApp-Verzeichnis gespeichert ist) aufgenommenes Bild auszuwählen, nachdem ich das Häkchen gedrückt habe?

24
Chirag

Ich nehme an, dass die onActivityResult -Methode tatsächlich aufgerufen wird, aber der 3. Parameter Intent intent ist Null. Es scheint, dass es ein Fehler von Nexus-Handys ist.

Sie können das Ausgabebild uri jedoch in der privaten Variablen speichern und anstelle der Absicht verwenden:

private Uri imageUri;

private void showAttachmentDialog(ValueCallback<Uri> 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;
    }
}

In diesem Code habe ich der Aktivität die Variable imageUri hinzugefügt und sie in beiden Methoden verwendet.

10
vortexwolf

Nachdem ich viel gekämpft habe, habe ich einen Code gefunden, mit dem ich Dateien von der Kombüse und von der Kamera von Geräten ab 5.0 kopieren kann

    private ValueCallback<Uri> mUploadMessage;
private Uri mCapturedImageURI = null;
private ValueCallback<Uri[]> 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;
}

dies ist die Initialisierung und Einstellung von 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());

und hier ist meine ChomeClient () - Methode

public class ChromeClient extends WebChromeClient {

    // For Android 5.0
    public boolean onShowFileChooser(WebView view, ValueCallback<Uri[]> 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<Uri> 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<Uri> uploadMsg) {
        openFileChooser(uploadMsg, "");
    }

    //openFileChooser for other Android versions
    public void openFileChooser(ValueCallback<Uri> uploadMsg,
                                String acceptType,
                                String capture) {

        openFileChooser(uploadMsg, acceptType);
    }

}

// hier ist meine onActivityResult-Methode zum Verarbeiten von Daten aus der Galerie oder der Kameraabsicht

@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;
}

und hier sind die erforderlichen Berechtigungen zum Öffnen der Kamera

<uses-permission Android:name="Android.permission.CAMERA" />
<uses-permission Android:name="Android.permission.CAMERA2" /> // for new versions api 21+
<uses-permission Android:name="Android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission Android:name="Android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission Android:name="Android.permission.RECORD_AUDIO" />

Hinweis: Mein Code enthält auch den Code für Geräte, auf denen 3.0+ ausgeführt wird, aber ich habe sie nie getestet. Der obige Code funktionierte auf Lolipop-, Marshmallow- und Nougat-Emulatoren. Wenn Sie anstelle der Kamera das Symbol Android System sehen, bedeutet dies, dass auf Ihrem Gerät viele Apps für die Kamera verfügbar sind.

9
Umar Ata

pdate 6/18: Dies scheint auf Samsung Galaxy S2 mit Android 4.2.1 nicht zu funktionieren. Dies funktionierte gut auf HTC One X + mit 4.1.2. Seien Sie gewarnt.


Ich hatte das gleiche Problem. Hier ist das Problem und wie ich es gelöst habe.

Problem:

Beim Aufruf von openFileChooser wird das Callback-Objekt ValueCallback<Uri> Übergeben. Dies ist der eigentliche Aufruf der Webansicht, wenn eine Datei dafür bereitsteht. Wir speichern dieses Objekt in mUploadMessage und verwenden die Funktion mUploadMessage.onReceiveValue() in onActivityResult, um die Datei an Webview zurückzugeben. Während Sie die Kamera auswählen, auf ein Bild klicken, es speichern und zur Webansicht-Aktivität zurückkehren, wird unsere Aktivität möglicherweise recycelt, was bedeutet, dass wir das Rückrufobjekt mUploadMessage tatsächlich verlieren. Daher kann die Datei nicht zum Hochladen an webview zurückgegeben werden.

Fix:

Um dieses Problem zu beheben, muss Javascript ausgeführt werden. Aktivieren Sie Javascript in der Webansicht. Grundsätzlich erhalten wir ein weiteres Rückrufobjekt, wenn wir das vorherige verloren haben.

Wir müssen ein boolesches Feld 'mUploadFileOnLoad' und drei Felder erstellen.

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

Wenn wir von der Kamera zu unserer Aktivität zurückkehren, wird onActivityResult aufgerufen. Wenn die Aktivität rekonstruiert wird, ist mUploadMessage null. Also werden wir die Parameter in Felder speichern und mUploadFileOnLoad auf true setzen und zurückgeben. Der übrige Teil ist sehr wichtig.

    @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
    }

Die wichtigen Teile dieser Lösung befinden sich in WebViewClient und 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<Uri> 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....
         }

und

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

Oben ist my_file Die ID des Elements <input> Auf der Webseite.

<input type="file" id="my_file">

Zusammenfassend haben wir also Folgendes getan: Wenn wir kein Rückrufobjekt haben, speichern wir die von anderen Aktivitäten empfangenen Daten und setzen mUploadFileOnLoad auf true und warten auf das Laden der Seite. Beim Laden der Seite verwenden wir Javascript, um die Dateiauswahl aufzurufen, damit wir ein Rückrufobjekt erhalten. Da wir bereits Ergebnisse haben, rufen wir onActivityResult auf und kehren zurück. onActivityResult hat jetzt einen Rückruf von der Webansicht.

6
Sundeep

Es tut mir leid mein Englisch.

Das ist die Lösung.

Als erstes definieren Sie so ein Dateimitglied.

public File mTempFile;

ihr openFileChooser ist in Ordnung.

onActivityResult Methode ist so wichtig.

kamera-App gibt keine URL zurück, aber ValueCallback muss eine URL haben.

Holen Sie sich Uri von mTempFile.

das ist Arbeit.

Ich benutze so.

if ( mTempFile.exists() ) {

    mUploadMessage.onReceiveValue(Uri.fromFile(mTempFile));
    mUploadMessage = null;

} else {

    mUploadMessage.onReceiveValue(result);
    mUploadMessage = null;
}

Wenn mTempFile vorhanden ist, das als camera bezeichnet wurde, ein anderer Fall aus der Galerie.

3
user3558502

Stellen Sie sicher, dass die Manifestdatei NICHT Android:launchMode="singleInstance" Enthält

2
user2381711