नेटिव-ऐक्टिविटी सैंपल,
फ़ोल्डर में NDK सैंपल रूट
native-activity
. यह पूरी तरह से मूल निवासी का बहुत आसान उदाहरण है
ऐप्लिकेशन है, जिसमें कोई Java सोर्स कोड नहीं है. किसी Java सोर्स के न होने पर,
Java कंपाइलर अब भी वर्चुअल मशीन को चलाने के लिए एक एक्ज़ीक्यूटेबल स्टब बनाता है.
स्टब, .so
में मौजूद असल प्रोग्राम के लिए रैपर के तौर पर काम करता है
फ़ाइल से लिए जाते हैं.
ऐप्लिकेशन अपने-आप पूरी स्क्रीन पर एक रंग दिखाता है और फिर पता चलता है कि वह किसी मूवमेंट के हिसाब से रंग को बदल देता है.
AndroidManifest.xml
सिर्फ़ नेटिव कोड वाले ऐप्लिकेशन को 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"
आखिर में, मेनिफ़ेस्ट android:value
को शेयर की गई लाइब्रेरी का नाम बताता है
बनाया गया, जिसमें शुरुआती lib
और .so
एक्सटेंशन को घटा दिया गया है. यह वैल्यू इसके बराबर होनी चाहिए
Android.mk
में LOCAL_MODULE
का नाम.
<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
में, एनडीके के लिए Android के स्टैंडर्ड एपीआई शामिल हैं. इसके बारे में ज़्यादा जानकारी पाने के लिए, ऐसे एपीआई जो Android और NDK पर काम करते हैं, Android NDK Native देखें APIs.EGL
, ग्राफ़िक एपीआई के प्लैटफ़ॉर्म के हिसाब से बने हिस्से से मेल खाता है.GLESv1_CM
, Android के लिए OpenGL का वर्शन है, जो OpenGL ES के मुताबिक है. यह लाइब्रेरी यह 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.
मुख्य.सी
इस फ़ाइल में पूरा प्रोग्राम मौजूद है.
नीचे दिए गए उदाहरणों में, शेयर की गई और स्टैटिक, दोनों लाइब्रेरी शामिल हैं,
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
लाइब्रेरी में इस फ़ंक्शन को कॉल किया जाता है,
उसे एक पहले से तय स्टेट स्ट्रक्चर को पास करना. यह ऐसे रैपर की तरह भी काम करता है जो
NativeActivity
कॉलबैक को मैनेज करना आसान बनाता है.
void android_main(struct android_app* state) {
इसके बाद, प्रोग्राम उन इवेंट को मैनेज करता है जो ग्लू लाइब्रेरी में मौजूद होते हैं. इवेंट हैंडलर स्टेट स्ट्रक्चर को फ़ॉलो करता है.
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;
ऐप्लिकेशन, सेंसर का इस्तेमाल करके, सेंसर पर निगरानी रखने की तैयारी करता है.
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
, जो यह जांच करता है कि क्या वे मेल खाते हैं
android_main
में तय किया गया कोई भी onAppCmd
इवेंट. जब
मैच होता है, तो मैसेज को प्रोसेस करने के लिए हैंडलर को भेजा जाता है.
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); } }