ويمكن العثور على عيّنة النشاط الأصلي ضمن
جذر نماذج 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
. يجب أن تكون هذه القيمة مماثلة
اسم 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
واجهات برمجة التطبيقات العادية لدعم Android الخاصة بحِزمة NDK. لمزيد من المعلومات عن واجهات برمجة التطبيقات التي يدعمها Android وNDK، راجع Android NDK Native API. - تتوافق
EGL
مع الجزء الخاص بالنظام الأساسي من واجهة برمجة تطبيقات الرسومات. - يتوافق
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
ماين.ج
يحتوي هذا الملف بشكل أساسي على البرنامج بالكامل.
يتضمن ما يلي تتجاوب مع المكتبات، المشتركة والثابتة،
تم تعدادها في 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
: خدمة تحقّق من المطابقة
أي أحداث 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); } }