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

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

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

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

استخدام إنشاء الرموز البرمجية بدلاً من الانعكاس

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

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

تستخدم العديد من المكتبات الحديثة إنشاء الرموز بدلاً من الانعكاس. راجِع KSP للحصول على نقطة دخول شائعة تستخدمها Room وDagger2 وغيرها الكثير.

الحالات التي يكون فيها التفكير الذاتي مقبولاً

إذا كان عليك استخدام الانعكاس، يجب أن يكون ذلك في أحد الخيارين التاليين فقط:

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

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

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

أنواع قواعد الاحتفاظ بالبيانات في المكتبات

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

  • يجب أن تحدّد قواعد الاحتفاظ بالمحتوى لدى المستهلك القواعد التي تحتفظ بأي محتوى يتضمّنه المكتبة. إذا كانت إحدى المكتبات تستخدم الانعكاس أو JNI لاستدعاء الرمز البرمجي الخاص بها أو الرمز البرمجي الذي يحدّده تطبيق العميل، يجب أن تصف هذه القواعد الرمز البرمجي الذي يجب الاحتفاظ به. يجب أن تتضمّن المكتبات قواعد الاحتفاظ بالمستهلكين، والتي تستخدم التنسيق نفسه المستخدَم في قواعد الاحتفاظ بالتطبيقات. يتم تجميع هذه القواعد في عناصر مكتبة (ملفات AAR أو JAR)، ويتم استخدامها تلقائيًا أثناء تحسين تطبيق Android عند استخدام المكتبة. يتم الاحتفاظ بهذه القواعد في الملف المحدّد باستخدام السمة consumerProguardFiles في ملف build.gradle.kts (أو build.gradle). لمزيد من المعلومات، يُرجى الاطّلاع على كتابة قواعد الاحتفاظ بالبيانات الخاصة بالمستهلكين.
  • يتم تطبيق قواعد الاحتفاظ بإنشاء المكتبة عند إنشاء مكتبتك. ولا تحتاج إليها إلا إذا قرّرت تحسين مكتبتك جزئيًا في وقت الإنشاء. ويجب أن يمنعوا إزالة واجهة برمجة التطبيقات العامة للمكتبة، وإلا لن تكون واجهة برمجة التطبيقات العامة متوفرة في توزيع المكتبة، ما يعني أنّه لن يتمكّن مطوّرو التطبيقات من استخدام المكتبة. يتم الاحتفاظ بهذه القواعد في الملف المحدّد باستخدام السمة proguardFiles في ملف build.gradle.kts (أو build.gradle). لمزيد من المعلومات، يُرجى الاطّلاع على تحسين إنشاء مكتبة AAR.

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

بالإضافة إلى الإرشادات العامة حول قواعد الاحتفاظ بالبيانات، إليك بعض الاقتراحات المخصّصة لمؤلفي المكتبات.

  • لا تستخدِم قواعد عامة غير ملائمة، وتجنَّب وضع إعدادات عامة مثل -dontobfuscate أو -allowaccessmodification في ملف قواعد الاحتفاظ بالمستهلكين الخاص بمكتبتك، لأنّها تؤثّر في جميع التطبيقات التي تستخدم مكتبتك.
  • لا تستخدِم -repackageclasses في ملف قواعد الاحتفاظ بالمحتوى الخاص بالمستهلكين في مكتبتك. ومع ذلك، لتحسين عملية إنشاء المكتبة، يمكنك استخدام -repackageclasses مع اسم حزمة داخلي، مثل <your.library.package>.internal، في ملف قواعد الاحتفاظ بإنشاء المكتبة. ويمكن أن يؤدي ذلك إلى تحسين كفاءة المكتبة حتى إذا لم يتم تحسين التطبيقات التي تستهلكها، ولكن لا يكون ذلك ضروريًا بشكل عام لأنّه من المفترض أن يتم تحسين التطبيقات أيضًا. لمزيد من التفاصيل حول تحسين المكتبات، يُرجى الاطّلاع على تحسين المكتبات لمطوّريها.
  • عليك توضيح أي سمات تحتاج إليها لتعمل مكتبتك في ملفات قواعد الاحتفاظ الخاصة بمكتبتك، حتى إذا كان هناك تداخل مع السمات المحدّدة في proguard-android-optimize.txt.
  • إذا كنت بحاجة إلى السمات التالية في توزيع مكتبتك، احتفِظ بها في ملف قواعد الاحتفاظ في إصدار مكتبتك، وليس في ملف قواعد الاحتفاظ في إصدار مكتبتك المخصّص للمستهلكين:
    • AnnotationDefault
    • EnclosingMethod
    • Exceptions
    • InnerClasses
    • RuntimeInvisibleAnnotations
    • RuntimeInvisibleParameterAnnotations
    • RuntimeInvisibleTypeAnnotations
    • RuntimeVisibleAnnotations
    • RuntimeVisibleParameterAnnotations
    • RuntimeVisibleTypeAnnotations
    • Signature
  • على مطوّري المكتبات الاحتفاظ بالسمة RuntimeVisibleAnnotations في قواعد الاحتفاظ الخاصة بالمستهلكين إذا تم استخدام التعليقات التوضيحية في وقت التشغيل.
  • يجب ألا يستخدم مؤلفو المكتبات الخيارات العامة التالية في قواعد الاحتفاظ الخاصة بالمستهلكين:
    • -include
    • -basedirectory
    • -injars
    • -outjars
    • -libraryjars
    • -repackageclasses
    • -flattenpackagehierarchy
    • -allowaccessmodification
    • -overloadaggressively
    • -renamesourcefileattribute
    • -ignorewarnings
    • -addconfigurationdebugging
    • -printconfiguration
    • -printmapping
    • -printusage
    • -printseeds
    • -applymapping
    • -obfuscationdictionary
    • -classobfuscationdictionary
    • -packageobfuscationdictionary

مكتبات AAR

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

Kotlin

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

Groovy

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

مكتبات JAR

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

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

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

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

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

Kotlin

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

Groovy

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 بواسطة R8 من الإصدار 8.0.0 حتى الإصدار 8.2.0 باستثناء الإصدار 8.2.0.

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