Hola Mundo con Android NDK [Parte 4]

¡Hola! Bienvenidos al 4º tutorial de Android NDK. Como ya habéis visto en el título del post, vamos a hacer un Hola Mundo con el NDK. Sabéis lo que significa, ¿no? ¡Primera aplicación! La aplicación que vamos a hacer va a ser sencillita. Su función será devolver un texto desde el NDK para mostrarlo en un TextView. Es un ejemplo simple, pero que creo que está bien para empezar. Ya haremos cosas más complejas en los próximos tutoriales.

  • Objetivo: aplicación que muestre un mensaje pasado desde el NDK.
  • Herramientas necesarias: Eclipse, Android SDK, Android NDK y una máquina virtual con Genymotion en versión menor que la 4.4, ya que no funciona muy bien con el NDK. También podéis usar el AVD del SDK, pero irá mucho más lento. Lo óptimo es un dispositivo físico, pero si no tenéis, usad una de las dos opciones para emular.

Si queréis ver los tutoriales de Android NDK, podéis hacerlo aquí.

Abajo tenéis este mismo tutorial pero grabado en vídeo. Lo he grabado por si lo preferís con voz ;)

Vamos a empezar.

PASO 1

Antes de nada, abrimos Eclipse y creamos un nuevo proyecto. Lo vamos a llamar HelloNDK. Va a tener soporte desde la API 14 hasta la 19. Podéis ver estas imágenes e ir siguiendo los pasos:

[gallery ids="9920,9921,9922

PASO 2

Vamos a programar la parte Java. Todavía no tocamos JNI (Java Native Interface) en el lado nativo.

Paso 2.1

Si os fijáis, el archivo activity_main.xml tiene un TextView como este:

<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" />

Como podéis ver, no tiene identificación, así que lo vamos a dejar así:

<TextView android:id="@+id/ndkTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" />

Paso 2.2

Ahora, en la clase MainActivity vamos a declarar el método nativo getStringFromJNI(), el cual nos devolverá el String "Hello from NDK". Además, crearemos una variable de la clase TextView para poder asignar ese texto a la aplicación. La librería de JNI la vamos a llamar hellondk. Nuestro código va a ser el siguiente:

public class MainActivity extends Activity { // Librería y método JNI static { System.loadLibrary("hellondk"); } native String getStringFromJNI(); TextView ndkText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Creo la variable TextView y le asigno el texto que devuelve // la llamada a la función nativa de JNI. ndkText = (TextView) findViewById(R.id.ndkTextView); ndkText.setText( getStringFromJNI() ); } }

Paso 3

Una vez hecho esto, toca ponerse con la parte de NDK.

Paso 3.1

Creamos una carpeta en la raíz del proyecto y la llamamos jni. Aquí dentro irá todo lo relacionado con la parte nativa:

Paso 3.2

Tenemos que crear ahora el fichero makefile. Este fichero contiene los parámetros de compilación del código nativo.

Se va a llamar Android.mk y su contenido es el siguiente:

LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE:= hellondk LOCAL_SRC_FILES:= hellondk.c include $(BUILD_SHARED_LIBRARY)

Paso 3.3

Haciendo uso de JAVAH tenemos que crear el fichero que va a hacer las funciones de header. En el link anterior tenéis toda la información necesaria. Generaremos un fichero con extensión .h, el cual no vamos a modificar una vez que esté creado.

Desde la terminal, tenemos que navegar al directorio donde tenemos la raíz del proyecto. En mi caso:

cd /home/mario/workspace/HelloNDK/

A continuación, tenemos que llamar a JAVAH. Es diferente en Windows y Linux. Si no me equivoco, en Mac es como en Linux. La diferencia es que en Windows se pone un ';' entre directorios y en Linux un ':'.

  • Windows:

javah -jni -classpath <RUTA-A-TU-SDK>/platforms/android-19/android.jar;bin/classes/ -d jni/ com.geekytheory.hellondk.MainActivity

  • Linux:

javah -jni -classpath <RUTA-A-TU-SDK>/platforms/android-19/android.jar:bin/classes/ -d jni/ com.geekytheory.hellondk.MainActivity

En mi caso particular, puesto que tengo el SDK en /home/mario/.android-sdk y estoy usando Linux, tengo que introducir lo siguiente:

javah -jni -classpath /home/mario/.android-sdk/platforms/android-19/android.jar:bin/classes/ -d jni/ com.geekytheory.hellondk.MainActivity

Si todo ha ido bien, se habrá creado un fichero llamado com_geekytheory_hellondk_MainActivity.h dentro de la carpeta jni, como vemos en la siguiente imagen:

Esta es la cabecera que contiene la declaración de las funciones nativas que vamos a utilizar. Por ahora únicamente getStringFromJNI().

Ahora tenemos que escribir el fichero en C que contiene el código que ejecuta esta función. Va a ser muy simple, ya que únicamente hace un return de un texto.

Paso 3.4

Vamos a copiar el archivo header que acabamos de generar y pegarlo en la misma carpeta. Además, le vamos a cambiar el nombre a hellondk.c (como hemos puesto en el makefile, paso 3.2). Una vez hecho esto, deberemos tener el mismo contenido en un archivo y en otro. Pues bien, vamos a abrir hellondk.c y lo vamos a modificar para que quede así:

#include <jni.h> #include <com_geekytheory_hellondk_MainActivity.h> jstring JNICALL Java_com_geekytheory_hellondk_MainActivity_getStringFromJNI( JNIEnv *env, jobject obj) { return (*env)->NewStringUTF(env, "Hello from NDK! Geeky Theory rules!"); }

No me estoy parando a explicar esto porque está visto en los tutoriales anteriores, pero si tenéis alguna duda, ya sabéis, a los comentarios.

Paso 3.5

El último paso sería compilar el código nativo con ndk-build para poder ejecutarlo en la aplicación. Para ello, tenemos que añadir el programa ndk-build a nuestro PATH. En Windows es con las variables de entorno. En Linux podemos hacer lo siguiente:

export PATH=$PATH:<RUTA-A-TU-CARPETA-NDK>

Por ejemplo, en mi caso sería:

export PATH=$PATH:/home/mario/.android-ndk

Ahora navegamos de nuevo a la raíz de nuestro proyecto y ejecutamos:

ndk-build

Obteniendo el siguiente resultado en consola:

mario@linux ~/workspace/HelloNDK $ ndk-build Android NDK: WARNING: APP_PLATFORM android-19 is larger than android:minSdkVersion 14 in ./AndroidManifest.xml [armeabi] Compile thumb  : hellondk <= hellondk.c [armeabi] SharedLibrary  : libhellondk.so [armeabi] Install        : libhellondk.so => libs/armeabi/libhellondk.so No os preocupéis por el Warning. No afecta en nada a nuestro proyecto. ¡Atención! Cada vez que cambiemos el código nativo tendremos que compilar con ndk-build. En el siguiente tutorial os explicaré cómo automatizar la tarea de compilar cada vez que haya una modificación.

Paso 4

Finalmente ejecutamos la aplicación. El terminal de Genymotion (o dispositivo donde lo ejecutéis) mostrará algo parecido a esto:

Vídeo

https://www.youtube.com/watch?v=TnAgy6BO34g Espero que os haya servido el tutorial. Nos vemos en los próximos. ¡Un abrazo!