Scrivere App per Android Studio con Codice Java e C/C++ .

Lo sviluppo di applicazioni per il sistema operativo Android ha acquistato negli ultimi anni grande importanza a seguito della diffusione di tablet, telefoni e dispositivi che adottano questo sistema operativo creato da Google.
Tra i principali fattori che a mio avviso hanno favorito questa forte espansione ci sono sicuramente:

  • Il costo, non ci sono licenze da pagare.
  • La disponibilità dei codici sorgenti e la possibilità di analizzare, studiare e/o modificare ogni singola riga di codice su cui è costruito il sistema operativo.
  • Il mantenimento continuo del sistema operativo viene costantemente sviluppato da centinaia di programmatori e aziende che lo tengono aggiornato e lo arricchiscono di funzionalità.
  • La sicurezza elevata del sistema; Android è molto attento alle policy sulla sicurezza e all’accessibilità delle risorse.
  • L’affidabilità del sistema il quale è molto ben pensato e strutturato e permette sempre il recovery, il ripristino, il riavvio etc…
  • La disponibilità gratuita dei tools per lo sviluppo di applicazioni e programmi.

Per sviluppare un’applicazione Android infatti servono poche cose:

  • Un telefono o un tablet su cui far girare l’applicazione ( si può usare anche l’emulatore ma vedere la propria applicazione girare su un device fisico è sempre consigliato).
  • Scaricare ed installare sul proprio PC ( Windows/Mac o Linux ) il sistema di sviluppo costituito da
    Android Studio, e delle relative SDK e NDK a corredo.

Tutto il materiale e la documentazione, bastano pochi click e qualche minuto di pazienza per avere tutte le risorse necessarie allo sviluppo installate e funzionati sul proprio sistema.

Linguaggio di programmazione.

Il linguaggio con il quale si sviluppano le applicazioni ( le famose app) è il Java.
Si tratta come molti sanno di un linguaggio multi piattaforma, orientato agli oggetti, per certi versi simile come sintassi allo C/C++ ma con molte particolarità e caratteristiche tutte sue.

Ad esempio, al fine di impedire l’introduzione di determinati bug durante la programmazione, in Java non si può operare con l’aritmetica dei puntatori o avere puntatori a funzioni.
La differente gestione l’ereditarietà multipla delle classi o la completa rimozione dell’istruzione goto sono solamente alcuni dei molteplici esempi delle differenti implementazioni tra i due linguaggi.

In ogni caso, senza scendere troppo nella disamina del linguaggio, va detto che esiste però la possibilità di creare applicazioni che utilizzano entrambi i linguaggi Java e C/C++.
I motivi per cui si dovrebbe poter introdurre parti di programma in C/C++ in un’applicazione Java sono ovviamente molteplici:

  • Le performance, il linguaggio C/C++ produce codice che molto più performante e funzionate del Java che rimane sempre un linguaggio da interpretare e non da eseguire.
  • Il riutilizzo e l’accesso a librerie e parti di codice Nativo o precedente mente scritto in C/C++.
    Il core di Android è scritto in linguaggio C/C++ e tantissime delle sue funzionalità più spinte e performanti sono accessibili solamente tramite l’NDK ovvero tramite l’interfaccia Nativa delle funzioni e delle librerie scritte in C/C++.
  • La possiblità di dare a vecchi programmatori che hanno sempre scritto codice in C/C++, un modo di sfogare la loro creatività e inventiva nel linguaggio con il quale si sentivano a proprio agio ( nota leggermente autobiografica!).

Ma come si scrive un’app a codice misto?

Esiste un’interfaccia che permette di chiamare funzioni e scambiare dati tra codice Java e codice Nativo chiamata JNI (Java Native Interface).
In poche parole il codice scritto in C/C++ viene compilato come libreria (.SO) ed i metodi chiamati tramite un’interfaccia appositamente costruita.

Facciamo un esempio operativo.
Dopo aver installato il sistema di sviluppo.
Create un nuovo progetto ed includete la possibilità di introdurre codice C/C++ spuntando la relativa opzione.

Riporto qui di seguito i passaggi per giungere ad un’applicazione funzionate.

Una volta terminato il wizard per creare la nuova applicazione, Android Studio apre il progetto nel quale immediatamente possiamo scorgere sulla parte sinistra dedicata ai file sia la parte Java che quella C/C++.

 

Aprendo il file CMaleLists.txt possiamo vedere che il file nativa-lib.cpp verrà compilato come libreria .SO. Questo è il file nel quale dovremo andare ad aggiungere eventuali altri files c/c++ utili per il nostro progetto.

