ตัวอย่างกิจกรรมดั้งเดิมอยู่ภายใต้
รูทตัวอย่าง NDK ในโฟลเดอร์
native-activity นี่เป็นตัวอย่างง่ายๆ ของ
โดยไม่มีซอร์สโค้ดของ Java ในกรณีที่ไม่มีซอร์ส Java ค่า
คอมไพเลอร์ Java ยังคงสร้างสตับที่สั่งการได้เพื่อให้เครื่องเสมือนเรียกใช้
ต้นขั้วทำหน้าที่เป็น Wrapper ของโปรแกรมเนทีฟจริง ซึ่งอยู่ใน.so
ตัวแอปเองจะแสดงผลสีบนทั้งหน้าจอ แล้วเปลี่ยนสีเป็นบางส่วนตามการเคลื่อนไหวที่ตรวจจับได้
AndroidManifest.xml
แอปที่มีเฉพาะโค้ดแบบเนทีฟต้องไม่ระบุระดับ API ของ Android ที่ต่ำกว่า 9
คลาสเฟรมเวิร์กของ NativeActivity
<uses-sdk android:minSdkVersion="9" />
บรรทัดต่อไปนี้ประกาศว่า android:hasCode เป็น false เนื่องจากแอปนี้มีเพียง
โค้ดแบบเนทีฟ ไม่ใช่ Java
<application android:label="@string/app_name"
android:hasCode="false">บรรทัดถัดไปคือการประกาศคลาส NativeActivity
<activity android:name="android.app.NativeActivity"สุดท้าย ไฟล์ Manifest ระบุว่า android:value เป็นชื่อของไลบรารีที่ใช้ร่วมกันที่จะ
ที่สร้างขึ้น ลบ lib เริ่มต้นและส่วนขยาย .so ค่านี้ต้องเหมือนกับ
ชื่อของ LOCAL_MODULE ใน Android.mk
<meta-data android:name="android.app.lib_name" android:value="native-activity" />
Android mk
ไฟล์นี้เริ่มต้นด้วยการระบุชื่อไลบรารีที่ใช้ร่วมกันที่จะสร้าง
LOCAL_MODULE := native-activity
ถัดไป จะประกาศชื่อไฟล์ซอร์สโค้ดดั้งเดิม
LOCAL_SRC_FILES := main.c
ถัดไป จะแสดงรายการไลบรารีภายนอกสำหรับระบบบิลด์ที่จะใช้ในการสร้างไบนารี
มี -l ตัวเลือก (ลิงก์ต่อ) อยู่หน้าชื่อไลบรารีแต่ละรายการ
logเป็นไลบรารีการบันทึกandroidครอบคลุม API การสนับสนุนมาตรฐานของ Android สำหรับ NDK สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ API ที่ Android และ NDK รองรับ โปรดดู Android NDK Native APIEGLสอดคล้องกับส่วนเฉพาะแพลตฟอร์มของ API กราฟิกGLESv1_CMสอดคล้องกับ OpenGL ES ซึ่งเป็นเวอร์ชันของ OpenGL สำหรับ Android ไลบรารีนี้ ขึ้นอยู่กับ EGL
สำหรับคลังแต่ละรายการ ให้ทำดังนี้
- ชื่อไฟล์จริงจะขึ้นต้นด้วย
libและลงท้ายด้วย ส่วนขยาย.soเช่น ชื่อไฟล์จริงของ ไลบรารีของlogคือliblog.so - ไลบรารีอยู่ในไดเรกทอรีต่อไปนี้ คือราก NDK
<ndk>/platforms/android-<sdk_version>/arch-<abi>/usr/lib/
LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv1_CM
บรรทัดถัดไประบุชื่อไลบรารีแบบคงที่ android_native_app_glue ซึ่ง
แอปพลิเคชันใช้เพื่อจัดการเหตุการณ์ในวงจรของ NativeActivity และการป้อนข้อมูลด้วยการสัมผัส
LOCAL_STATIC_LIBRARIES := android_native_app_glue
บรรทัดสุดท้ายจะบอกระบบบิลด์เพื่อสร้างไลบรารีแบบคงที่นี้
สคริปต์ ndk-build จะวางไลบรารีที่สร้าง
(libandroid_native_app_glue.a) ลงในไดเรกทอรี obj
ที่สร้างขึ้นระหว่างขั้นตอนบิลด์ ดูข้อมูลเพิ่มเติมเกี่ยวกับandroid_native_app_glue
โปรดดูส่วนหัว android_native_app_glue.h และไฟล์ต้นฉบับ .c ที่เกี่ยวข้อง
$(call import-module,android/native_app_glue)
ดูข้อมูลเพิ่มเติมเกี่ยวกับไฟล์ Android.mk ได้ที่
Android.mk
Main.c
โดยพื้นฐานแล้วไฟล์นี้จะมีทั้ง Progam
รายการต่อไปนี้รวมถึงที่สอดคล้องกับไลบรารี ทั้งที่แชร์และแบบคงที่
แจกแจงในAndroid.mk
#include <EGL/egl.h> #include <GLES/gl.h> #include <android/sensor.h> #include <android/log.h> #include <android_native_app_glue>
ไลบรารี android_native_app_glue เรียกฟังก์ชันต่อไปนี้
ผ่านโครงสร้างสถานะที่กำหนดไว้ล่วงหน้า และยังทำหน้าที่เป็น Wrapper ที่
จัดการ Callback ของ NativeActivity ได้ง่ายขึ้น
void android_main(struct android_app* state) {
ถัดไป โปรแกรมจะจัดการกับเหตุการณ์ที่จัดคิวโดย Glue Library กิจกรรม จะใช้โครงสร้างสถานะ
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;
แอปพลิเคชันกำลังเตรียมพร้อมเพื่อเริ่มตรวจสอบเซ็นเซอร์ โดยใช้
API ใน 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);
ถัดไป ลูปจะเริ่มขึ้น ซึ่งแอปพลิเคชันจะสำรวจระบบสำหรับ
ข้อความ (เหตุการณ์เซ็นเซอร์) ส่งข้อความไปยัง
android_native_app_glue ซึ่งจะตรวจสอบว่าตรงกันหรือไม่
เหตุการณ์ onAppCmd ใดๆ ที่กำหนดไว้ใน android_main เมื่อ
ตรงกัน ข้อความจะส่งไปยังตัวจัดการเพื่อการดำเนินการ
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; } }
เมื่อคิวว่างเปล่า และโปรแกรมออกจากลูปการสำรวจ โปรแกรมจะเรียก OpenGL ให้วาดหน้าจอ
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); } }