التحسين لمؤلفي المكتبات

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

تستهدف هذه المستندات مطوّري المكتبات المنشورة، ولكنها قد تكون مفيدة أيضًا لمطوّري وحدات المكتبات الداخلية في تطبيق كبير ومكوّن من وحدات.

إذا كنت مطوّر تطبيقات وتريد التعرّف على كيفية تحسين تطبيق Android، اطّلِع على مقالة تفعيل ميزة تحسين التطبيقات. للتعرّف على المكتبات المناسبة للاستخدام، اطّلِع على مقالة اختيار المكتبات بحكمة.

استخدام codegen بدلاً من Reflection

استخدِم إنشاء الرموز البرمجية (codegen) بدلاً من ميزة "العرض المطابق" كلما أمكن. إنّ إنشاء الرموز البرمجية والتفكير في الرمز البرمجي هما من الأساليب الشائعة لتجنُّب استخدام رمز برمجي عادي عند البرمجة، ولكنّ إنشاء الرموز البرمجية أكثر توافقًا مع أدوات تحسين التطبيقات، مثل R8:

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

تستخدم العديد من المكتبات الحديثة codegen بدلاً من ميزة التأمل. اطّلِع على العامل الترويجي الرئيسي (KSP) لمعرفة نقطة دخول شائعة يستخدمها Room وDagger2 وغيرها الكثير.

الحالات التي تكون فيها الانعكاسات مقبولة

إذا كان عليك استخدام ميزة "الانعكاس"، يجب عدم استخدامها إلا في أيّ من المحتوى التالي:

  • أنواع مستهدَفة محدّدة (منفّذو الواجهات أو الفئات الفرعية المحدّدة)
  • رمز يستخدم تعليقًا توضيحيًا محدّدًا لوقت التشغيل

يؤدي استخدام ميزة "العرض المرجعي" بهذه الطريقة إلى الحد من تكلفة وقت التشغيل، ويتيح كتابة قواعد الاحتفاظ بالمستهلكين المستهدَفين.

هذا الشكل المحدّد والمستهدف من التوسّع هو نمط يمكنك مشاهدته في كلٍّ من إطار عمل Android (على سبيل المثال، عند تضخيم الأنشطة وعناصر العرض والعناصر القابلة للرسم) ومكتبات AndroidX (على سبيل المثال، عند إنشاء WorkManager ListenableWorkers أو RoomDatabases). في المقابل، فإنّ المعالجة المفتوحة لملف برمجي Gson غير مناسبة للاستخدام في تطبيقات Android.

كتابة قواعد الاحتفاظ بالبيانات للمستهلك

يجب أن تحزِّم المكتبات قواعد الاحتفاظ ببيانات "المستهلك" التي تستخدم التنسيق نفسه المستخدَم في قواعد الاحتفاظ ببيانات التطبيقات. ويتم تجميع هذه القواعد في عناصر المكتبة (ملفّات AAR أو JAR) ويتم استخدامها تلقائيًا أثناء تحسين تطبيقات Android عند استخدام المكتبة.

مكتبات ميزة "الاقتراحات المطبّقة تلقائيًا"

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

Kotlin

android {
    defaultConfig {
        consumerProguardFiles("consumer-proguard-rules.pro")
    }
    ...
}

رائع

android {
    defaultConfig {
        consumerProguardFiles 'consumer-proguard-rules.pro'
    }
    ...
}

مكتبات JAR

لتجميع القواعد مع مكتبة Kotlin/Java التي يتم شحنها كملف JAR، ضَع ملف القواعد في الدليل META-INF/proguard/ لملف JAR النهائي، مع أي اسم ملف. على سبيل المثال، إذا كان الرمز البرمجي في <libraryroot>/src/main/kotlin، ضَع ملف consumer rules في <libraryroot>/src/main/resources/META-INF/proguard/consumer-proguard-rules.pro وسيتم تجميع القواعد في الموقع الصحيح في حزمة JAR الناتجة.

تأكَّد من أنّ حِزم JAR النهائية تُجمِّع القواعد بشكل صحيح من خلال التحقّق من أنّ القواعد في الدليل META-INF/proguard.

تحسين عملية إنشاء مكتبة AAR (متقدّمة)

بشكل عام، يجب عدم تحسين إصدار مكتبة مباشرةً لأنّه يمكن إجراء عدد محدود جدًا من التحسينات في وقت إنشاء المكتبة. لا يمكن لـ IDE R8 معرفة كيفية استخدام جميع طرق المكتبة والمَعلمات التي يتم تمريرها إلا أثناء ملف APK للتطبيق، عندما يتم تضمين مكتبة كجزء من التطبيق. بصفتك مطوّر مكتبة، عليك التفكير في مراحل متعددة من التحسين والحفاظ على السلوك، سواء في وقت إنشاء المكتبة أو التطبيق، قبل تحسين هذه المكتبة.

