يتم عادةً إنشاء تطبيقات Android باستخدام نظام الإنشاء Gradle. قبل الخوض في تفاصيل كيفية ضبط الإصدار، سنطّلع على أساسيات الإصدار حتى تتمكّن من الاطّلاع على النظام ككل.
ما هو الإصدار؟
يحوّل نظام الإنشاء رمز المصدر إلى تطبيق قابل للتنفيذ. غالبًا ما تتضمّن عمليات الإنشاء أدوات متعددة لتحليل التطبيق أو المكتبة وتجميعهما وربطهما وتجميعهما في حِزم. يستخدم Gradle نهجًا يستند إلى المهام لتنظيم هذه الأوامر وتنفيذها.
المهام هي وحدات تحوي أوامر تحوّل الإدخالات إلى
مخرجات. تحدِّد الإضافات المهام وإعداداتها. يؤدي تطبيق ملفٍ داعم إلى تسجيل مهامه وربطها معًا باستخدام المدخلات والمخرجات. على سبيل المثال، سيؤدي تطبيق المكوّن الإضافي لنظام Gradle المتوافق مع Android (AGP)
على ملف التصميم إلى تسجيل جميع المهام اللازمة لإنشاء حزمة APK أو
مكتبة Android. يتيح لك المكوّن الإضافي java-library
إنشاء ملف jar من رمز مصدر Java. تتوفّر مكوّنات إضافية مشابهة لـ Kotlin ولغات أخرى، ولكن المكوّنات الإضافية الأخرىتهدف إلى توسيع نطاق المكوّنات الإضافية. على سبيل المثال، يهدف المكوّن الإضافي protobuf
إلى إضافة دعم
protobuf إلى المكوّنات الإضافية الحالية، مثل AGP أو java-library
.
يفضّل Gradle الأسلوب على الإعدادات، لذا ستتضمّن المكوّنات الإضافية قيمًا جيدة تلقائيًا، ولكن يمكنك ضبط عملية الإنشاء بشكل أكبر من خلال لغة خاصة بالنطاق (DSL) تعريفية. تم تصميم لغة DSL لكي تتمكّن من تحديد ما تريد إنشاؤه، بدلاً من كيفية إنشائه. يدير المنطق في الإضافات "كيفية" تنفيذ ذلك. يتم تحديد هذه الإعدادات في عدة ملفات إنشاء في مشروعك (والمشاريع الفرعية).
يمكن أن تكون مدخلات المهام ملفات ودلائل بالإضافة إلى معلومات أخرى يتم تشفيرها على أنّها أنواع Java (عدد صحيح أو سلاسل أو فئات مخصّصة). لا يمكن أن تكون النواتج سوى دليل أو ملفات، لأنّه يجب كتابتها على القرص. يؤدي توصيل مخرج مهمة بمدخل مهمة أخرى إلى ربط المهام معًا بحيث يجب تنفيذ إحدى المهام قبل الأخرى.
على الرغم من أنّ Gradle يتيح كتابة رمز عشوائي وبيانات مهام في ملفات الإنشاء ، قد يجعل ذلك من الصعب على الأدوات فهم عملية الإنشاء ويكون من الصعب عليك الاحتفاظ بها. على سبيل المثال، يمكنك كتابة اختبارات للرمز البرمجي داخل المكوّنات الإضافية، ولكن ليس في ملفات الإنشاء. بدلاً من ذلك، يجب حصر منطق التصميم وملفتَي IDE لملف الترجمة والرمز البرمجي في المكوّنات الإضافية (التي تحدّدها أنت أو شخص آخر) وتحديد كيفية استخدامك لهذا المنطق في ملفات التصميم.
ماذا يحدث عند تشغيل عملية إنشاء Gradle؟
يتم تنفيذ عمليات إنشاء Gradle في ثلاث مراحل. تنفِّذ كل مرحلة من هذه المراحل أجزاء مختلفة من الرمز البرمجي الذي تحدِّده في ملفات الإنشاء.
- تحدِّد عملية الإعداد المشاريع والمشاريع الفرعية التي يتم تضمينها في عملية الإنشاء، وتُنشئ مسارات فصول التحميل التي تحتوي على ملفات الإنشاء والمكونات المضمَّنة في الإصدار. تركّز هذه المرحلة على ملف الإعدادات الذي تُعلن فيه عن المشروعات التي تريد بنائها والمواقع التي تريد جلب المكوّنات الإضافية والمكتبات منها.
- يُسجِّل الإعداد المهام لكل مشروع، وينفِّذ ملف الإصدار لتطبيق مواصفات إصدار المستخدم. من المهم معرفة أنّ رمز الضبط لن يتمكّن من الوصول إلى البيانات أو الملفات التي يتم إنشاؤها أثناء التنفيذ.
- ينفِّذ التنفيذ عملية "الإنشاء" الفعلية لتطبيقك. الناتج للإعداد هو رسم بياني اتجاهي لا دوري (DAG) للمهام، ويمثّل جميع خطوات الإنشاء المطلوبة التي طلبها المستخدم (المهام التي يتم تقديمها في سطر الأوامر أو كإعدادات تلقائية في ملفات الإنشاء). يمثّل هذا الرسم البياني العلاقة بين المهام، سواء كانت صريحة في بيان المهمة أو استنادًا إلى مدخلاتها ومخرجاتها. إذا كانت إحدى المهام تحتوي على إدخال هو المخرجات لمهمة أخرى، يجب تنفيذها بعد المهمة الأخرى. تُنفِّذ هذه الخطوة المهام القديمة بالترتيب المحدّد في الرسم البياني. وإذا لم تتغيّر مدخلات المهام منذ آخر تنفيذ لها، سيتخطّاها Gradle.
لمزيد من المعلومات، يُرجى الاطّلاع على دورة حياة عملية الإنشاء في Gradle.
لغات وصف الجلسات (DSL) للإعداد
يستخدم Gradle لغة خاصة بالنطاق (DSL) لضبط عمليات الإنشاء. يركز هذا النهج التعريفي على تحديد بياناتك بدلاً من كتابة تعليمات خطوة بخطوة (أمرية). يمكنك كتابة ملفات الإنشاء باستخدام Kotlin أو Groovy، ولكننا ننصح بشدة باستخدام Kotlin.
تحاول لغات DSL تسهيل المساهمة في المشروع على الجميع، سواء كانوا خبراء في المجال أو مبرمجين، من خلال تحديد لغة صغيرة تمثّل البيانات بطريقة أكثر طبيعية. يمكن لمكوّنات Gradle الإضافية توسيع لغة برمجة التطبيقات المحدودة (DSL) لضبط البيانات التي تحتاجها لإنجاز مهامها.
على سبيل المثال، قد يبدو إعداد جزء Android من عملية الإنشاء على النحو التالي:
Kotlin
android { namespace = "com.example.app" compileSdk = 34 // ... defaultConfig { applicationId = "com.example.app" minSdk = 34 // ... } }
رائع
android { namespace 'com.example.myapplication' compileSdk 34 // ... defaultConfig { applicationId "com.example.myapplication" minSdk 24 // ... } }
من وراء الكواليس، يشبه رمز DSL ما يلي:
fun Project.android(configure: ApplicationExtension.() -> Unit) {
...
}
interface ApplicationExtension {
var compileSdk: Int
var namespace: String?
val defaultConfig: DefaultConfig
fun defaultConfig(configure: DefaultConfig.() -> Unit) {
...
}
}
يتم تمثيل كلّ وحدة في لغة DSL بدالة تأخذ دالة LAMBDA لتحديد إعداداتها، وسمة تحمل الاسم نفسه للوصول إليها. ويجعل ذلك الرمز البرمجي في ملفات التصميم يبدو أكثر شبهاً بمواصفات البيانات.
المهام التابعة الخارجية
قدّم نظام إنشاء Maven مواصفات التبعية، ونظام التخزين والإدارة. يتم تخزين المكتبات في المستودعات (الخوادم أو الأدلة)، مع البيانات الوصفية التي تشمل الإصدار والموارد التي تعتمد عليها المكتبات الأخرى. يمكنك تحديد المستودعات التي تريد البحث فيها وإصدارات التبعيات التي تريد استخدامها، ويقوم نظام الإنشاء بتنزيلها أثناء عملية الإنشاء.
يتم تحديد عناصر Maven حسب اسم المجموعة (الشركة أو المطوّر أو غير ذلك) واسم العنصر (اسم المكتبة) وإصدار هذا العنصر. ويتم تمثيله عادةً
برمز group:artifact:version
.
تحسِّن هذه الطريقة إدارة الإصدارات بشكل كبير. غالبًا ما تُعرف هذه المستودعات باسم "مستودعات Maven"، ولكنّها تعتمد على طريقة حزم العناصر ونشرها. تمت إعادة استخدام هذه المستودعات وبيانات التعريف في عدة أنظمة إنشاء، بما في ذلك Gradle (ويمكن لنظام Gradle نشر المحتوى في هذه المستودعات). تسمح المستودعات العامة بالمشاركة للجميع، وتحتفظ مستودعات الشركة بالموارد الداخلية داخليًا.
يمكنك أيضًا تقسيم مشروعك إلى مشاريع فرعية (المعروفة أيضًا باسم "الوحدات" في استوديو Android)، والتي يمكن استخدامها أيضًا كأحد المكوّنات التي يعتمد عليها المشروع. ينتج كل مشروع فرعي نتائج (مثل ملفات JAR) يمكن استخدامها من قِبل المشاريع الفرعية أو مشروعك من المستوى الأعلى. ويمكن أن يؤدي ذلك إلى تحسين وقت الإنشاء من خلال عزل الأجزاء التي يجب إعادة إنشائها، بالإضافة إلى فصل المهام بشكل أفضل في التطبيق.
سنوضّح بالتفصيل كيفية تحديد التبعيات في إضافة تبعيات الإنشاء.
إنشاء الأسعار المتغيرة
عند إنشاء تطبيق Android، ستحتاج عادةً إلى إنشاء عدة صيغ. تحتوي الأسعار المتغيرة على رمز برمجي مختلف أو يتم إنشاؤها باستخدام خيارات مختلفة، وتتألف من أنواع الإصدارات ونُسخ المنتجات.
تختلف أنواع الإصدارات عن خيارات الإصدار المعلَن عنها. يُعدّ AGP تلقائيًا نوعَي الإصدار و"تصحيح الأخطاء"، ولكن يمكنك تعديلهما وإضافة المزيد (ربما لأجل الإصدار التجريبي أو الاختبار الداخلي).
لا يؤدي إصدار تصحيح الأخطاء إلى تصغير تطبيقك أو تشويشه، ما يؤدي إلى تسريع عملية إنشاءه والحفاظ على جميع الرموز كما هي. ويضع الإصدار أيضًا علامة على التطبيق تفيد بأنّه "قابل لتصحيح الأخطاء"، ويوقّعه بمفتاح تصحيح أخطاء عام ويسمح بالوصول إلىملفات التطبيق المثبَّتة على الجهاز. يتيح لك ذلك استكشاف البيانات المحفوظة في الملفات وقواعد البيانات أثناء تشغيل التطبيق.
تحسِّن الإصدارات العلنية التطبيق وتوقّعه باستخدام مفتاح الإصدار، كما تحمي ملفات التطبيق المثبَّتة.
باستخدام أنواع المنتجات، يمكنك تغيير المصدر المضمّن ومتغيرات التبعية للتطبيق. على سبيل المثال، قد تحتاج إلى إنشاء إصدار "تجريبي" وإصدار "كامل" لتطبيقك، أو ربما إصدار "مجاني" وإصدار "مدفوع". يمكنك كتابة المصدر المشترك في دليل مجموعة مصادر "رئيسي"، و استبدال المصدر أو إضافته في مجموعة مصادر تحمل اسم النكهة.
تُنشئ أداة AGP خيارات لكل مجموعة من نوع الإصدار ونكهة المنتج. إذا
لم تحدِّد النكهات، يتم تسمية الأسعار المتغيرة حسب أنواع الإصدارات. في حال تحديد كليهما، يتم تسمية الصيغة <flavor><Buildtype>
. على سبيل المثال، باستخدام نوعَي الإصدارrelease
وdebug
والنكهتَينdemo
وfull
، ستنشئ أداة AGP
الصيغ التالية:
demoRelease
demoDebug
fullRelease
fullDebug
الخطوات التالية
بعد الاطّلاع على مفاهيم عملية الإنشاء، اطّلِع على بنية عملية إنشاء التطبيقات على Android في مشروعك.