[android] Carica un'immagine dalla fotocamera o dalla galleria in WebView


Answers

Aggiornamento 6/18: Questo non sembra funzionare su Samsung Galaxy S2 con Android 4.2.1. Questo ha funzionato bene su HTC One X + con 4.1.2. Essere ammonito

Ho affrontato lo stesso problema. Ecco il problema e come l'ho risolto.

Problema:

Quando viene chiamato openFileChooser viene passato l'oggetto ValueCallback<Uri> . Questa è la chiamata effettiva alla visualizzazione web quando abbiamo un file pronto per questo. Salviamo questo oggetto su mUploadMessage e usiamo la funzione mUploadMessage.onReceiveValue() in onActivityResult per restituire il file a Webview. Mentre scegli la fotocamera, fai clic su un'immagine, salvala e torna all'attività di visualizzazione Web, la nostra attività potrebbe essere riciclata, il che significa che in realtà perdiamo l'oggetto mUploadMessage . E quindi, il file non può essere restituito a Webview per il caricamento.

Difficoltà:

Correzione comporta l'esecuzione di alcuni javascript, quindi abilitare JavaScript su Webview. Fondamentalmente, otterremo un altro oggetto di richiamo se abbiamo perso il precedente.

Dobbiamo creare un campo booleano ' mUploadFileOnLoad ' e tre campi.

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

Quando torniamo alla nostra attività dalla fotocamera, verrà chiamato onActivityResult . Se l'attività viene ricostruita, mUploadMessage è nullo. Quindi, salveremo i parametri nei campi e imposteremo mUploadFileOnLoad su true e return. L'altra parte è molto importante.

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

Le parti importanti di questa soluzione sono in WebViewClient e 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....
         }

e

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

In quanto sopra, my_file è l'id dell'elemento <input> nella pagina web.

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

Quindi, in sintesi, quello che abbiamo fatto è: quando non abbiamo un oggetto di callback, salviamo i dati ricevuti da altre attività e impostiamo mUploadFileOnLoad su true e mUploadFileOnLoad caricamento della pagina. Quando la pagina viene caricata, usiamo Javascript per invocare il selettore di file in modo da ottenere un oggetto di callback. Poiché abbiamo già dei risultati, invochiamo onActivityResult e ritorniamo. onActivityResult ora ha un callback dalla webview.

Question

WebView in questa app apre una pagina con il pulsante di caricamento.

Di seguito è riportato il blocco di codice che consente di aprire una finestra di dialogo per caricare l'immagine dalla galleria o dalla fotocamera.

All'interno della mia attività ho:

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

All'interno di onCreate ho il seguente:

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

Sono in grado di vedere l'opzione per fotocamera, galleria di immagini e file explorer facendo clic sul pulsante Carica.

File explorer e Gallery funziona come previsto. Il problema è che, quando scatto una foto utilizzando la fotocamera, non viene caricata nell'opzione "scegli file" che mostra lo stato "Nessun file scelto".

SULLA SELEZIONE DELLA VIDEOCAMERA:

ACCENDERE SNAPSHOT MEDIANTE FOTOCAMERA: vengono visualizzate le opzioni Indietro e controllo.

SULLA SCELTA DEL CONTRASSEGNO:

FILE NON È CARICATO :( IN OPZIONE "SCEGLI IL FILE"

CHE COSA È PREVISTO:

Ho controllato che ho il permesso di scrittura corretto e quindi viene generata una directory denominata "MyApp" e l'immagine viene memorizzata al suo interno (se presa richiamando la telecamera dopo aver fatto clic sul pulsante di caricamento sulla pagina Web).

Come dire programmaticamente all'applicazione di scegliere la foto scattata dalla fotocamera (che è stata memorizzata nella directory MyApp) dopo aver premuto il segno di spunta?




Mi dispiace il mio inglese.

Questa è una soluzione.

Il primo, si definisce un membro del file come questo.

public File mTempFile;

il tuo openFileChooser è ok.

onActivityResult metodo onActivityResult è così importante.

l'app della fotocamera non restituisce l'url, ma ValueCallback deve avere l'url.

Ottieni uri da mTempFile.

questo è lavoro.

Io uso così.

if ( mTempFile.exists() ) {

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

} else {

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

Se esiste mTempFile che è stato chiamato camera, altro caso dalla galleria.




Links