إذا كنت لا تزال تريد تحسين مكتبتك في وقت التصميم، يتيح المكوّن الإضافي لنظام Gradle المتوافق مع Android إجراء ذلك.

Kotlin

android {
    buildTypes {
        release {
            isMinifyEnabled = true
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
        configureEach {
            consumerProguardFiles("consumer-rules.pro")
        }
    }
}

رائع

android {
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles
                getDefaultProguardFile('proguard-android-optimize.txt'),
                'proguard-rules.pro'
        }
        configureEach {
            consumerProguardFiles "consumer-rules.pro"
        }
    }
}

يُرجى العلم أنّ سلوك proguardFiles يختلف كثيرًا عن consumerProguardFiles:

  • يتم استخدام proguardFiles في وقت الإنشاء، غالبًا مع getDefaultProguardFile("proguard-android-optimize.txt")، لتحديد الجزء من مكتبتك الذي يجب الاحتفاظ به أثناء إنشاء المكتبة. على الأقل، يجب أن يكون هذا هو واجهة برمجة التطبيقات المتاحة للجميع.
  • في المقابل، يتم تجميع consumerProguardFiles في المكتبة لتأثيرها في التحسينات التي يتم إجراؤها لاحقًا أثناء إنشاء تطبيق يستخدِم مكتبتك.

على سبيل المثال، إذا كانت مكتبتك تستخدِم ميزة "العرض المرجعي" لإنشاء فئات داخلية، قد تحتاج إلى تحديد قواعد الاحتفاظ في كلّ من proguardFiles و consumerProguardFiles.

إذا كنت تستخدم -repackageclasses في إصدار مكتبتك، أعِد تجميع الفصول الدراسية في حزمة فرعية داخل حزمة مكتبتك. على سبيل المثال، استخدِم -repackageclasses 'com.example.mylibrary.internal' بدلاً من -repackageclasses 'internal'.

إتاحة إصدارات مختلفة من R8 (متقدم)

يمكنك تخصيص القواعد لاستهداف إصدارات معيّنة من R8. يتيح ذلك لمكتبتك العمل على النحو الأمثل في المشاريع التي تستخدم إصدارات R8 أحدث، مع السماح باستمرار استخدام القواعد الحالية في المشاريع التي تستخدم إصدارات R8 أقدم.

لتحديد قواعد R8 المستهدَفة، عليك تضمينها في دليل META-INF/com.android.tools داخل classes.jar من ملف AAR أو في دليل META-INF/com.android.tools من ملف JAR.

In an AAR library:
    proguard.txt (legacy location, the file name must be "proguard.txt")
    classes.jar
    └── META-INF
        └── com.android.tools (location of targeted R8 rules)
            ├── r8-from-<X>-upto-<Y>/<R8-rule-files>
            └── ... (more directories with the same name format)

In a JAR library:
    META-INF
    ├── proguard/<ProGuard-rule-files> (legacy location)
    └── com.android.tools (location of targeted R8 rules)
        ├── r8-from-<X>-upto-<Y>/<R8-rule-files>
        └── ... (more directories with the same name format)

في الدليل META-INF/com.android.tools، يمكن أن يكون هناك عدة أدلة فرعية بأسماء على شكل r8-from-<X>-upto-<Y> للإشارة إلى إصدارات R8 التي تمّت كتابة القواعد لها. يمكن أن يحتوي كل دليل فرعي على ملف واحد أو أكثر يحتوي على قواعد R8، مع أي أسماء ملفات وإمتدادات.

يُرجى العِلم أنّ الجزءَين -from-<X> و-upto-<Y> اختياريان، ويكون الإصدار <Y> حصريًا، وتكون نطاقات الإصدارات عادةً مستمرة، ولكن يمكنها أيضًا التداخل.

على سبيل المثال، r8 وr8-upto-8.0.0 وr8-from-8.0.0-upto-8.2.0 و r8-from-8.2.0 هي أسماء أدلة تمثّل مجموعة من قواعد R8 المستهدَفة. يمكن استخدام القواعد ضمن الدليل r8 من خلال أي إصدارات من R8. يمكن استخدام القواعد ضمن الدليل r8-from-8.0.0-upto-8.2.0 من الإصدار 8.0.0 إلى الإصدار 8.2.0 ولكن ليس بما في ذلك هذا الإصدار.

يستخدم المكوّن الإضافي لنظام Gradle المتوافق مع Android هذه المعلومات لاختيار جميع القواعد التي يمكن استخدامها من خلال الإصدار الحالي من R8. إذا لم تحدّد المكتبة قواعد R8 targeted ، سيختار المكوّن الإضافي لنظام Android Gradle القواعد من المواقع الجغرافية القديمة (proguard.txt لملف AAR أو META-INF/proguard/<ProGuard-rule-files> لملف JAR).