بناء تطبيقات Android و iOS في خط أنابيب CI/CD

لديك تطبيق جوال يتم تجميعه بنجاح على حاسوبك المحمول. تدفع الكود إلى المستودع، يبدأ خط أنابيب CI، وبعد عشر دقائق يفشل بخطأ لم تره من قبل. إصدار SDK مختلف. تبعية تم حلها إلى إصدار أحدث قليلاً. شهادة التوقيع مفقودة. هذا هو واقع بناء التطبيقات الجوالة في CI: ما يعمل محلياً غالباً ما ينكسر في خط الأنابيب.

أول شيء يجب إتقانه في خط أنابيب CI للجوال هو عملية البناء نفسها. ليس فقط تشغيل المترجم، بل إنتاج قطعة أثرية متسقة وقابلة للاختبار وجاهزة للتوزيع. تتعامل Android و iOS مع هذا بشكل مختلف، ولكل منهما مزالقها الخاصة.

بناء Android باستخدام Gradle

تعمل عمليات بناء Android من خلال Gradle، الذي يقرأ الإعدادات من ملفات build.gradle. هناك ثلاثة إعدادات SDK مهمة هنا: compileSdk و minSdk و targetSdk. من السهل الخلط بينها، لكن لكل منها غرض محدد.

يتحكم compileSdk في مستوى API المتاح أثناء التجميع. إذا قمت بتعيينه إلى 34، يمكنك استخدام واجهات برمجة التطبيقات المقدمة في Android 14. minSdk هو أدنى إصدار Android يدعمه تطبيقك. إذا قمت بتعيينه إلى 26، فلن تتمكن الأجهزة التي تعمل بنظام Android 8.0 أو الأقدم من تثبيت تطبيقك. يخبر targetSdk Android بالإصدار الذي اختبرت تطبيقك ضده. عندما تستهدف SDK أحدث، قد يطبق Android تغييرات سلوكية تؤثر على تطبيقك.

يجب أن يستخدم خط الأنابيب نفس إصدارات SDK المستخدمة في بيئة التطوير المحلية لديك. غالباً ما يتسبب عدم التطابق في أخطاء ترجمة تظهر فقط في CI. قم بتثبيت هذه الإصدارات بشكل صريح في ملفات build.gradle الخاصة بك وتحقق منها في تكوين خط الأنابيب.

التبعيات هي مصدر شائع آخر للمشاكل. يسحب Gradl المكتبات من Maven Central أو Google Maven أو المستودع الداخلي الخاص بك. بدون تخزين مؤقت، يقوم خط الأنابيب بتنزيل كل تبعية من الصفر في كل بناء. مشروع يحتوي على عشرين تبعية يمكن أن يقضي من عشر إلى خمس عشرة دقيقة في التنزيل فقط. قم بتخزين دليل تبعيات Gradle مؤقتاً بين عمليات البناء. تدعم معظم منصات CI هذا من خلال تغيير بسيط في التكوين، وهذا يقلل وقت البناء بشكل كبير.

مخرجات بناء Android هي إما APK أو AAB. APK هو التنسيق الأقدم الذي يمكنك تثبيته مباشرة على جهاز. AAB هو التنسيق الأحدث الذي تقوم بتحميله إلى Google Play، والذي يقوم بعد ذلك بإنشاء APKs محسّنة لكل تكوين جهاز. استخدم APK للاختبار الداخلي والتوزيع اليدوي. استخدم AAB للإصدارات الرسمية عبر متجر Play. يجب أن يدعم خط الأنابيب الخاص بك كليهما، لكن الاختيار يعتمد على وجهة القطعة الأثرية.

إليك مهمة GitHub Actions بسيطة تقوم ببناء تطبيق Android وتخزين APK كقطعة أثرية:

