2010-08-31 7 views
16

Ich habe angefangen, eine App zu schreiben, die dem Benutzer ein HTML-Formular über ein WebView zur Verfügung stellt. Da das Formular nicht unter meiner Kontrolle ist, können die ausgefüllten Daten entweder als GET- oder als POST-Anfrage gesendet werden. Meine App wird benötigt, um die transportierten Formulardaten zu erfassen, dh um zu erhalten, was in die Formularfelder eingegeben wurde.ist es möglich, auf HTML-Formulardaten zuzugreifen, die über ein WebView POSTed sind?

Mit einem angemessenen Rückruf von WebViewClient wie onPageLoaded(), ist es einfach, Formulardaten von einer GET-Anfrage zu erfassen. Ich kann jedoch keine geeignete Methode finden, um das Gleiche für POST-Daten zu ermöglichen, d. H. In der Lage zu sein, auf den HTTP POST-Nachrichtentext zuzugreifen, der die Formulardaten enthält. Fehle mir hier ein relevanter Callback oder gibt es einfach keine Möglichkeit, das angegebene Ziel mit der gegebenen API zu erreichen (selbst die neueste Stufe 8)?

Angenommen, es war nicht möglich, ich überlegte, Teile von android.webkit zu überschreiben und zu erweitern, um einen neuen Callback-Hook einzuführen, der den POST-Körper irgendwie passiert. Auf diese Weise könnte meine App mit einem angepassten Browser/WebViewClient ausgeliefert werden, der die gewünschte Funktion erfüllt. Allerdings konnte ich im Code keinen guten Startpunkt finden und würde mich über Hinweise in dieser Hinsicht freuen (falls der Ansatz überhaupt vielversprechend erscheint).

Vielen Dank im Voraus!

+0

Eigentlich habe ich mich einen Weg gefunden haben: Es sollte möglich sein, einige JavaScript zu injizieren, die das parsen Formularfelder, wenn der Benutzer das Formular absendet. Die bereitgestellte Javascript-zu-Java-Schnittstelle sollte dann in der Lage sein, die gefüllten Daten zur weiteren Verarbeitung in den Java-Raum zurück zu übertragen. Will diesen Ansatz versuchen und Bericht erstatten. Natürlich sind weitere Rückmeldungen immer noch willkommen! –

Antwort

22

Wie in meinem eigenen Kommentar zu der ursprünglichen Frage angegeben, funktioniert der JavaScript-Injektionsansatz. Im Grunde müssen Sie dem DOM-onsubmit-Ereignis ein Stück JavaScript-Code hinzufügen, die Felder des Formulars analysieren und das Ergebnis an eine von Java registrierte Funktion zurückgeben.

Code-Beispiel:

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 + "})()"); 
     } 
} 

Informell, das, was tut, ist die benutzerdefinierte JavaScript-Code (als onsubmit Handler) injiziert, wenn eine Seite fertig geladen. Bei der Übermittlung eines Formulars analysiert Javascript die Formulardaten und gibt sie über das Objekt JavaScriptInterface an Java zurück.

Um Formularfelder zu analysieren, fügt der Javascript-Code Formular onsubmit und Schaltfläche onclick Handler hinzu. Ersteres kann kanonische Formulareinreichungen durch eine reguläre Übergabeschaltfläche behandeln, während letztere mit benutzerdefinierten Übergabeschaltflächen, d. H. Schaltflächen, die zusätzliche Javascript-Magie ausführen, bevor sie form.submit() aufrufen, umgehen kann.

Bitte beachten Sie, dass der Javascript-Code möglicherweise nicht perfekt ist: Es könnte andere Methoden geben, ein Formular zu senden, das mein injizierter Code möglicherweise nicht erfassen kann. Ich bin jedoch überzeugt, dass der injizierte Code aktualisiert werden kann, um mit solchen Möglichkeiten umzugehen.

+0

'window.HTMLOUT.processFormData (data);' hat nicht für mich funktioniert, sondern nur 'HTMLOUT.processFormData (data);' hat für mich funktioniert. – flexdroid

+0

schön .... danke mann – Noman

+0

ok, ich habe es endlich bekommen. korrigierte den Code auch –

6

Die bereitgestellte Antwort gibt Fehler, damit ich eine einfachere Implementierung machen beschlossen, die auch JavaScript gut strukturiert funktions (JS Sinn in einer Datei ist):

In Ihrem Vermögen Ordner eine Datei namens inject.js mit folgendem Code erstellen innen:

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

Dies ist der Javascript-Code, den wir für Injektionszwecke verwenden werden, können Sie die if-Anweisungen, wie Sie sehen fit wechseln und Typen anstelle oder Namen verwenden.Der Rückruf an Android ist diese Zeile: window.AndroidInterface.processHTML(str);

dann Ihre Aktivität/Fragment sollte wie folgt aussehen:

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

Woher bekommen Sie den Wert aus der Eingabebox? –

Verwandte Themen