بصفتك مؤلف مكتبة، عليك التأكّد من أنّه يمكن لمطوّري التطبيقات دمج مكتبتك بسهولة في تطبيقاتهم مع الحفاظ على تجربة مستخدم نهائية عالية الجودة. يعني ذلك أنّ مكتبتك يجب أن تكون متوافقة مع تحسين Android (R8) بدون أن يطلب المطوّر إعدادات إضافية، أو يجب توثيق أنّ المكتبة قد تكون غير مناسبة للاستخدام على Android. من المهم ألا تمنع المكتبات المخصّصة للاستخدام على Android عمليات التحسين المهمة للتطبيقات ، وأن تلتزم بمتطلبات التحسين الإضافية.
هذه الوثائق موجَّهة لمطوّري المكتبات المنشورة، ولكنها قد تكون مفيدة أيضًا لمطوّري وحدات المكتبات الداخلية في تطبيق كبير ومجزّأ.
إذا كنت مطوّر تطبيقات وأردت التعرّف على كيفية تحسين تطبيق Android الخاص بك، يُرجى الاطّلاع على مقالة تفعيل تحسين التطبيقات. للتعرّف على المكتبات المناسبة للاستخدام، يُرجى الاطّلاع على مقالة اختيار المكتبات بحكمة.
التعرّف على أنواع قواعد الاحتفاظ
يتوفّر نوعان مختلفان من قواعد الاحتفاظ التي يمكنك استخدامها في المكتبات:
- يجب أن تحدّد قواعد الاحتفاظ الخاصة بالمستهلك القواعد التي تحتفظ بأي محتوى تعرضه المكتبة. إذا كانت المكتبة تستخدم الانعكاس أو JNI للوصول إلى الرمز البرمجي الخاص بها أو الرمز البرمجي الذي يحدّده تطبيق العميل، يجب أن تصف هذه القواعد الرمز البرمجي الذي يجب الاحتفاظ به. يجب أن تجمّع المكتبات قواعد الاحتفاظ الخاصة بالمستهلك، التي تستخدم التنسيق نفسه لقواعد الاحتفاظ الخاصة بالتطبيقات. يتم تجميع هذه القواعد في عناصر المكتبة (ملفات AAR أو JAR) ويتم استخدامها تلقائيًا أثناء تحسين تطبيق Android عند استخدام المكتبة. يتم الاحتفاظ بهذه القواعد في الـ
ملف المحدّد باستخدام السمة
consumerProguardFilesفي الـbuild.gradle.kts(أوbuild.gradle) ملف. لمزيد من المعلومات، يُرجى الاطّلاع على قسم اقتراحات إضافية. - يتم تطبيق قواعد الاحتفاظ الخاصة بإصدار المكتبة عند إنشاء مكتبتك. ولا تكون هذه القواعد ضرورية إلا إذا قرّرت تحسين مكتبتك جزئيًا في وقت الإنشاء. يجب أن تحتفظ هذه القواعد بواجهة برمجة التطبيقات العامة للمكتبة من الإزالة، وإلا لن تظهر واجهة برمجة التطبيقات العامة في توزيع المكتبة، ما يعني أنّه لا يمكن لمطوّري التطبيقات استخدام المكتبة. يتم الاحتفاظ بهذه القواعد في الملف
المحدّد باستخدام السمة
proguardFilesفي ملفbuild.gradle.kts(أوbuild.gradle). لمزيد من المعلومات، يُرجى الاطّلاع على مقالة تحسين إصدار مكتبة AAR.
المتطلبات والإرشادات المتعلّقة بالتحسين
يؤثر إعداد R8 في المكتبات بشكل عام على حجم الملف الثنائي النهائي وأداء التطبيق المستخدِم. بالإضافة إلى أفضل الممارسات العامة لقواعد الاحتفاظ ، على مؤلفي المكتبات الالتزام بمتطلبات معيّنة ومراعاة إرشادات إضافية.
الالتزام بمتطلبات التحسين
يُعدّ عدم كفاءة المكتبات عاملاً رئيسيًا في تضخّم التطبيقات والذاكرة المهدرة وبطء عمليات بدء التشغيل وأخطاء "التطبيق لا يستجيب" (ANR). يجب ألا تنتهك المكتبات المتطلبات التالية لتجنُّب تقليل جودة التطبيق وتجربة المستخدم بشكل كبير.
عدم استخدام قواعد احتفاظ واسعة النطاق أو على مستوى الحزمة: يجب ألا تتضمّن مكتبتك قواعد احتفاظ واسعة النطاق تحتفظ بمعظم الرمز البرمجي في مكتبتك أو في مكتبة أخرى. قد تحلّ قواعد الاحتفاظ الواسعة النطاق حالات الأعطال على المدى القصير، ولكنها تزيد من حجم التطبيق لجميع التطبيقات التي تستخدم مكتبتك.
يُرجى عدم تضمين قواعد احتفاظ على مستوى الحزمة (مثل
-keep class com.mylibrary.** {*; }) للحِزم في مكتبتك أو المكتبات الأخرى التي تتم الإشارة إليها. تحدّ هذه القواعد من تحسين هذه الحِزم في جميع التطبيقات التي تستخدم مكتبتك.عدم استخدام قواعد عامة غير مناسبة: لا تستخدم أبدًا الخيارات العامة مثل
-dontobfuscateأو-allowaccessmodification.استخدام إنشاء الرمز البرمجي بدلاً من الانعكاس كلما أمكن: استخدِم إنشاء الرمز البرمجي (codegen) بدلاً من الانعكاس كلما أمكن. يُعدّ كل من إنشاء الرمز البرمجي والانعكاس من الأساليب الشائعة لتجنُّب رمز النص النموذجي أثناء البرمجة، ولكنّ إنشاء الرمز البرمجي أكثر توافقًا مع أداة تحسين التطبيقات، مثل R8.
باستخدام إنشاء الرمز البرمجي، يتم تحليل الرمز البرمجي وتعديله أثناء عملية التصميم. بما أنّه لا يتم إجراء أي تعديلات كبيرة بعد وقت التجميع، تعرف أداة التحسين الرمز البرمجي المطلوب في النهاية والرمز البرمجي الذي يمكن إزالته بأمان.
باستخدام الانعكاس، يتم تحليل الرمز البرمجي ومعالجته في وقت التشغيل. بما أنّه لا يتم الانتهاء من الرمز البرمجي فعليًا إلى أن يتم تنفيذه، لا تعرف أداة التحسين الرمز البرمجي الذي يمكن إزالته بأمان. من المرجّح أن تزيل أداة التحسين الرمز البرمجي الذي يتم استخدامه ديناميكيًا من خلال الانعكاس أثناء وقت التشغيل، ما يؤدي إلى حدوث أعطال في التطبيق لدى المستخدمين.
تستخدم العديد من المكتبات الحديثة إنشاء الرمز البرمجي بدلاً من الانعكاس. يُرجى الاطّلاع على KSP للحصول على نقطة دخول شائعة تستخدمها Room، Hilt، والعديد من المكتبات الأخرى.
توفير الدعم للوضع الكامل في R8: يجب ألا يتعطّل تطبيقك عند تفعيل الوضع الكامل في R8. الوضع الكامل في R8 هو الوضع المقترَح لاستخدام R8، وهو الوضع التلقائي منذ الإصدار 8.0 من المكوّن الإضافي لنظام Gradle المتوافق مع Android (AGP)، الذي أصبح مستقرًا في عام 2023. إذا تعطلت مكتبتك في R8، يكون الحلّ هو تحديد نقطة دخول الانعكاس أو JNI المحدّدة وإضافة قاعدة مستهدَفة، وليس الاحتفاظ بالحزمة بأكملها.
اقتراحات إضافية
بالإضافة إلى متطلبات التحسين، إليك اقتراحات إضافية:
- لا تستخدِم
-repackageclassesفي ملف قواعد الاحتفاظ الخاصة بالمستهلك في مكتبتك. ومع ذلك، لتحسين إصدار مكتبتك، يمكنك استخدام-repackageclassesمع اسم حزمة داخلية، مثل<your.library.package>.internal، في ملف قواعد الاحتفاظ الخاصة بإصدار مكتبتك. يمكن أن يؤدي ذلك إلى تحسين كفاءة مكتبتك في التطبيقات غير المحسَّنة. ومع ذلك، ليس ذلك ضروريًا بشكل عام، لأنّه يجب أيضًا تحسين التطبيقات. - أفصِح عن أي سمات تحتاج إليها لكي تعمل مكتبتك في ملفات قواعد الاحتفاظ الخاصة بمكتبتك، حتى إذا كان هناك تداخل مع السمات المحدّدة في
proguard-android-optimize.txt. - إذا كنت بحاجة إلى السمات التالية في توزيع مكتبتك، احتفِظ بها في ملف قواعد الاحتفاظ الخاصة بإصدار مكتبتك، وليس في ملف قواعد الاحتفاظ الخاصة بالمستهلك في مكتبتك:
AnnotationDefaultEnclosingMethodExceptionsInnerClassesRuntimeInvisibleAnnotationsRuntimeInvisibleParameterAnnotationsRuntimeInvisibleTypeAnnotationsRuntimeVisibleAnnotationsRuntimeVisibleParameterAnnotationsRuntimeVisibleTypeAnnotationsSignature
- على مؤلفي المكتبات الاحتفاظ بالسمة
RuntimeVisibleAnnotationsفي قواعد الاحتفاظ الخاصة بالمستهلك إذا تم استخدام التعليقات التوضيحية في وقت التشغيل. - على مؤلفي المكتبات عدم استخدام الخيارات العامة التالية في قواعد الاحتفاظ الخاصة بالمستهلك:
-include-basedirectory-injars-outjars-libraryjars-repackageclasses-flattenpackagehierarchy-allowaccessmodification-renamesourcefileattribute-ignorewarnings-addconfigurationdebugging-printconfiguration-printmapping-printusage-printseeds-applymapping-obfuscationdictionary-classobfuscationdictionary-packageobfuscationdictionary
الحالات التي يكون فيها استخدام الانعكاس مناسبًا
إذا كان عليك استخدام الانعكاس، يجب أن يكون ذلك فقط في أيّ من الحالتَين التاليتَين:
- أنواع مستهدَفة معيّنة (منفّذو واجهة معيّنة أو فئات فرعية معيّنة)
- الرمز البرمجي الذي يستخدم تعليقًا توضيحيًا معيّنًا في وقت التشغيل
يحدّ استخدام الانعكاس بهذه الطريقة من تكلفة وقت التشغيل، ويتيح كتابة قواعد احتفاظ مستهدَفة للمستهلك.
هذا الشكل المحدّد والمستهدَف من الانعكاس هو نمط يمكنك ملاحظته في كل من
إطار عمل Android (على سبيل المثال، أثناء تحميل موارد النظام)
ومكتبات AndroidX (على سبيل المثال، عند إنشاء WorkManager
ListenableWorkers أو RoomDatabases). في المقابل، لا يكون الانعكاس المفتوح
من Gson مناسبًا للاستخدام في تطبيقات Android.
الأفكار الخاطئة الشائعة
قد تؤدي بعض الأفكار الخاطئة الشائعة إلى إعداد R8 بشكل غير صحيح. وتشمل هذه الأفكار ما يلي:
فهم غير صحيح لعمليات التحسين في R8: على عكس ما هو شائع، لا تقتصر عمليات التحسين في R8 على التعتيم فقط، بل تشمل أيضًا تخفيض حجم الرموز والتحسينات المنطقية باستخدام تقنيات تضمين الطرق ودمج الفئات. لمزيد من المعلومات، يُرجى الاطّلاع على مقالة نظرة عامة على تحسين R8.
تجاوز تحسين المكتبات المعتمة: من الأخطاء الشائعة عدم تحسين مكتبة لأنّه تم تحسينها أو تعتيمها عند تجميعها في ملف AAR (أرشيف Android) أو JAR (أرشيف Java ). تكون عمليات التحسين أثناء مدّة تصميم المكتبة محدودة، ويجب ألا يوقف تطبيقك تحسين المكتبة من خلال تضمينها في قاعدة احتفاظ. لمزيد من المعلومات، يُرجى الاطّلاع على مقالة نظرة عامة على تحسين R8.
فهم غير صحيح للخيار
-keepتمنع قاعدة-keepأداة R8 من تشغيل أي من مراحل التحسين. لمزيد من المعلومات، يُرجى الاطّلاع على مقالة اختيار خيار الاحتفاظ المناسب.
التحقّق من جودة قواعد الاحتفاظ الخاصة بالمستهلك
للتحقّق من أنّ مكتبتك لا تمنع تحسين الكثير من الرمز البرمجي عند تضمينها في تطبيق، استخدِم نموذج مكتبة أو تطبيق اختبار التكامل. فعِّل R8، وافحص الجودة العامة لإعداد R8 في التطبيق باستخدام أداة R8 Configuration Analyzer.
إذا تبيّن أنّ قواعد المستهلك تحدّ من التحسين في أجزاء كبيرة من الرمز البرمجي لمكتبتك، يشير ذلك إلى أنّ قواعد المستهلك بحاجة إلى تحسين. ضيِّق نطاق قواعد المستهلك واختبِر أي جوانب متأثرة من مكتبتك في تطبيق تم تفعيل R8 فيه.
إعداد تجميع القواعد
لضمان تطبيق قواعد الاحتفاظ الخاصة بالمستهلك بشكل صحيح، عليك تجميعها بشكل مناسب حسب تنسيق مكتبتك.
مكتبات AAR
لإضافة قواعد المستهلك لمكتبة 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، ضَع ملف قواعد المستهلك في <libraryroot>/src/main/resources/META-INF/proguard/consumer-proguard-rules.pro
وسيتم تجميع القواعد في الموقع الصحيح في ملف JAR الناتج.
تأكَّد من أنّ ملف JAR النهائي يجمّع القواعد بشكل صحيح من خلال التحقّق من أنّ القواعد موجودة في الدليل META-INF/proguard.
تحسين إصدار مكتبة AAR (متقدّم)
بشكل عام، ليس عليك تحسين إصدار مكتبة مباشرةً لأنّ عمليات التحسين المحتمَلة في مدّة تصميم المكتبة محدودة جدًا. بصفتك مطوّر مكتبة، عليك التفكير في مراحل التحسين وسلوك الاحتفاظ المتعددة، سواء في مدّة تصميم المكتبة أو التطبيق، قبل تحسين هذه المكتبة.
إذا كنت لا تزال تريد تحسين مكتبتك في مدّة التصميم، يتيح لك المكوّن الإضافي لنظام Gradle المتوافق مع Android (AGP) ذلك.
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'.
تحسين أداء واجهة مستخدم Compose
إذا كانت مكتبتك تتضمّن مكوّنات واجهة مستخدم Compose، يمكنك تحسينها لكل من تقليص البرنامج الثنائي باستخدام R8 (كما هو موضّح سابقًا) وكفاءة إعادة التكوين:
- تصميم عناصر قابلة للإنشاء مستقرة: للسماح للمجمّع بتخطّي العناصر القابلة للإنشاء بأمان عندما لم تتغيّر الإدخالات، يمكنك تنظيم نماذج البيانات وإعدادات المكتبة لاتباع قواعد الاستقرار. لمزيد من المعلومات، يُرجى الاطّلاع على مقالة الاستقرار في Compose.
- مراجعة مقاييس المجمّع: استخدِم مقاييس مجمّع Compose للتحقّق من وضع علامة "قابلة لإعادة التشغيل" و"قابلة للتخطّي" على نقاط دخول مكتبتك. يقلّل ذلك من تكلفة إعادة التركيب للتطبيقات المستخدِمة. لمزيد من المعلومات، يُرجى الاطّلاع على مقالة تشخيص مشاكل الاستقرار.
توفير الدعم لإصدارات مختلفة من 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 من 8.0.0 إلى 8.2.0 باستثناء الإصدار 8.2.0 استخدام القواعد ضمن الدليل r8-from-8.0.0-upto-8.2.0.
يستخدم المكوّن الإضافي لنظام Gradle المتوافق مع Android (AGP) هذه المعلومات لاختيار جميع القواعد التي يمكن استخدامها من خلال إصدار R8 الحالي. إذا لم تحدّد مكتبة قواعد R8
المستهدَفة، سيختار المكوّن الإضافي لنظام Gradle المتوافق مع Android (AGP) القواعد من المواقع القديمة
(proguard.txt لملف AAR أو META-INF/proguard/<ProGuard-rule-files> لملف
JAR).