name: Android Build
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          distribution: 'temurin'
          java-version: '17'
      - name: Cache Gradle dependencies
        uses: actions/cache@v4
        with:
          path: ~/.gradle/caches
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
          restore-keys: |
            ${{ runner.os }}-gradle-
      - name: Build release APK
        run: ./gradlew assembleRelease
      - name: Upload APK
        uses: actions/upload-artifact@v4
        with:
          name: app-release
          path: app/build/outputs/apk/release/*.apk

يقوم هذا المثال بإعداد JDK، وتمكين التخزين المؤقت لـ Gradle، وتشغيل بناء الإصدار، ورفع APK الناتج. قم بضبط إصدار Java ومسار Gradle wrapper ليتوافق مع مشروعك.

بناء iOS باستخدام Xcode

تستخدم عمليات بناء iOS Xcode ونظام البناء الخاص به. يقوم خط الأنابيب بتشغيل xcodebuild مع معلمات تحدد المخطط (scheme) والتكوين (Debug أو Release) والوجهة (محاكي أو جهاز فعلي). ملف المشروع إما .xcodeproj أو .xcworkspace. إذا كان مشروعك يستخدم CocoaPods، فأنت بحاجة إلى ملف workspace.

إدارة التبعيات هي المكان الذي تنكسر فيه عمليات بناء iOS غالباً. تستخدم العديد من مشاريع iOS CocoaPods أو Swift Package Manager أو Carthage. يجب على خط الأنابيب تشغيل pod install أو swift package resolve قبل البناء. إذا اختلفت الإصدارات التي تم حلها في CI عما يستخدمه فريقك محلياً، فستحصل على أخطاء يصعب تصحيحها. قم بقفل إصدارات التبعيات. يقوم CocoaPods بإنشاء ملف Podfile.lock. قم بتثبيته في المستودع وتأكد من أن خط الأنابيب يستخدمه.

مخرجات بناء iOS هي ملف IPA. على عكس APK، IPA هو حزمة تحتوي على التطبيق الموقع. تنتج خطوط الأنابيب عادةً نوعين: IPA للتطوير للاختبار الداخلي باستخدام شهادات التطوير، وIPA للتوزيع لمتجر التطبيقات. كلاهما يحتاج إلى توقيع مناسب، والذي سنغطيه بشكل منفصل.

تخزين القطع الأثرية للبناء

ينتج كل من بناء Android و iOS قطعاً أثرية تحتاج إلى التخزين. أبسط نهج هو استخدام التخزين المدمج للقطع الأثرية في منصة CI الخاصة بك. للفرق الأكبر أو سير العمل الأكثر تعقيداً، قم بتحميل القطع الأثرية إلى موقع مشترك مثل S3 أو Google Cloud Storage.

يوضح الرسم البياني التالي كيفية عمل خطوط أنابيب بناء Android و iOS بالتوازي والتقارب عند تخزين القطع الأثرية.

flowchart TD A[سحب الكود] --> B[Android: بناء Gradle] A --> C[iOS: بناء Xcode] B --> D[APK / AAB] C --> E[IPA] D --> F[تخزين القطع الأثرية] E --> F F --> G[رقم الإصدار ورقم البناء]

كل قطعة أثرية تحتاج إلى معرف واضح. قم بتضمين رقم الإصدار ورقم البناء في اسم الملف أو البيانات الوصفية. يجب أن تكون قادراً على تتبع أي قطعة أثرية إلى الالتزام (commit) المحدد الذي أنتجها. بدون هذا، يصبح تصحيح مشكلة إنتاجية تخميناً.

قائمة التحقق العملية

قبل أن تعلن أن خط أنابيب بناء تطبيقات الجوال جاهز، راجع قائمة التحقق القصيرة هذه:

  • إصدارات SDK في build.gradle متطابقة بين البيئة المحلية وبيئة CI
  • التخزين المؤقت لتبعيات Gradle مفعل
  • ملف Podfile.lock أو ما يعادله مثبت في المستودع ومستخدم في CI
  • مخطط Xcode والتكوين محددان بشكل صريح في خط الأنابيب
  • أسماء ملفات القطع الأثرية تتضمن رقم الإصدار ورقم البناء
  • القطع الأثرية للبناء مخزنة ويمكن الوصول إليها بعد انتهاء خط الأنابيب

الخلاصة

خط أنابيب بناء تطبيقات الجوال لا يتعلق فقط بتشغيل مترجم. إنه يتعلق بإعادة إنتاج نفس البيئة، ونفس التبعيات، ونفس التكوين في كل مرة. عندما يعمل البناء المحلي ولكن خط الأنابيب يفشل، فالمشكلة دائماً تقريباً هي اختلاف في أحد هذه الأشياء الثلاثة. قم بقفلها، وقم بالتخزين المؤقت بقوة، وقم بتسمية القطع الأثرية بوضوح. بقية خط الأنابيب يعتمد على إتقان هذه الخطوة الأولى.