Nueva Estrategia. Usar Un WebView De Proxy.

Tras un par de horas leyendo y programando, se me acaba de ocurrir una forma más directa y sencilla de realizar el "proxy", o mas bien es un workaround. Simplemente crear un editText para urls, y cuando se pulse el botón, se pase el texto (url) al WebView, a poder ser corriendo sin interfaz de forma asyncrona en la propia actividad.

Para cumplir con el objetivo de poder usar XHR, usaré una interfaz que me permita comunicar Java y Javascript. Entonces cada petición de Javascript, va a llamar a la interfaz expuesta de Java. El WebView obtiene el código fuente utilizando el pseudoProtocolo pasándole un script directamente al motor WebKit como argumento del método loadUrl de la instancia del WebView y le envía de vuelta el contenido al documento HTML (tras obtenerlo con un querySelector) también a través de loadURL modificando la propiedad respuesta de XHR como si de una respuesta real de XHR se tratase. Creo que puede quedar totalmente transparente para el usuario. Lo que no tengo atado es lo del WebView sin interfaz. No aseguro que se pueda de manera directa. En todo caso podré hacerlo bindeándolo como servicio.

Ya tengo un mini ejemplo que hice en github.com/StringManolo de como usar interfaces y ya tiene un HTML, la interfaz a Javascript y el WebView para abrir el HTML. No sé si necesitaré un segundo WebView para fetchear el contenido, o podré hacerlo desde la misma instancia de WebView que utilizo para renderizar el HTML. Me parece bastante trivial de implementar, asique en un rato me pondré a ello.



Llevo un rato programando y me apetece compartir lo que llevo hecho.

ActividadPrincipal.java
package com.stringmanolo.proxyview;

import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebSettings;
import android.webkit.WebViewClient;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.annotation.TargetApi;


import com.stringmanolo.proxyview.R;

public class ActividadPrincipal extends Activity {

  private WebView ProxyView;
 
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.principal_actividad);
   
    ProxyView  = new WebView(this);

    WebSettings webSettings = ProxyView.getSettings();
    webSettings.setJavaScriptEnabled(true); 
 
    String MiUserAgent = "Mozilla/5.0 (Linux; U; Android 4.3; en-us; SM-N900T Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30";
    ProxyView.getSettings().setUserAgentString(MiUserAgent);

    ProxyView.addJavascriptInterface(new JSInterface(this), "ProxyView");

    ProxyView.setWebViewClient(new WebViewClient() {
      @TargetApi(android.os.Build.VERSION_CODES.M)
      @Override
      public void onReceivedError(WebView view, WebResourceRequest req, WebResourceError rerr) {
        onReceivedError(view, rerr.getErrorCode(), rerr.getDescription().toString(), req.getUrl().toString());
      }
    });
  
  ProxyView.loadUrl("file:///android_asset/Request.html");
  setContentView(ProxyView);
  }

  @Override
  public void onBackPressed() {
    if(ProxyView.canGoBack()) {
      ProxyView.goBack();
    }

    else {
      super.onBackPressed();
    }
  }
}


JSinterfaz
package com.stringmanolo.proxyview;

import android.content.Context;
import android.webkit.JavascriptInterface;

/* TO DO:
* Add request headers before send request
* Callback to webview?
*
*/

public class JSInterface {
  Context mContext;
  JSInterface(Context c) {
    mContext = c;
  }

  @JavascriptInterface
  public void Request(String method, String url) {
   /* Pass Intent To WebView to make request */
   }
   
}


request.html

<!DOCTYPE html>
<html>
  <!-- This file is just a working example
about, how to make Cross Origen Requests -->
  <head>
    <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
    <meta charset="UTF-8">
    <title>Requests</title>
  </head>
  <body>
    <input type="text" class="request" placeholder="method">
    <input type="text" class="request" placeholder="url">
    <button type="button" id="request">Send
 
    
<button type="button" onclick="alert(referenceObject.url + ' ' + referenceObject.method)">Test
    <script>
    
      function Request(method, url, callback) {
        ProxyView.request(method, url);
      }
    
    
    /* This object will have the method and the url to craft the request after button click event. */
    var referenceObject = {};
    var buttonEvent;
    
    function main() {  

      
      
      function getRequestParams(inputsByClass, buttonById, reference) {
        var inputs = document.getElementsByClassName(inputsByClass);
      
        var request = {};
        request.method=(inputs[0].value).toString();
        request.url=(inputs[1].value).toString();
        referenceObject = JSON.parse(JSON.stringify(request));
      }
   
         
      
      var button = document.getElementById("request");      
      buttonEvent = button.addEventListener("click", function(){getRequestParams("request", "request", referenceObject)});
      
    } window.onload=main();
    </script>
  </body> 
</html>

Comentarios

Entradas populares