تحسين سرعة الإصدار

تؤدي أوقات الإنشاء الطويلة إلى إبطاء عملية التطوير. تعرض هذه الصفحة بعض الأساليب للمساعدة في حلّ المشاكل المؤثِّرة في سرعة الإصدار.

في ما يلي العملية العامة لتحسين سرعة إصدار تطبيقك:

  1. تحسين إعدادات تصميمك من خلال اتّخاذ بضع خطوات تفيد على الفور معظم مشاريع "استوديو Android"
  2. احرص على تطوير إصدارك لتحديد وتشخيص بعض العقبات الأكثر تعقيدًا التي قد تكون خاصة بمشروعك أو محطة العمل.

وأثناء تطوير تطبيقك، انشره على جهاز يعمل بالإصدار Android 7.0 (المستوى 24 لواجهة برمجة التطبيقات) أو إصدار أحدث كلما أمكن ذلك. تنفّذ الإصدارات الأحدث من نظام Android آليات أفضل لنشر التحديثات على تطبيقك، مثل وقت تشغيل Android (ART) والدعم المحلي لملفات DEX المتعددة.

ملاحظة: بعد إنشاء أول إصدار جديد بدون أي مشاكل، قد تلاحظ أنّ الإصدارات اللاحقة، سواء الإصدار الدقيق أم التزايدي، تحقّق أداءً أسرع حتى بدون استخدام أيٍّ من التحسينات الموضّحة في هذه الصفحة. ويرجع ذلك إلى أنّ برنامج Gradle الخفيف يحتوى على تحسين الأداء، على غرار عمليات JVM الأخرى.

تحسين إعدادات تصميمك

اتّبِع هذه النصائح لتحسين سرعة إنشاء مشروع "استوديو Android".

تحديث أدواتك باستمرار

تخضع أدوات Android لتحسينات الإصدار وميزات جديدة مع كل تحديث تقريبًا. تفترض بعض النصائح في هذه الصفحة أنّك تستخدم أحدث إصدار. وللاستفادة من أحدث التحسينات، عليك تعديل المعلومات التالية باستمرار:

استخدام KSP بدلاً من kapt

تُعدّ أداة معالجة التعليقات التوضيحية في Kotlin (kapt) أبطأ بشكل ملحوظ من معالج رموز Kotlin (KSP). إذا كنت تكتب مصدر Kotlin يتضمّن تعليقات توضيحية وتستخدم أدوات تعالج التعليقات التوضيحية (مثل Room) التي تتوافق مع برنامج KSP، ننصحك بنقل البيانات إلى برنامج KSP.

تجنب تجميع الموارد غير الضرورية

تجنَّب تجميع الموارد التي لا تختبرها وتجميعها، مثل عمليات أقلمة اللغات الإضافية وموارد كثافة الشاشة. بدلاً من ذلك، حدِّد موردًا واحدًا وكثافة شاشة واحدة فقط لصيغة "dev"، كما هو موضّح في النموذج التالي:

رائع

android {
    ...
    productFlavors {
        dev {
            ...
            // The following configuration limits the "dev" flavor to using
            // English stringresources and xxhdpi screen-density resources.
            resourceConfigurations "en", "xxhdpi"
        }
        ...
    }
}

Kotlin

android {
    ...
    productFlavors {
        create("dev") {
            ...
            // The following configuration limits the "dev" flavor to using
            // English stringresources and xxhdpi screen-density resources.
            resourceConfigurations("en", "xxhdpi")
        }
        ...
    }
}

تجربة وضع بوابة مكوّنات Gradle في آخر مرة

في نظام التشغيل Android، يمكن العثور على جميع المكوّنات الإضافية في مستودعات google() وmavenCentral(). ومع ذلك، قد يحتاج التصميم إلى مكوّنات إضافية تابعة لجهات خارجية تم حلها باستخدام خدمة gradlePluginPortal().

يتم البحث عن المستودعات بالترتيب الذي تم الإعلان عنها، لذلك يتم تحسين أداء الإصدار إذا كانت المستودعات المدرَجة أولاً تحتوي على معظم المكوّنات الإضافية. بالتالي، جرِّب إدخال gradlePluginPortal() من خلال وضعه في آخر مجموعة في المستودع ضمن ملف settings.gradle. وفي معظم الحالات، يؤدي ذلك إلى تقليل عدد عمليات البحث عن المكوّنات الإضافية المتكررة وتحسين سرعة الإصدار.

