2010-08-31 12 views
16

Ho iniziato a scrivere un'app che fornisce all'utente un modulo HTML tramite una WebView. Poiché il modulo non è sotto il mio controllo, i dati inseriti possono essere inviati come richiesta GET o POST. La mia app è richiesta per catturare i dati del modulo trasportato, vale a dire, ottenere una sospensione su ciò che è stato inserito nei campi del modulo.è possibile accedere ai dati dei moduli HTML inviati tramite WebView?

Utilizzando un callback adeguato da WebViewClient come onPageLoaded(), è facile acquisire i dati dei moduli da una richiesta GET. Tuttavia, non riesco a trovare alcun metodo appropriato per consentire lo stesso per i dati POST, cioè, essere in grado di accedere al corpo del messaggio POST HTTP contenente i dati del modulo. Mi manca una richiamata rilevante qui o semplicemente non c'è modo di realizzare l'obiettivo specificato con l'API fornita (anche l'ultimo livello 8)?

Supponendo che non fosse possibile, ho considerato l'override e l'estensione di parti di android.webkit per introdurre un nuovo hook di richiamata che è passato in qualche modo al corpo POST. In questo modo, la mia app potrebbe essere fornita con un browser personalizzato/WebView Client che soddisfa la funzionalità desiderata. Tuttavia, non sono riuscito a trovare alcun buon punto di partenza nel codice e sarei lieto di avere qualche suggerimento in merito (nel caso in cui l'approccio sembra affatto promettente).

Grazie in anticipo!

+0

In realtà, forse ho trovato me stesso modo: Dovrebbe essere possibile iniettare un po 'di JavaScript che analizza il forma i campi quando l'utente invia il modulo. L'interfaccia Javascript-to-Java fornita dovrebbe quindi essere in grado di trasferire nuovamente i dati compilati nello spazio Java per un'ulteriore elaborazione. Proverà questo approccio e riferirà. Naturalmente, ogni ulteriore feedback è ancora benvenuto! –

risposta

22

Come indicato nel mio commento alla domanda originale, l'approccio di iniezione JavaScript funziona. Fondamentalmente, ciò che devi fare è aggiungere qualche parte del codice JavaScript all'evento onsubmit DOM, far analizzare i campi del modulo e restituire il risultato a una funzione registrata in Java.

Codice esempio:

public class MyBrowser extends Activity { 
    private final String jsInjectCode = 
     "function parseForm(event) {" + 
     " var form = this;" + 
     " // make sure form points to the surrounding form object if a custom button was used" + 
     " if (this.tagName.toLowerCase() != 'form')" + 
     "  form = this.form;" +  
     " var data = '';" + 
     " if (!form.method) form.method = 'get';" + 
     " data += 'method=' + form.method;" + 
     " data += '&action=' + form.action;" +   
     " var inputs = document.forms[0].getElementsByTagName('input');" + 
     " for (var i = 0; i < inputs.length; i++) {" + 
     "   var field = inputs[i];" + 
     "   if (field.type != 'submit' && field.type != 'reset' && field.type != 'button')" + 
     "    data += '&' + field.name + '=' + field.value;" + 
     " }" + 
     " HTMLOUT.processFormData(data);" + 
     "}" + 
     "" + 
     "for (var form_idx = 0; form_idx < document.forms.length; ++form_idx)" + 
     " document.forms[form_idx].addEventListener('submit', parseForm, false);" +  
     "var inputs = document.getElementsByTagName('input');" + 
     "for (var i = 0; i < inputs.length; i++) {" + 
     " if (inputs[i].getAttribute('type') == 'button')" + 
     "  inputs[i].addEventListener('click', parseForm, false);" + 
     "}" + 
     ""; 

    class JavaScriptInterface { 
     @JavascriptInterface 
     public void processFormData(String formData) { 
      //added annotation for API > 17 to make it work 
      <do whatever you need to do with the form data> 
     } 
    } 

    onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.browser); 
     WebView browser = (WebView)findViewById(R.id.browser_window); 
     browser.getSettings().setJavaScriptEnabled(true); 
     browser.addJavascriptInterface(new JavaScriptInterface(), "HTMLOUT"); 
     browser.setWebViewClient(new WebViewClient() { 
     @Override 
     public boolean shouldOverrideUrlLoading(WebView view, String url) { 
      view.loadUrl(url); 
      return true; 
     } 

     @Override 
     public void onPageFinished(WebView view, String url) { 
      view.loadUrl("javascript:(function() { " + 
         MyBrowser.jsInjectCode + "})()"); 
     } 
} 

Informalmente, Quello che fa è iniettare il codice JavaScript personalizzato (come un gestore onsubmit) ogni volta che una pagina termina il caricamento. All'invio di un modulo, Javascript analizzerà i dati del modulo e li ritrasferirà su Java tramite l'oggetto JavaScriptInterface.

Per analizzare i campi modulo, il codice Javascript aggiunge il modulo onsubmit e il pulsante onclick gestori. Il primo può gestire l'invio di moduli canonici tramite un normale pulsante di invio, mentre il secondo riguarda i pulsanti di invio personalizzati, ovvero i pulsanti che eseguono alcune magie Javascript aggiuntive prima di chiamare form.submit().

Si prega di notare che il codice Javascript potrebbe non essere perfetto: potrebbero esserci altri metodi per inviare un modulo che il mio codice iniettato potrebbe non essere in grado di catturare. Tuttavia, sono convinto che il codice iniettato possa essere aggiornato per gestire tali possibilità.

+0

'window.HTMLOUT.processFormData (dati);' non ha funzionato per me ma solo 'HTMLOUT.processFormData (dati);' ha funzionato per me. – flexdroid

+0

nice .... grazie uomo – Noman

+0

ok, ho capito. corretto il codice anche –

6

La risposta fornita dà l'errore, così ho deciso di fare un'implementazione più semplice, che inoltre ha caratterizzato ben strutturato JavaScript (JS senso è in un file):

Nel vostro patrimonio cartella creare un file chiamato inject.js con codice seguente all'interno:

document.getElementsByTagName('form')[0].onsubmit = function() { 
    var objPWD, objAccount, objSave; 
    var str = ''; 
    var inputs = document.getElementsByTagName('input'); 
    for (var i = 0; i < inputs.length; i++) { 
     if (inputs[i].name.toLowerCase() === 'username') { 
      objAccount = inputs[i]; 
     } else if (inputs[i].name.toLowerCase() === 'password') { 
      objPWD = inputs[i]; 
     } else if (inputs[i].name.toLowerCase() === 'rememberlogin') { 
      objSave = inputs[i]; 
     } 
    } 
    if(objAccount != null) { 
     str += objAccount.value; 
    } 
    if(objPWD != null) { 
     str += ' , ' + objPWD.value; 
    } 
    if(objSave != null) { 
     str += ' , ' + objSave.value; 
    } 
    window.AndroidInterface.processHTML(str); 
    return true; 
}; 

Questo è il codice javascript che useremo per le iniezioni, è possibile passare l'istruzioni if, come si vede in forma e utilizzare i tipi di posto o di nomi.La richiamata per Android è questa linea: window.AndroidInterface.processHTML(str);

Allora la vostra attività/frammento dovrebbe assomigliare a questa:

public class MainActivity extends ActionBarActivity { 
    class JavaScriptInterface { 
     @JavascriptInterface 
     public void processHTML(String formData) { 
      Log.d("AWESOME_TAG", "form data: " + formData); 
     } 
    } 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     WebView webView = new WebView(this); 
     this.setContentView(webView); 

     // enable javascript 
     WebSettings webSettings = webView.getSettings(); 
     webSettings.setJavaScriptEnabled(true); 
     webView.addJavascriptInterface(new JavaScriptInterface(), "AndroidInterface"); 

     // catch events 
     webView.setWebViewClient(new WebViewClient(){ 
      @Override 
      public void onPageFinished(WebView view, String url) { 
       try { 
        view.loadUrl("javascript:" + buildInjection()); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 
     }); 

     webView.loadUrl("http://someurl.com"); 
    } 

    private String buildInjection() throws IOException { 
     StringBuilder buf = new StringBuilder(); 
     InputStream inject = getAssets().open("inject.js");// file from assets 
     BufferedReader in = new BufferedReader(new InputStreamReader(inject, "UTF-8")); 
     String str; 
     while ((str = in.readLine()) != null) { 
      buf.append(str); 
     } 
     in.close(); 

     return buf.toString(); 
    } 
+0

Dove si ottiene il valore dalla casella di testo –

Problemi correlati