لتفعيل تحسين التطبيق، يجب استخدام مكتبات متوافقة مع تحسين Android. إذا لم يتم ضبط إحدى المكتبات على تحسين Android، مثلاً إذا كانت تستخدم الانعكاس بدون تجميع قواعد الاحتفاظ المرتبطة بها، قد لا تكون مناسبة لتطبيق Android. توضّح هذه الصفحة سبب ملاءمة بعض المكتبات لتحسين التطبيقات، وتقدّم نصائح عامة لمساعدتك في الاختيار.
تفضيل إنشاء الرموز البرمجية على استخدام الانعكاس
بشكل عام، عليك اختيار المكتبات التي تستخدم إنشاء الرموز البرمجية (codegen) بدلاً من الانعكاس. باستخدام codegen، يمكن للمحسِّن تحديد الرمز البرمجي المستخدَم فعليًا أثناء وقت التشغيل والرمز البرمجي الذي يمكن إزالته بسهولة أكبر. قد يكون من الصعب معرفة ما إذا كانت المكتبة تستخدم إنشاء الرموز البرمجية أو الانعكاس، ولكن هناك بعض المؤشرات التي يمكن أن تساعدك، لذا راجِع النصائح.
لمزيد من المعلومات حول إنشاء الرموز البرمجية مقابل الانعكاس، يُرجى الاطّلاع على التحسين لمؤلفي المكتبات.
نصائح عامة عند اختيار المكتبات
استخدِم هذه النصائح للمساعدة في ضمان توافق مكتباتك مع ميزة "تحسين التطبيق".
التحقّق من مشاكل التحسين
عند التفكير في استخدام مكتبة جديدة، اطّلِع على أداة تتبُّع المشاكل في المكتبة والمناقشات على الإنترنت لمعرفة ما إذا كانت هناك مشاكل متعلقة بالتصغير أو ضبط إعدادات تحسين التطبيق. إذا كانت هناك بدائل، عليك محاولة البحث عنها. يُرجى مراعاة ما يلي:
- تعمل مكتبات AndroidX والمكتبات الأخرى، مثل Hilt، بشكل جيد مع تحسين التطبيقات لأنّها تستخدم إنشاء الرموز بدلاً من الانعكاس. وعند استخدامها، يقدّمون قواعد الحد الأدنى للاحتفاظ بالبيانات من أجل الاحتفاظ فقط بالرمز المطلوب.
- تستخدم مكتبات التسلسل بشكل متكرر ميزة "الانعكاس" لتجنُّب الرموز النموذجية عند إنشاء مثيل للكائنات أو تسلسلها. بدلاً من استخدام طرق تستند إلى الانعكاس (مثل Gson لملفات JSON)، ابحث عن مكتبات تستخدم إنشاء الرموز البرمجية لتجنُّب هذه المشاكل، مثلاً من خلال استخدام Kotlin Serialization.
- يجب تجنُّب المكتبات التي تتضمّن قواعد الاحتفاظ على مستوى الحزمة إذا أمكن ذلك. يمكن أن تساعد قواعد الاحتفاظ على مستوى الحزمة في حلّ الأخطاء، ولكن يجب في النهاية تحسين قواعد الاحتفاظ الواسعة النطاق للاحتفاظ فقط بالرمز البرمجي المطلوب. لمزيد من المعلومات، يُرجى الاطّلاع على تطبيق عمليات التحسين بشكل تدريجي.
- يجب ألا تتطلّب منك المكتبات نسخ قواعد الاحتفاظ بالبيانات ولصقها من المستندات في ملف في مشروعك، خاصةً قواعد الاحتفاظ بالبيانات على مستوى الحزمة. وتصبح هذه القواعد عبئًا على مطوّر التطبيق على المدى الطويل، كما يصعب تحسينها وتغييرها بمرور الوقت.
تفعيل التحسين بعد إضافة مكتبة جديدة
عند إضافة مكتبة جديدة، فعِّل ميزة التحسين بعد ذلك وتحقّق مما إذا كانت هناك أخطاء. في حال ظهور أخطاء، ابحث عن بدائل لهذه المكتبة أو اكتب قواعد الاحتفاظ. إذا كانت إحدى المكتبات غير متوافقة مع التحسين، يُرجى إرسال تقرير عن خطأ في هذه المكتبة.
القواعد ترافقية
يُرجى العِلم أنّ قواعد الاحتفاظ بالبيانات ترافقية. وهذا يعني أنّه لا يمكن إزالة بعض القواعد التي يتضمّنها عنصر تابع للمكتبة، وقد تؤثر هذه القواعد في تجميع أجزاء أخرى من تطبيقك. على سبيل المثال، إذا كانت إحدى المكتبات تتضمّن قاعدة لإيقاف تحسينات الرمز البرمجي، ستؤدي هذه القاعدة إلى إيقاف التحسينات في مشروعك بأكمله.
التحقّق من استخدام الانعكاس (ميزة متقدّمة)
قد تتمكّن من معرفة ما إذا كانت إحدى المكتبات تستخدم الانعكاس من خلال فحص الرمز البرمجي الخاص بها. إذا كانت المكتبة تستخدم الانعكاس، تأكَّد من أنّها توفّر قواعد الاحتفاظ المرتبطة. من المحتمل أن تستخدم إحدى المكتبات ميزة الانعكاس إذا كانت تفعل ما يلي:
- يستخدم فئات أو طرقًا من حزمتَي
kotlin.reflectأوjava.lang.reflect - يستخدم الدالتَين
Class.forNameأوclassLoader.getClass - تقرأ التعليقات التوضيحية في وقت التشغيل، مثلاً إذا كانت تخزّن قيمة تعليق توضيحي باستخدام
val value = myClass.getAnnotation()أوval value = myMethod.getAnnotation()ثم تنفّذ إجراءً باستخدامvalue يتم استدعاء الطرق باستخدام اسم الطريقة كسلسلة، على سبيل المثال:
// Calls the private `processData` API with reflection myObject.javaClass.getMethod("processData", DataType::class.java) ?.invoke(myObject, data)
فلترة قواعد الاحتفاظ غير الصالحة (متقدّمة)
يجب تجنُّب المكتبات التي تتضمّن قواعد إبقاء تحتفظ برمز برمجي يجب إزالته. ولكن إذا كان عليك استخدامها، يمكنك فلترة القواعد كما هو موضّح في الرمز التالي:
// If you're using AGP 8.4 and higher
buildTypes {
release {
optimization.keepRules {
it.ignoreFrom("com.somelibrary:somelibrary")
}
}
}
// If you're using AGP 7.3-8.3
buildTypes {
release {
optimization.keepRules {
it.ignoreExternalDependencies("com.somelibrary:somelibrary")
}
}
}
دراسة حالة: لماذا يتعطّل Gson عند إجراء تحسينات؟
Gson هي مكتبة تسلسل غالبًا ما تتسبّب في حدوث مشاكل في تحسين التطبيق لأنّها تستخدم الانعكاس بشكل كبير. يوضّح مقتطف الرمز التالي كيفية استخدام Gson عادةً، ما قد يؤدي بسهولة إلى حدوث أعطال أثناء وقت التشغيل. لاحظ أنّه عند استخدام Gson للحصول على قائمة بعناصر User، لن تحتاج إلى استدعاء الدالة الإنشائية أو تمرير مصنع إلى الدالة fromJson(). إنّ إنشاء فئات يحدّدها التطبيق أو استخدامها بدون أي مما يلي يشير إلى أنّ إحدى المكتبات قد تستخدم انعكاسًا مفتوحًا:
- فئة التطبيق التي تنفّذ مكتبة أو واجهة أو فئة عادية
- مكوّن إضافي لإنشاء الرموز البرمجية، مثل KSP
class User(val name: String)
class UserList(val users: List<User>)
// This code runs in debug mode, but crashes when optimizations are enabled
Gson().fromJson("""[{"name":"myname"}]""", User::class.java).toString()
عندما يحلّل R8 هذا الرمز البرمجي ولا يجد أي مثيل للفئة UserList أو User، يمكنه إعادة تسمية الحقول أو إزالة الدوال الإنشائية التي يبدو أنّها غير مستخدَمة، ما يؤدي إلى تعطُّل تطبيقك. إذا كنت تستخدم أي مكتبات أخرى بطرق مشابهة، عليك التأكّد من أنّها لن تتعارض مع تحسين التطبيق، وفي حال حدوث ذلك، تجنَّب استخدامها.
يُرجى العِلم أنّ Room وHilt ينشئان أنواعًا محدّدة في التطبيق، ولكنّهما يستخدمان إنشاء الرموز البرمجية لتجنُّب الحاجة إلى الانعكاس.