لتطوير التطبيقات لنظام التشغيل Android، توفر Google حزمتي تطوير: SDK وNDK. هناك العديد من المقالات والكتب وكذلك الإرشادات الجيدة من Google حول SDK. ولكن حتى جوجل نفسها لا تكتب سوى القليل عن NDK. ومن بين الكتب الجديرة بالاهتمام، أود أن أشير إلى كتاب واحد فقط، وهو Cinar O. - Pro Android C++ with the NDK – 2012.
تستهدف هذه المقالة أولئك الذين ليسوا على دراية بعد (أو على دراية قليلة) بنظام Android NDK ويرغبون في تعزيز معرفتهم. سأهتم بـ JNI، لأنه يبدو لي أننا بحاجة إلى البدء بهذه الواجهة. أيضًا، في النهاية، دعونا نلقي نظرة على مثال صغير به وظيفتين لكتابة ملف وقراءته.
التوافق الثنائي أو التوافق الثنائي هو نوع من توافق البرامج الذي يسمح للبرنامج بالعمل في بيئات مختلفة دون تغيير ملفاته القابلة للتنفيذ.
جدول JNI، منظم مثل جدول الوظائف الافتراضية في C++. يمكن أن يعمل VM مع العديد من هذه الجداول. على سبيل المثال، سيكون أحدهما لتصحيح الأخطاء، والثاني للاستخدام. المؤشر إلى واجهة JNI صالح فقط في مؤشر الترابط الحالي. هذا يعني أن المؤشر لا يمكنه الانتقال من مؤشر ترابط إلى آخر. ولكن يمكن استدعاء الأساليب الأصلية من مواضيع مختلفة. مثال:
Jdouble Java_pkg_Cls_f__ILjava_lang_String_2 (JNIEnv *env, jobject obj, jint i, jstring s) ( const char *str = (*env)->GetStringUTFChars(env, s, 0); (*env)->ReleaseStringUTFChars(env, s, str ); عودة 10 )
جي كلاس كلاز؛ clazz = (*env)->FindClass(env, "java/lang/String"); // الكود الخاص بك (*env)->DeleteLocalRef(env, clazz);
تظل المراجع العالمية حتى يتم إصدارها بشكل صريح. لتسجيل مرجع عمومي، قم باستدعاء الأسلوب NewGlobalRef. إذا لم تعد هناك حاجة إلى المرجع العام، فيمكن حذفه باستخدام طريقة RemoveGlobalRef:
Jclass localClazz; jclass globalClazz; localClazz = (*env)->FindClass(env, "java/lang/String"); globalClazz = (*env)->NewGlobalRef(env, localClazz); // الكود الخاص بك (*env)->DeleteLocalRef(env, localClazz);
Jthrowable ExceptionOccurred(JNIEnv *env);
على سبيل المثال، بعض وظائف الوصول إلى صفيف JNI لا تُرجع أخطاء، ولكنها قد تؤدي إلى استثناءات ArrayIndexOutOfBoundsException أو ArrayStoreException.
نوع جافا | النوع الأصلي | وصف |
---|---|---|
منطقية | jboolean | غير موقعة 8 بت |
بايت | jbyte | وقعت 8 بت |
شار | jchar | غير موقعة 16 بت |
قصير | com.jshort | وقعت 16 بت |
كثافة العمليات | جينت | وقعت 32 بت |
طويل | jlong | وقعت 64 بت |
يطفو | jfloat | 32 بت |
مزدوج | jdouble | 64 بت |
فارغ | فارغ | لا يوجد |
لإنشاء مشروع أصلي، تحتاج إلى إنشاء مشروع Android عادي واتباع الخطوات التالية:
مثال على الحد الأدنى من التكوين:
LOCAL_PATH:= $(اتصل بـ my-dir) يتضمن $(CLEAR_VARS) LOCAL_MODULE:= NDKBegining LOCAL_SRC_FILES:= ndkBegining.c include $(BUILD_SHARED_LIBRARY)
دعونا ننظر في الأمر بالتفصيل:
افتراضيًا، يتم تثبيت الدعم لإصدار 64 بت من الأدوات المساعدة، ولكن يمكنك إجباره على إنشاء 32 بت فقط عن طريق تعيين العلامة NDK_HOST_32BIT=1. لا تزال Google توصي باستخدام أدوات مساعدة 64 بت لتحسين أداء البرامج الكبيرة.
الآن أصبح كل شيء أسهل بكثير مع هذا. اتبع هذا الرابط. قم بتنزيل حزمة Eclipse ADT، التي تحتوي بالفعل على كل ما تحتاجه للتجميع.
الآن يمكنك إطلاق. سيحتوي دليل bin/classes على ملفات الرأس الخاصة بك.
بعد ذلك، نقوم بنسخ هذه الملفات إلى دليل jni لمشروعنا الأصلي. اتصل بقائمة سياق المشروع وحدد أدوات Android - إضافة المكتبة الأصلية. سيسمح لنا هذا باستخدام وظائف jni.h. بعد ذلك، يمكنك إنشاء ملف cpp (أحيانًا يقوم Eclipse بإنشائه افتراضيًا) وكتابة نصوص الطرق الموضحة بالفعل في ملف الرأس.
لم أقم بإضافة مثال رمزي إلى المقالة حتى لا أطيله. يمكنك عرض/تنزيل مثال من جيثب.
العلامات:
Android NDK (Native Development Kit) هي مجموعة أدوات شائعة جدًا تُستخدم لتطوير تطبيقات الأجهزة المحمولة. تستخدم العديد من التطبيقات في متجر تطبيقات Android Market مكونات تم تطويرها باستخدام لغات برمجة أخرى غير Java لتحقيق أقصى قدر من الأداء. وبناءً على ذلك، فإن NDK عبارة عن مجموعة أدوات تساعد المطورين على إنشاء مكونات لتطبيقاتهم باستخدام لغات البرمجة المجمعة لأغراض مختلفة، بدءًا من تحقيق الأداء الأمثل وحتى تبسيط التعليمات البرمجية المستخدمة.
نعلم جميعًا أن عملية تطوير تطبيقات Android ترتبط ارتباطًا وثيقًا باستخدام لغة البرمجة Java، وأيضًا أن استخدام لغة البرمجة هذه يبسط حياة المطورين إلى حد كبير لأنه يمكنهم استخدام نموذج Java الأنيق الموجه للكائنات. يتم تحويل التطبيقات أو الخوارزميات المطبقة في Java إلى كود ثانوي خاص يعمل بنفس الطريقة على جميع الأنظمة الأساسية المدعومة. في الوقت نفسه، يتوفر جهاز Java الظاهري أو JVM (Java Virtual Machine)، المسؤول عن تجميع JIT وتنفيذ كود Java الثانوي، لجميع الأنظمة الأساسية الموجودة تقريبًا، بدءًا من الحواسيب المركزية وحتى الهواتف المحمولة.
ومع ذلك، في حالة نظام Android، الذي يُستخدم بشكل أساسي على الهواتف الذكية والأجهزة اللوحية، يعد تحقيق أقصى أداء للتطبيقات على الأجهزة المستخدمة أمرًا أساسيًا. يتم أولاً تحويل كود مصدر Java، كما هو مذكور أعلاه، إلى كود بايت. هذا هو بالضبط الرمز الثانوي الذي يتم تنفيذه مع اختلافات طفيفة على الأنظمة الأساسية التي يتوفر لها جهاز Java الظاهري. في نهاية المطاف، يتم تشغيل التطبيق بأكمله داخل جهاز افتراضي على جهاز يعمل بنظام Android.
عندما يتعلق الأمر بتطوير تطبيقات Android، فإن العامل المذكور أعلاه يعد عيبًا بسيطًا. لكن البرمجة في Java يمكن أن تكون صعبة للغاية بسبب التعقيد المستمر للتعليمات البرمجية وصعوبة فهمها. علاوة على ذلك، يتطلب استخدام الرمز الثانوي متعدد المنصات والجهاز الظاهري موارد حوسبة كبيرة على الجهاز.
هناك عامل مهم آخر يتطلب الاهتمام وهو التعليمات البرمجية متعددة المنصات. إذا كنا بحاجة إلى كتابة برنامج لمنصات أجهزة متعددة، فقد ينتهي بنا الأمر إلى إعادة كتابة جزء كبير من وحدة التحكم وكود العرض لكل منصة، وهو ليس حلاً ذكيًا. ولكن يجب نقل جميع التعليمات البرمجية المتعلقة بوحدة التحكم إلى C وC++، حيث تدعمها جميع منصات الأجهزة المحمولة تقريبًا؛ وبالتالي، إذا تمكنا من تنفيذ المنطق داخل المكتبات في C وC++ واستخدامه لاحقًا على منصات متعددة، فسنكون قادرين على تقليل عقوبة أداء التطبيق. في مثل هذه الحالات، سوف نستخدم كود C وC++ مع كود Java العادي أو "رمز النظام الأساسي المتعدد".
عند استخدام لغة برمجة مجمعة، يتم تجميع التعليمات البرمجية المصدر مباشرة في كود الجهاز لوحدة المعالجة المركزية، وليس في تمثيل وسيط كما هو الحال في لغة جافا. بهذه الطريقة، يمكن لمطوري التطبيقات إنشاء تطبيقات ذات أداء مثالي لأجهزة Android المختلفة. يمكن تنظيم أجزاء من التعليمات البرمجية المترجمة ضمن مكتبة مشتركة واحدة، ويمكن استدعاء الوظائف منها من كود Java. يجب إنشاء مكتبة مشتركة منفصلة لكل من بنيات وحدة المعالجة المركزية المدعومة. قد تظل معظم كود المصدر الخاص به دون تغيير. يجب إضافة المكتبات المشتركة المترجمة إلى ملف .apk الخاص بالتطبيق الخاص بك. مع كل ما قيل، لن يتغير النموذج الأساسي لتطبيقات Android.
Android NDK عبارة عن مجموعة أدوات تسمح لك بتنفيذ أجزاء من تطبيق Android بلغات برمجة مجمعة مثل C وC++ وتحتوي على مكتبات لإدارة الأنشطة والوصول إلى المكونات المادية للجهاز، مثل أجهزة الاستشعار المختلفة والشاشة.
تم دمج Android NDK مع أدوات من Software Development Kit (Android SDK)، بالإضافة إلى بيئة التطوير المتكاملة لـ Android Studio أو بيئة تطوير Eclipse ADT القديمة. ومع ذلك، لا يمكن استخدام NDK بمفرده.
قلب Android NDK هو البرنامج النصي ndk-build، وهو المسؤول عن اجتياز ملفات مشروع Android تلقائيًا (يبدأ تطوير كل تطبيق Android جديد باستخدام بيئة تطوير متكاملة مثل Android Studio أو Eclipse بإنشاء ملفات مشروع جديدة). وجمع المعلومات حول المكونات التي يجب تجميعها. هذا البرنامج النصي مسؤول أيضًا عن إنشاء الثنائيات ونسخ هذه الثنائيات إلى دليل ملفات مشروع التطبيق.
يمكننا استخدام الكلمة الأساسية الأصلية للسماح للمترجم بمعرفة أن جزءًا معينًا قد تم تنفيذه داخل الكود المترجم. على سبيل المثال:
أرقام int العامة الأصلية(int x, int y);
أيضًا، أثناء عملية بناء المشروع، يتم إنشاء مكتبات مشتركة (المكتبات المشتركة الأصلية، بامتداد .so) والمكتبات الثابتة (المكتبات المشتركة الأصلية، بامتداد .a)، والتي يمكن ربطها بمكتبات أخرى. تستخدم الواجهة الثنائية للتطبيقات (ABI) المكتبات المشتركة ذات الامتداد .so لتنفيذ تعليمات برمجية للجهاز على النظام أثناء تشغيل التطبيق.
يتم تنفيذ جميع التعليمات البرمجية المترجمة من خلال واجهة تسمى Java Native Interface (JNI)، والتي تسمح بربط مكونات Java وC/C++ معًا.
لبناء المشروع باستخدام البرنامج النصي ndk-build، سيتعين علينا إنشاء ملفين: Android.mk وApplication.mk. يجب أن يكون كلا الملفين موجودين في دليل JNI. يصف ملف Android.mk الوحدة واسمها، وإشارات البناء، والمكتبات المستخدمة، وملفات التعليمات البرمجية المصدر التي يجب تجميعها، ويصف ملف Application.mk الوحدات الثنائية اللازمة لعمل التطبيق.
يأتي Android NDK بتنسيق أرشيف ذاتي الاستخراج. لهذا السبب، سيتعين علينا فقط ضبط بت التنفيذ وفك ضغطه:
$ chmod +x android-ndk-r10c-linux-x86_64.bin $ ./android-ndk-r10c-linux-x86_64.bin
ونتيجة لذلك، سيتم حفظ مكونات NDK في دليل العمل الحالي.
التفريغ اليدوي
نظرًا لأن ملف .bin ليس أكثر من أرشيف 7-Zip ذاتي الاستخراج، فيمكننا استخراج محتوياته يدويًا باستخدام الأمر التالي:
$ 7za x -o/path/to/target/directories/android-ndk-r10c-linux-x86_64.bin
تتوفر الحزمة التي تحتوي على مكونات أرشيفية 7-Zip من مستودع Ubuntu الرسمي ويمكن تثبيتها، على سبيل المثال، باستخدام الأمر apt-get:
$ sudo apt-get install p7zip-full
يمكننا تثبيت Android NDK باستخدام مكون SDK Manager مباشرة من Android Studio.
للقيام بذلك، بعد فتح المشروع، يجب أن تذهب إلى القائمة الرئيسية للنافذة الأدوات\u003e Android\u003e SDK Manager. بعد ذلك، تحتاج إلى تحديد المربعات المجاورة لأسماء المكونات LLDB، CMake وNDK. بعد ذلك، تحتاج فقط إلى تطبيق التغييرات باستخدام الزر المناسب.
بعد إعداد Android Studio، يمكننا إنشاء مشروع جديد يدعم لغات البرمجة C/C++. ومع ذلك، إذا كنا بحاجة إلى إضافة أو استيراد التعليمات البرمجية الموجودة بهذه اللغات إلى مشروع Android Studio، فسنضطر إلى اتباع الخطوات أدناه.
الخطوة الأولى هي إنشاء ملفات كود مصدر جديدة باستخدام لغات البرمجة المذكورة وإضافتها إلى مشروع مفتوح في Android Studio. يمكننا تخطي هذه الخطوة إذا كان المشروع يحتوي بالفعل على ملفات مشابهة أو كنا بحاجة إلى استيراد مكتبة مجمعة مسبقًا إليه.
يتيح لك البرنامج النصي لبناء CMake إخبار نظام البناء الذي يحمل نفس الاسم بكيفية تجميع ملفات التعليمات البرمجية المصدر وإنشاء المكتبة الثنائية الناتجة. هذا الملف مطلوب أيضًا لاستيراد مكتبات NDK الموجودة أو المجمعة وربطها بمكتبتنا. يمكننا أيضًا تخطي هذه الخطوة دون أي عواقب إذا كانت مكتبتنا الثنائية الحالية تأتي بالفعل مع ملف البرنامج النصي للبناء CMakeLists.txt أو إذا كانت تستخدم مكون ndk-build وتأتي مع ملف البرنامج النصي للبناء Android.mk .
بعد ذلك، نحتاج إلى إخبار Gradle بوجود مكتبتنا الثنائية عن طريق تحديد المسار إلى ملف البرنامج النصي الخاص ببناء CMake أو ndk-build. يستخدم Gradle البرنامج النصي للبناء المحدد لاستيراد الكود المصدري إلى مشروع Android Studio وحزم المكتبة الثنائية الناتجة (ملف بامتداد .so) في ملف حزمة بتنسيق APK.
ملاحظة مهمة:إذا كان المشروع يستخدم أداة ndkCompile القديمة، فسيتعين علينا فتح ملف build.poperties وإزالة السطر التالي من التعليمات البرمجية منه قبل تكوين Gradle لاستخدام CMake أو ndk-build:
Android.useDeprecatedNdk = true
يمكننا الآن إنشاء تطبيقنا وتشغيله من خلال النقر على زر التشغيل. سيعتبر Gradle عملية CMake أو ndk-build بمثابة تبعية سيتم إنشاؤها، وبناء المكتبة الثنائية، وتجميعها في ملف APK.
بمجرد تشغيل التطبيق على الجهاز أو في المحاكي، يمكننا استخدام ميزات بيئات التطوير المتكاملة المتنوعة مثل Android Studio لتصحيح أخطائه.
كل هذا يوضح أهمية Android NDK لمطوري التطبيقات لمنصة Android. على سبيل المثال، تسمح هذه المجموعة من مكونات البرامج لمنشئي محركات الألعاب بتحسين إصدارات منتجاتهم لنظام Android بشكل أفضل، ونتيجة لذلك سينتجون تأثيرات رسومية أكثر إثارة للإعجاب، وإنفاق موارد نظام أقل عليها.
لا ترتبط عملية إنشاء تطبيق بسيط يعتمد على Android NDK بأية صعوبات. ومع ذلك، يجب على كل مطور أن يفهم نقطة مهمة واحدة: تم تصميم مكونات برنامج Android NDK للاستخدام في حالات محددة ولا ينبغي استخدامها في تطوير أي تطبيق.
يمكن أن يساعد Android NDK في عملية تطوير التطبيقات ويجعلها صعبة قدر الإمكان. كما أنه ليس سراً أن استخدام الكود الثنائي على منصة أندرويد في بعض الحالات لا يؤدي إلى زيادة ملحوظة في أداء التطبيق (على الرغم من أن أدائه يزيد في معظم الحالات)، ولكنه على أي حال يؤدي إلى تعقيد الكود الخاص به. عادةً، يتم تحقيق تحسينات في أداء التطبيق عن طريق تشغيل التعليمات البرمجية مع تعليمات خاصة بوحدة المعالجة المركزية (CPU). ولكن بشكل عام، يوصى باستخدام NDK فقط عندما يكون أداء التطبيق معلمة حرجة، وليس عندما يكون المطور أكثر راحة في كتابة التعليمات البرمجية في C/C++.
في الختام، ينبغي القول أنه لا توجد قواعد ثابتة تحكم الحالات المحتملة لاستخدام NDK، لذلك يجب عليك دائمًا اللجوء إلى معرفتك وخبرتك وحدسك.
أندرويد إن دي كيههي مجموعة أدوات موثوقة وفعالة مصممة خصيصًا لنظام Android والمطورين الذين يحتاجون إلى تنفيذ أجزاء من تطبيقاتهم باستخدام لغات البرمجة مثل C++ أو C#.
ومع ذلك، قبل استخدام Android NDK، يجب أن تكون خبيرًا كبيرًا في لغات التعليمات البرمجية الأصلية هذه وأن تتأكد من أن جهاز الكمبيوتر الخاص بك يلبي جميع متطلبات النظام، وإلا فلن تتمكن من الاستفادة من جميع الميزات التي تأتي بها مجموعة الأدوات.
بشكل عام، يمكنك الحصول على الكثير من برامج C أو Java النصية للتطبيق الحالي، ولكن عند استخدام Android NDK، يمكنك تسريع عملية تطوير مشروعك، بالإضافة إلى الحفاظ على مزامنة التغييرات بين المشاريع التي تعمل بنظام Android وغير Android.
باعتبارك مطورًا متقدمًا، عند استخدام Android NDK، فإنك تحتاج إلى الموازنة بين فوائده وعيوبه. ومن ثم، يجب عليك استخدامه فقط إذا كان ضروريًا عند تطوير تطبيق جديد وكنت بحاجة إلى هذا المكون.
ومع ذلك، ليس عليك أن تفترض أنه يمكنك زيادة أداء التطبيق الخاص بك فقط لأنك تستخدم التعليمات البرمجية الأصلية. ما عليك سوى التحقق من المتطلبات ومعرفة ما إذا كانت واجهات برمجة تطبيقات إطار عمل Android توفر لك الوظيفة الرئيسية التي تحتاجها.
ومع ذلك، عندما تكون متأكدًا من أن Android NDK هو مكون تحتاجه حقًا لتشغيل تطبيقاتك وتطويرها، يمكنك فك ضغطه ووضعه في الدليل المناسب. بعد ذلك، ستكون المتغيرات مثل "android_log_print" و"sample_ndk" متاحة داخل مشروعك.
بالإضافة إلى ذلك، توفر لك حزمة NDK الأدوات المناسبة حتى تتمكن من العمل بكفاءة مع البرامج النصية الخاصة بك، دون الحاجة إلى التعامل مع جميع تفاصيل وحدة المعالجة المركزية وABI.
مع الأخذ في الاعتبار أن Android NDK مخصص خصيصًا لمطوري Java، فهو يوفر لهم فئات مفيدة تُعلم الكود الأصلي الخاص بهم بأي عمليات رد اتصال في دورة حياة النشاط. ومع ذلك، فإن الجزء الأكثر إثارة للاهتمام في مجموعة الأدوات هذه هو أنها تمكنهم من تضمين المكتبات الأصلية في ملف حزمة التطبيق، والذي يمكن نشره على أجهزة Android.