لمزيد من المعلومات حول كيفية تنقل Gradle بين المستودعات المتعددة، يرجى الاطّلاع على القسم تعريف المستودعات المتعددة في مستندات Gradle.

استخدام قيم تهيئة الإصدار الثابت مع إصدار تصحيح الأخطاء

استخدِم دائمًا قيمًا ثابتة للسمات التي تتم إضافتها في ملف البيان أو ملفات الموارد لنوع إصدار تصحيح الأخطاء.

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

  ...
  // Use a filter to apply onVariants() to a subset of the variants.
  onVariants(selector().withBuildType("release")) { variant ->
      // Because an app module can have multiple outputs when using multi-APK, versionCode
      // is only available on the variant output.
      // Gather the output when we are in single mode and there is no multi-APK.
      val mainOutput = variant.outputs.single { it.outputType == OutputType.SINGLE }

      // Create the version code generating task.
      val versionCodeTask = project.tasks.register("computeVersionCodeFor${variant.name}", VersionCodeTask::class.java) {
          it.outputFile.set(project.layout.buildDirectory.file("versionCode${variant.name}.txt"))
      }

      // Wire the version code from the task output.
      // map will create a lazy Provider that:
      // 1. Runs just before the consumer(s), ensuring that the producer (VersionCodeTask) has run
      //    and therefore the file is created.
      // 2. Contains task dependency information so that the consumer(s) run after the producer.
      mainOutput.versionCode.set(versionCodeTask.flatMap { it.outputFile.map { it.asFile.readText().toInt() } })
  }
  ...

  abstract class VersionCodeTask : DefaultTask() {

    @get:OutputFile
    abstract val outputFile: RegularFileProperty

    @TaskAction
    fun action() {
        outputFile.get().asFile.writeText("1.1.1")
    }
  }

يمكنك الاطّلاع على وصفة setVersionsFromTask على GitHub للتعرّف على كيفية ضبط رمز إصدار ديناميكي في مشروعك.

استخدام إصدارات التبعية الثابتة

عند تعريف الإضافات في ملفات build.gradle، تجنَّب استخدام أرقام الإصدارات الديناميكية (التي تحتوي على علامة جمع في النهاية، مثل 'com.android.tools.build:gradle:2.+'). قد يؤدّي استخدام أرقام إصدارات ديناميكية إلى إجراء تحديثات غير متوقّعة للإصدار وصعوبة في حلّ الاختلافات بين الإصدارات وبطء الإصدارات الناتجة عن بحث Gradle عن التحديثات. استخدِم أرقام إصدارات ثابتة بدلاً من ذلك.

إنشاء وحدات مكتبة

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

إنشاء مهام لمنطق تصميم مخصّص

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

ملاحظة: إذا كان إصدارك يتضمن عددًا كبيرًا من المهام المخصَّصة، قد تحتاج إلى تنظيم ملفات build.gradle من خلال إنشاء فئات مهام مخصّصة. أضِف صفوفك إلى دليل project-root/buildSrc/src/main/groovy/، علمًا بأنّ Gradle ستضم تلقائيًا هذه الفئات في مسار الفئة لجميع ملفات build.gradle في مشروعك.

تحويل الصور إلى تنسيق WebP

WebP هو تنسيق ملف صور يوفر ضغطًا مع فقدان البيانات (مثل JPEG) بالإضافة إلى شفافية (مثل PNG). يوفّر تنسيق WebP ضغطًا أفضل من تنسيق الملف بتنسيق JPEG أو PNG.

ويمكن أن يؤدي تقليل أحجام ملفات الصور بدون الحاجة إلى ضغط وقت الإصدار إلى تسريع الإصدارات، لا سيما إذا كان تطبيقك يستخدم الكثير من موارد الصور. مع ذلك، قد تلاحظ زيادة بسيطة في استخدام وحدة المعالجة المركزية (CPU) للجهاز عند فك ضغط صور WebP. استخدِم "استوديو Android" لتحويل صورك إلى تنسيق WebP بسهولة.

إيقاف تعديل ملفات PNG

في حال عدم تحويل صور PNG إلى تنسيق WebP، يمكنك تسريع عملية التصميم من خلال إيقاف ميزة "الضغط التلقائي للصور" في كل مرة يتم فيها إنشاء تطبيقك.

إذا كنت تستخدم الإصدار 3.0.0 من برنامج Gradle المتوافق مع Android أو إصدارًا أحدث، يتم إيقاف معالجة ملفات PNG بشكل تلقائي لنوع الإصدار "تصحيح الأخطاء". لإيقاف هذا التحسين مع أنواع الإصدارات الأخرى، أضِف ما يلي إلى ملف build.gradle:

