Das Beispiel für native Aktivitäten befindet sich unter der
NDK-Beispielstamm, im Ordner
native-activity
Das ist ein sehr einfaches Beispiel für eine
ohne Java-Quellcode. Falls keine Java-Quelle vorhanden ist,
Der Java-Compiler erstellt weiterhin einen ausführbaren Stub, den die virtuelle Maschine ausführen kann.
Der Stub dient als Wrapper für das eigentliche native Programm, das sich im .so
befindet.
-Datei.
Die App selbst rendert eine Farbe auf dem gesamten Bildschirm und und ändert dann die Farbe teilweise als Reaktion auf erkannte Bewegungen.
AndroidManifest.xml
Eine App mit ausschließlich nativem Code darf kein Android-API-Level unter 9 angeben.
Framework-Klasse NativeActivity
<uses-sdk android:minSdkVersion="9" />
In der folgenden Zeile wird android:hasCode
als false
deklariert, da diese App nur
nativer Code – ohne Java.
<application android:label="@string/app_name"
android:hasCode="false">
In der nächsten Zeile wird die Klasse NativeActivity
deklariert.
<activity android:name="android.app.NativeActivity"
Schließlich gibt das Manifest android:value
als Namen der gemeinsam genutzten Bibliothek an, die
erstellt, abzüglich der anfänglichen lib
- und der .so
-Erweiterung. Dieser Wert muss mit
den Namen von LOCAL_MODULE
auf Android.mk
.
<meta-data android:name="android.app.lib_name" android:value="native-activity" />
Android.Mk
Diese Datei enthält zuerst den Namen der gemeinsam genutzten Bibliothek, die generiert werden soll.
LOCAL_MODULE := native-activity
Als Nächstes wird der Name der nativen Quellcodedatei deklariert.
LOCAL_SRC_FILES := main.c
Als Nächstes werden die externen Bibliotheken aufgelistet, die das Build-System zum Erstellen der Binärdatei verwenden kann. Die
-l
(verlinken) vor jedem Bibliotheksnamen.
log
ist eine Logging-Bibliothek.android
umfasst die standardmäßigen Android-Support-APIs für NDK. Weitere Informationen zu Informationen zu den von Android und vom NDK unterstützten APIs finden Sie unter Android NDK Native APIsEGL
entspricht dem plattformspezifischen Teil der Grafik-API.GLESv1_CM
entspricht OpenGL ES, der Version von OpenGL für Android. Diese Bibliothek hängt von EGL ab.
Für jede Bibliothek:
- Der tatsächliche Dateiname beginnt mit
lib
und endet mit.so
. Zum Beispiel der tatsächliche Dateiname für die Dielog
-Bibliothek istliblog.so
. - Die Bibliothek befindet sich im folgenden Verzeichnis, dem NDK-Stammverzeichnis:
<ndk>/platforms/android-<sdk_version>/arch-<abi>/usr/lib/
LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv1_CM
Die nächste Zeile enthält den Namen der statischen Bibliothek, android_native_app_glue
, der vom
App zur Verwaltung von NativeActivity
-Lebenszyklus-Ereignissen und Eingabe per Berührung
LOCAL_STATIC_LIBRARIES := android_native_app_glue
Mit der letzten Zeile wird das Build-System angewiesen, diese statische Bibliothek zu erstellen.
Das Skript ndk-build
platziert die erstellte Bibliothek.
(libandroid_native_app_glue.a
) in das Verzeichnis obj
die während des Build-Prozesses generiert werden. Weitere Informationen zu android_native_app_glue
finden Sie im android_native_app_glue.h
-Header und der entsprechenden .c
Quelldatei.
$(call import-module,android/native_app_glue)
Weitere Informationen zur Datei Android.mk
finden Sie unter
Android.mk
haupt.c
Diese Datei enthält im Wesentlichen das gesamte Programm.
Die folgendenIncludes entsprechen den Bibliotheken, sowohl gemeinsam genutzten als auch statischen,
in Android.mk
aufgezählt.
#include <EGL/egl.h> #include <GLES/gl.h> #include <android/sensor.h> #include <android/log.h> #include <android_native_app_glue>
Die Bibliothek android_native_app_glue
ruft die folgende Funktion auf:
und übergeben ihm eine vordefinierte
Statusstruktur. Er dient auch als Wrapper,
vereinfacht die Verarbeitung von NativeActivity
-Callbacks.
void android_main(struct android_app* state) {
Als Nächstes verarbeitet das Programm Ereignisse, die von der Glue Library in die Warteschlange gestellt werden. Das Ereignis folgt der Zustandsstruktur.
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;
Die Anwendung bereitet sich auf die Überwachung der Sensoren vor. Dabei werden die
APIs 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);
Als Nächstes beginnt eine Schleife, in der die Anwendung das System nach
Meldungen (Sensorereignisse). Er sendet Nachrichten an
android_native_app_glue
, die prüft, ob sie übereinstimmen
alle onAppCmd
-Ereignisse, die in android_main
definiert sind. Wenn ein
Übereinstimmung vorliegt, wird die Nachricht zur Ausführung an den Handler gesendet.
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; } }
Sobald die Warteschlange leer ist und das Programm die Abfrageschleife beendet, wird das Ereignis das OpenGL-Programm aufruft, um den Bildschirm zu zeichnen.
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); } }