Trabajando con imágenes SVG en Android: Interface entre Java y Javascript.

Como prometí en el artículo anterior Trabajando con imágenes SVG en Android hoy les voy a contar cómo podemos “comunicarnos” con Javascript, desde Java.

La palabra comunicarnos la escribo entre comillas ya que me refiero a pasar data entre las dos tecnologías. Para hacer esto necesitamos una interface en Java que se implementa de una manera muy sencilla.

Para empezar y para que sea más sencillo vamos utilizar el mismo código que el artículo anterior y voy a resaltar en negrita lo necesario para poder interactuar con el Javascript de la web que hay en el WebView. En este caso lo que quiero es “interceptar” el evento click en la web y vamos a mostrar el id del punto donde hagamos “tap”. Para interceptar ese evento vamos a usar Javascript con Jquery (muy fácil, ya verán) y ahí llamaremos a nuestro método en Java.

Ahora sí! Basta de explicaciones y vamos a lo importante, el código.

Así quedará nuestra Activity, en este caso llamada MainActivity.java

public class MainActivity extends AppCompatActivity {

private String mTextToPass;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

WebView webView = (WebView) this.findViewById(R.id.webView);
//Para ejecutar JS en el webView
webView.getSettings().setJavaScriptEnabled(true);
//Para poder hacer zoom en el webView
webView.getSettings().setSupportZoom(true);
webView.getSettings().setBuiltInZoomControls(true);
//Para que no muestre controles de zoom
webView.getSettings().setDisplayZoomControls(false);
//Instancia para que el webView pueda manejar todas las funciones de Chrome
webView.setWebChromeClient(new WebChromeClient());
webView.setWebViewClient(new WebViewClient());
//Agregamos la interfase llamada "Android" entre JS y Java.
webView.addJavascriptInterface(new InterfaseJavaJS(this), "Android");
mTextToPass = "Texto enviado desde Java";
//Cargamos el file que esta en la carpeta assets
webView.loadUrl("file:///android_asset/index.html");
}

//Clase que es la interfase
public class InterfaseJavaJS {
Context context;

WebAppInterface(Context c) {
context = c;
}

@JavascriptInterface //Importantísimo!
public void showToast(String msg) {
Toast.makeText(context, "El id que se clickeo es: " + msg, Toast.LENGTH_SHORT).show();
}
@JavascriptInterface //Importantísimo!
public String getStringFromJava() {
return mTextToPass;
}

}
}

Para resaltar en esta parte es el método webView.addJavascriptInterface(new InterfaseJavaJS(this), “Android”); ya que es el que le dice al WebView que agregue la interface con nombre “Android”. Como ven para esto creo una clase llamada InterfaseJavaJS con los métodos que voy a llamar desde JS. Otro punto importante es la notación “@JavascriptInterfase” arriba de cada método que se va a usar en JS, sin esto nunca se ejecutarían showToast y getStringFromJava.

Para este ejemplo utilice el DOM del svg embebido entre tags <div> como se ve en el siguiente código.

<body>
<div id="container">
<p id="svgString"></p>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.0"
width="168.89999mm"
height="279.39999mm"
viewBox="0 0 168.9 279.4"
id="svg2"
xml:space="preserve"
>
<defs
id="defs4"
>
<style
type="text/css"
id="style6"
/>
</defs>
.
. mucho código tags del svg
 <path
d="M 84.7898,134.635 C 84.7898,133.3983 83.7873,132.3957 82.5506,132.3957 C 81.3139,132.3957 80.3114,133.3983 80.3114,134.635 C 80.3114,135.8713 81.3139,136.874 82.5506,136.874 C 83.7873,136.874 84.7898,135.8716 84.7898,134.635 z "
style="
fill:#ffcc00"
id="path62"
/>
.
. mucho más tags del svg
.
</div>

El SVG está compuesto de tags, para decirlo de otra manera es un DOM. En este caso en partícular nos interesa el tag <path> que contiene el atributo id para poder mostrarlo.

Ahora pasemos al código de JS para ya ir cerrando el circuito con Java.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>

<script type="text/javascript">
$(document).ready(function(){
//obtengo el String que envié desde Java y lo agrego en un tag <p> con id svgString.
var svgDom = getSvgString();
$("#svgString").append(svgDom);
//por cada tag <path> le agrego el evento "click"
$("path").each(function(){
this.addEventListener("click", function(){
//invoco la función que llama al método de Java.
showAndroidToast(this.getAttribute("id"));
})
})
});

function showAndroidToast(toastMsg) {
Android.showToast(toastMsg);
}

function getSvgString() {
return Android.getStringFromJava();
}
</script>

¿Ven? No era tan difícil aunque debo reconocer que esas 5 líneas de Javascript para agregar el evento “click” me costó un poco. En esta parte lo importante es agregar el nombre de la interface antes de llamar al método de Java, como en el caso de Android.showToast(toastMsg);

Arriba a la izquierda se puede ver el texto enviado desde Java.
Al hacer tap sobre alguna columna amarilla, nos mostrará un Toast con el id del tag path que se tapeo.

Y con eso tenemos una interface entre Java y Javascript para poder obtener el “click” en la WebView y usarlo en Java para implementarlo en imágenes SVG en Android.

Subí el código a un repositorio en GitHub https://github.com/gastonmira/SVG-Android para que puedan bajarlo y jugar un poco.

Como siempre cualquier duda que tengan por favor comentenlo e intentaré responder lo antes posible.

Nota: Sí, ya sé podría haber usado un SnackBar en vez de un Toast.
Nota 2: Fuente de la imagen svg https://commons.wikimedia.org/wiki/File:Iglesia_de_San_Jose-Plano-Medellin.svg
A single golf clap? Or a long standing ovation?

By clapping more or less, you can signal to us which stories really stand out.