رائع

android {
    buildTypes {
        release {
            // Disables PNG crunching for the "release" build type.
            crunchPngs false
        }
    }
}

Kotlin

android {
    buildTypes {
        getByName("release") {
            // Disables PNG crunching for the "release" build type.
            isCrunchPngs = false
        }
    }
}

بما أنّ أنواع الإصدارات أو نكهات المنتجات لا تحدّد هذه السمة، عليك ضبط هذه السمة يدويًا على true عند إنشاء إصدار الإصدار من تطبيقك.

إجراء التجارب باستخدام أداة تجميع البيانات المهملة المتوازية مع JVM

يمكن تحسين أداء الإصدار من خلال ضبط أداة تجميع البيانات المهملة JVM المثالية التي يستخدمها Gradle. تم إعداد جهاز JDK 8 لاستخدام أداة تجميع البيانات المهملة الموازية بشكل تلقائي، بينما تم ضبط الإصدار 9 من نظام التشغيل JDK والإصدارات الأحدث لاستخدام أداة تجميع البيانات المهملة G1.

لتحسين أداء الإصدار، ننصحك باختبار إصدارات Gradle باستخدام أداة تجميع النفايات الموازية. في gradle.properties، اضبط ما يلي:

org.gradle.jvmargs=-XX:+UseParallelGC

في حال كانت هناك خيارات أخرى تم ضبطها من قبل في هذا الحقل، أضِف خيارًا جديدًا:

org.gradle.jvmargs=-Xmx1536m -XX:+UseParallelGC

لقياس سرعة الإصدار باستخدام إعدادات مختلفة، يمكنك مراجعة إنشاء ملف شخصي على إصدارك.

زيادة حجم أجزاء JVM

إذا لاحظت إصدارات بطيئة، وتستغرق عملية جمع البيانات المهملة على وجه الخصوص أكثر من 15% من وقت الإنشاء في نتائج أداة تحليل الإصدارات، يجب عندها زيادة حجم كومة الذاكرة المؤقتة لجهاز Java الافتراضي (JVM). في ملف gradle.properties، اضبط الحدّ على 4 أو 6 أو 8 غيغابايت كما هو موضّح في المثال التالي:

org.gradle.jvmargs=-Xmx6g

ثم اختبر تحسين سرعة الإصدار. إنّ أسهل طريقة لتحديد حجم كومة الذاكرة المؤقتة المثالي هي زيادة الحدّ المسموح به بمقدار قليل، ثم إجراء اختبار لتحسين سرعة الإصدار بشكل كافٍ.

إذا كنت تستخدم أيضًا أداة تجميع البيانات المهملة المتوازية JVM، من المفترض أن يبدو الخط بالكامل على النحو التالي:

org.gradle.jvmargs=-Xmx6g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:+UseParallelGC -XX:MaxMetaspaceSize=1g

يمكنك تحليل أخطاء ذاكرة JVM من خلال تفعيل العلامة HeapDumpOnOutOfMemoryError. وبذلك، سينشئ جهاز JVM تفريغًا للذاكرة عند نفاد الذاكرة.

استخدام فئات R غير المتعددة

يمكنك استخدام فئات R غير انتقالية للحصول على إصدارات أسرع للتطبيقات التي تحتوي على وحدات متعددة. يساعد إجراء ذلك في منع تكرار الموارد من خلال التأكّد من أنّ كل فئة R في كل وحدة تحتوي فقط على مراجع لمواردها الخاصة بدون سحب المراجع من تبعياتها. يؤدي هذا إلى إصدارات أسرع والفوائد المقابلة لتجنب التجميع. وهذا هو السلوك التلقائي في الإصدار 8.0.0 من المكوّن الإضافي لنظام Gradle المتوافق مع Android والإصدارات الأحدث.

بدءًا من الإصدار Android Studio Bumblebee، يتم تلقائيًا تفعيل صفوف R غير الانتقالية للمشاريع الجديدة. بالنسبة إلى المشاريع التي تم إنشاؤها باستخدام إصدارات سابقة من "استوديو Android"، عليك تعديلها لاستخدام صفوف R غير الانتقالية من خلال الانتقال إلى Refactor > Migrate to non-Transitive R Classs.

لمزيد من المعلومات عن موارد التطبيقات وصف R، يمكنك الاطّلاع على نظرة عامة على موارد التطبيقات.

