2010-08-31 3 views
16

Я начал писать приложение, которое предоставляет пользователю форму HTML через WebView. Поскольку форма не находится под моим контролем, заполненные данные могут быть отправлены как GET, так и POST-запрос. Мое приложение должно захватывать данные переносимой формы, то есть задерживать то, что было введено в поля формы.Возможно ли получить доступ к данным HTML-формы, отправленным через WebView?

Используя адекватный обратный вызов из WebViewClient, такой как onPageLoaded(), легко получить данные формы из запроса GET. Тем не менее, я не могу найти подходящий метод, позволяющий делать то же самое для POSTED-данных, то есть иметь возможность доступа к телу сообщения HTTP POST, содержащему данные формы. Я пропустил соответствующий обратный вызов здесь или нет простого пути для достижения указанной цели с данным API (даже последний уровень 8)?

Предполагая, что это невозможно, я рассмотрел вопрос о переопределении и расширении частей android.webkit, чтобы ввести новый крюк обратного вызова, который каким-то образом передается POST-корпусом. Таким образом, мое приложение может быть отправлено с помощью настроенного браузера/WebViewClient, который выполняет желаемую функцию. Тем не менее, я не мог найти хорошего места для начала в коде и был бы рад любым намекам в этом отношении (в случае, если подход выглядит перспективным вообще).

Заранее благодарен!

+0

На самом деле, я, возможно, нашли способ себя: Должна быть возможность вводить некоторые JavaScript, который разбирает поля формы, когда пользователь отправляет форму. Приведенный интерфейс Javascript-to-Java затем должен быть способен переносить заполненные данные обратно в пространство Java для дальнейшей обработки. Попробуй этот подход и сообщите об этом. Конечно, любые дальнейшие отзывы по-прежнему приветствуются! –

ответ

22

Как указано в моем собственном комментарии к исходному вопросу, работает подход внедрения JavaScript. В основном, что вам нужно сделать, это добавить часть кода JavaScript в событие DOM onsubmit, проанализировать поля формы и вернуть результат обратно к зарегистрированной Java функции.

Пример кода:

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

неформально, что это делает впрыскивать JavaScript код обычая (как onsubmit обработчика) всякий раз, когда страница загрузится. При представлении формы Javascript будет анализировать данные формы и передавать ее обратно на землю Java через объект JavaScriptInterface.

Для разбора полей формы код Javascript добавляет форму onsubmit и кнопку onclick обработчиков. Первый может обрабатывать представления канонической формы через обычную кнопку отправки, в то время как последний имеет дело с пользовательскими кнопками отправки, то есть кнопками, которые делают некоторую дополнительную магию JavaScript, прежде чем звонить form.submit().

Обратите внимание, что код Javascript может быть не идеальным: могут быть другие методы отправки формы, которую мой код ввода не сможет поймать. Тем не менее, я убежден, что введенный код можно обновить, чтобы справиться с такими возможностями.

+0

'window.HTMLOUT.processFormData (data);' не работает для меня, а просто 'HTMLOUT.processFormData (data);' работал для меня. – flexdroid

+0

приятно .... спасибо человеку – Noman

+0

нормально, я финналы получил его. исправил код также –

6

Предоставленный ответ дает ошибку, так что я решил сделать более простую реализацию, которая также признаки хорошо структурированный JavaScript (то есть JS в файле):

В ваших активах папке создать файл с именем inject.js с помощью следующего кода внутри:

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

Это Java-код, который мы будем использовать для инъекций, вы можете переключиться из КРП заявление, как вы считаете нужным, и вместо этого или имен используете тип.Обратный вызов для Android эта линия: window.AndroidInterface.processHTML(str);

Тогда ваша активность/фрагмент должен выглядеть следующим образом:

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

Где вы получаете значение из поля ввода –

Смежные вопросы