L'esempio di attività nativa si trova nel
Root di esempio di NDK, nella cartella
native-activity
. È un esempio molto semplice di un'architettura
senza codice sorgente Java. In assenza di origini Java,
Il compilatore Java crea comunque uno stub eseguibile per l'esecuzione della macchina virtuale.
Lo stub funge da wrapper per il programma nativo effettivo, che si trova nell'elemento .so
.
L'app stessa visualizza semplicemente un colore sull'intero schermo cambia parzialmente il colore in risposta ai movimenti rilevati.
AndroidManifest.xml
Per un'app con solo codice nativo non deve specificare un livello API Android inferiore a 9, che ha introdotto
la classe framework NativeActivity
.
<uses-sdk android:minSdkVersion="9" />
La riga seguente dichiara android:hasCode
come false
, poiché questa app ha
codice nativo, non Java.
<application android:label="@string/app_name"
android:hasCode="false">
La riga successiva dichiara la classe NativeActivity
.
<activity android:name="android.app.NativeActivity"
Infine, il file manifest specifica android:value
come nome della libreria condivisa da utilizzare
creata, meno la lib
iniziale e l'estensione .so
. Questo valore deve essere uguale a
il nome di LOCAL_MODULE
in Android.mk
.
<meta-data android:name="android.app.lib_name" android:value="native-activity" />
Android.MK
Per iniziare, questo file indica il nome della libreria condivisa da generare.
LOCAL_MODULE := native-activity
Successivamente, dichiara il nome del file di codice sorgente nativo.
LOCAL_SRC_FILES := main.c
Quindi, elenca le librerie esterne per il sistema di compilazione da utilizzare nella creazione del file binario. La
L'opzione -l
(link contro) precede ogni nome della raccolta.
log
è una libreria di logging.android
comprende le API di supporto Android standard per NDK. Per ulteriori informazioni sulle API supportate da Android e NDK; consulta l'articolo relativo alla tecnologia Android NDK Native per le API.EGL
corrisponde alla parte dell'API grafica specifica per la piattaforma.GLESv1_CM
corrisponde a OpenGL ES, la versione di OpenGL per Android. Questa libreria dipende da EGL.
Per ogni libreria:
- Il nome effettivo del file inizia con
lib
e termina con.so
. Ad esempio, il nome effettivo del file La raccoltalog
èliblog.so
. - La libreria si trova nella seguente directory, NDK root:
<ndk>/platforms/android-<sdk_version>/arch-<abi>/usr/lib/
.
LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv1_CM
Nella riga successiva viene specificato il nome della libreria statica, android_native_app_glue
, di cui
utilizzata per gestire NativeActivity
eventi del ciclo di vita e input tocco.
LOCAL_STATIC_LIBRARIES := android_native_app_glue
L'ultima riga indica al sistema di compilazione di creare questa libreria statica.
Lo script ndk-build
inserisce la libreria creata
(libandroid_native_app_glue.a
) nella directory obj
generati durante il processo di compilazione. Per ulteriori informazioni sull'android_native_app_glue
consulta la relativa intestazione android_native_app_glue.h
e il .c
file di origine corrispondente.
$(call import-module,android/native_app_glue)
Per ulteriori informazioni sul file Android.mk
, vedi
Android.mk.
main.c
Questo file contiene essenzialmente l'intero programma.
I seguenti elementi corrispondono alle librerie, sia condivise che statiche,
enumerato in Android.mk
.
#include <EGL/egl.h> #include <GLES/gl.h> #include <android/sensor.h> #include <android/log.h> #include <android_native_app_glue>
La libreria android_native_app_glue
chiama la seguente funzione:
passando una struttura di stato predefinita. Funge anche da wrapper
semplifica la gestione dei callback NativeActivity
.
void android_main(struct android_app* state) {
Il programma quindi gestisce gli eventi in coda dalla libreria di glue. L'evento segue la struttura dello stato.
struct engine engine; // Suppress link-time optimization that removes unreferenced code // to make sure glue isn't stripped. app_dummy(); memset(&engine, 0, sizeof(engine)); state->userData = &engine; state->onAppCmd = engine_handle_cmd; state->onInputEvent = engine_handle_input; engine.app = state;
L'applicazione si prepara ad iniziare a monitorare i sensori, utilizzando
API in sensor.h
.
engine.sensorManager = ASensorManager_getInstance(); engine.accelerometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager, ASENSOR_TYPE_ACCELEROMETER); engine.sensorEventQueue = ASensorManager_createEventQueue(engine.sensorManager, state->looper, LOOPER_ID_USER, NULL, NULL);
Poi ha inizio un ciclo, in cui l'applicazione esegue il polling del sistema
i messaggi (eventi dei sensori). Invia messaggi a
android_native_app_glue
, che controlla se corrispondono
qualsiasi evento onAppCmd
definito in android_main
. Quando
una corrispondenza, il messaggio viene inviato al gestore per l'esecuzione.
while (1) { // Read all pending events. int ident; int events; struct android_poll_source* source; // If not animating, we will block forever waiting for events. // If animating, we loop until all events are read, then continue // to draw the next frame of animation. while ((ident=ALooper_pollAll(engine.animating ? 0 : -1, NULL, &events, (void**)&source)) >= 0) { // Process this event. if (source != NULL) { source->process(state, source); } // If a sensor has data, process it now. if (ident == LOOPER_ID_USER) { if (engine.accelerometerSensor != NULL) { ASensorEvent event; while (ASensorEventQueue_getEvents(engine.sensorEventQueue, &event, 1) > 0) { LOGI("accelerometer: x=%f y=%f z=%f", event.acceleration.x, event.acceleration.y, event.acceleration.z); } } } // Check if we are exiting. if (state->destroyRequested != 0) { engine_term_display(&engine); return; } }
Quando la coda è vuota e il programma esce dal loop di polling, la il programma chiama OpenGL per disegnare lo schermo.
if (engine.animating) { // Done with events; draw next animation frame. engine.state.angle += .01f; if (engine.state.angle > 1) { engine.state.angle = 0; } // Drawing is throttled to the screen update rate, so there // is no need to do timing here. engine_draw_frame(&engine); } }