استخدام فئات R غير الثابتة

استخدِم حقول فئة R غير ثابتة في التطبيقات والاختبارات لتحسين تزايد تجميع Java والسماح بتقليص الموارد بدقة أكبر. تكون حقول فئة R غير ثابتة دائمًا للمكتبات، حيث يتم ترقيم الموارد عند إنشاء حزمة APK للتطبيق أو الاختبار الذي يعتمد على تلك المكتبة. وهذا هو السلوك التلقائي في الإصدار 8.0.0 من المكوّن الإضافي لنظام Gradle المتوافق مع Android والإصدارات الأحدث.

إيقاف علامة Jetifier

وبما أنّ معظم المشاريع تستخدم مكتبات AndroidX مباشرةً، يمكنك إزالة علامة Jetifier للحصول على أداء أفضل للإصدار. لإزالة علامة Jetifier، عليك ضبط android.enableJetifier=false في ملف gradle.properties.

يمكن لأداة "تحليل الإصدار" إجراء فحص لمعرفة ما إذا كان يمكن إزالة العلامة بأمان لكي يحصل مشروعك على أداء أفضل في الإصدار والابتعاد عن مكتبات دعم Android التي لا تخضع للصيانة. لمعرفة المزيد من المعلومات حول "أداة تحليل الإصدارات"، يُرجى الاطّلاع على القسم تحديد مشاكل أداء الإصدار وحلّها.

استخدام ذاكرة التخزين المؤقت للإعدادات

تتيح ذاكرة التخزين المؤقت للإعدادات لمنصة Gradle تسجيل المعلومات المتعلقة بالرسم البياني لمهام الإصدار وإعادة استخدامه في الإصدارات اللاحقة، كي لا تضطر خدمة Gradle إلى إعادة ضبط الإصدار بأكمله من جديد.

لتمكين ذاكرة التخزين المؤقت للإعدادات، اتبع الخطوات التالية:

  1. تحقق من توافق جميع المكونات الإضافية للمشروع.

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

  2. أضِف الرمز التالي إلى ملف gradle.properties:

      org.gradle.configuration-cache=true
      # Use this flag carefully, in case some of the plugins are not fully compatible.
      org.gradle.configuration-cache.problems=warn

عندما تكون ذاكرة التخزين المؤقت للإعدادات مفعّلة، تعرض مخرجات الإصدار Calculating task graph as no configuration cache is available for tasks في المرة الأولى التي تشغّل فيها مشروعك. أثناء عمليات التشغيل اللاحقة، يعرض ناتج الإصدار Reusing configuration cache.

لمعرفة المزيد من المعلومات عن ذاكرة التخزين المؤقت للإعدادات، يمكنك الاطّلاع على مشاركة المدونة مراجعة تفصيلية للتخزين المؤقت للإعدادات ومستندات Gradle حول ذاكرة التخزين المؤقت للإعدادات.

طرح مشاكل في ذاكرة التخزين المؤقت للإعدادات في الإصدار 8.1 من Gradle والإصدار 8.1 من برنامج Gradle المتوافق مع Android

أصبحت ذاكرة التخزين المؤقت للإعدادات مستقرة في الإصدار 8.1 من Gradle ووفّرت ميزة تتبُّع واجهة برمجة التطبيقات للملفات. يتم تسجيل المكالمات مثل File.exists() وFile.isDirectory() وFile.list() من خلال Gradle لتتبُّع ملفات إدخال الإعدادات.

يستخدم المكوّن الإضافي Android Gradle Plugin (AGP) 8.1 واجهات برمجة التطبيقات File هذه لبعض الملفات التي يجب ألا يعتبرها Gradle مدخلات في ذاكرة التخزين المؤقت. يؤدي ذلك إلى حدوث إبطال إضافي لذاكرة التخزين المؤقت عند استخدامها مع Gradle 8.1 والإصدارات الأحدث، ما يؤدي إلى إبطاء أداء الإصدار. يتم التعامل مع ما يلي كمدخلات ذاكرة التخزين المؤقت في 8.1 AGP:

إدخال أداة تتبع المشكلات ثابت في
$GRADLE_USER_Home/android/FakeBasedency.jar المشكلة رقم 289232054 8.2 جنيه مصري
إخراج cmake المشكلة رقم 287676077 8.2 جنيه مصري
$GRADLE_USER_home/.android/analytics.settings المشكلة رقم 278767328 8.3 جنيه مصري

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