Per accedere dalla parte Java alle funzioni C/C++ si utilizzano delle funzioni che vengono indicate come Native.
Se controllate il File MainActivity.Java vedrete che alla fine viene dichiarata la funzione:

public native String stringFromJNI();

Questo metodo chiama la funzione Nativa scritta dentro il file native-lib.cpp che nel mio caso si chiamata:

Java_com_example_giorgio_myapplication_MainActivity_stringFromJNI(JNIEnv* env, jobject);

Perchè questa differenza nei nomi?
E’ una prticolarità del JNI il quale ha una serie di convenzioni e regole che vanno rispettate.

Aggiungere una nuova funzione.

Per aggiungere una nuova funzione si fa in questo modo:

  • Si scrive la funzione in Java con i parametri ed i valori di ritorno richiesti.
  • Si fa generare automaticamente ad Android Studio il corretto nome da inserire nella parte C/C++.

Facciamo un esempio:

Nel file MainActovity.Java scriviamo la nostra nuova funzione e caratterizziamola con la parola “native”;

Se attenderete qualche minuto vedrete comparire una piccola lampadina rossa sulla sinistra:

Se ci cliccate sopra potete selezionare la voce: Create Function Java….

Appena fatto vedrete che Android Studio inserisce per voi la funzione con il nome ed i parametri richiesti nel file C/C++.
Al sui interno potete scrivere tutto il codice C che volete.

Ma dove va a finire il codice scritto in C/C++?

La parte Nativa viene compilata all’interno di un libreria SO.
Se selezionata la voce presente nel menù Build chiamata “Analize APK..” potete vedere com’è costituita l’APK che avete appena generato.
Noterete che all’interno di essa viene pacchettizzata anche la libreria SO creata e già pronta per essere eseguita su tutte le architetture disponibili.

La libreria compilata può essere anche estratta e utilizzata per essere direttamente inserita in altre app senza la necessità di “ri-includere” anche le sorgenti della libreria.

Se andate nella cartella che contiene il vostro progetto e navigate all’interno della cartella:

path/app/build/intermediates/cmake/release/obj

potete vedere la vostra libreria compilata ed eventualmente prelevarla per distribuirla a terzi già compilata.

 

Creare un file Jar che contiene l’interfaccia Java.

Solitamente quando si vuole creare una libreria che contiene codice nativo da distribuire a terzi, non si scrive le funzioni nativa all’interno dell’applicazione come abbiamo sin qui fatto.
Solitamente si crea una libreria Jar che contiene tutto il codice necessario per accedere alle funzioni native; in tal modo per includere in una nuova app le funzionalità implementate sarà possibile distribuire due file: il file .SO della libreria compilata ed il file .Jar che contiene la parte java d’interfaccia.
In questo modo con un paio di Drag&Drop sarà possibile includere le funzionalità implementate dalla libreria in una nuova app senza dover distribuire il codice sorgente.

Per prima cosa creiamo un nuovo package.

Impostiamo un nome per il nuovo package

Creiamo la classe Java nella quale andremo a scrivere il codice dell’interfaccia alla nostra libreria Nativa,

Fate attenzione chiamare il file java in modo diverso dal nome del package.

Orta all’interno del file Java creato andiamo ad inserire il Load della libreria e a riscrivere le classi native come avevamo fatto precedentemente.
Dobbiamo riscriverle di nuovo perché i nomi nativi cambieranno in quanto ora stiamo lavorando in in package diverso.

Ora importiamo il nuovo package creato nel file principale della nostra applicazione MyActicity.Java

import natLibInterface.natLibInt;

creiamo un oggetto della libreria

natLibInt natLib = new natLibInt();

con il quale accederemo al metodo stringFronJNI() tramite in questo modo:

natLib.stringFromJNI()

Il gioco è fatto.

Ovviamente possiamo includere dentro al nuovo package tutte le classi e gli oggetti java che ci servono.

Libreria Jar please!

A questo punto non ci rimane che generare una libreria Jar che contenga tutta la nostra classe Java d’interfaccia.

Per fare questo apriamo la linea di comando ( il terminal ) :

e andiamo dentro la cartella

/app/build/intermediates/classes/debug

e digitiamo il comando:

jar -cf0 natInterface.jar natLibInterface/

 

La libreria Jar creata potrà quindi essere distribuita insieme ai file SO.

 

Per vedere come utilizzare questi due oggetti in una nuova App, ci diamo appuntamento ad un nuovo post.

 

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione /  Modifica )

Google photo

Stai commentando usando il tuo account Google. Chiudi sessione /  Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...

This site uses Akismet to reduce spam. Learn how your comment data is processed.