عند تفعيل تحسين التطبيق باستخدام الإعدادات التلقائية، تُجري أداة R8 تحسينات شاملة لزيادة مزايا الأداء إلى أقصى حد. تُجري أداة R8 تعديلات كبيرة على الرموز البرمجية، بما في ذلك إعادة تسمية الفئات والحقول والطُرق ونقلها وإزالتها. إذا لاحظت أنّ هذه التعديلات تؤدي إلى حدوث أخطاء، عليك تحديد أجزاء الرمز التي يجب عدم تعديلها من خلال R8، وذلك من خلال الإشارة إليها في قواعد الاحتفاظ.
السيناريوهات الشائعة التي تتطلّب قواعد الاحتفاظ
يحدّد R8 جميع الطلبات المباشرة في الرمز البرمجي ويحتفظ بها. ومع ذلك، لا يمكن لأداة R8 رصد استخدامات الرموز البرمجية غير المباشرة، ما قد يؤدي إلى إزالة الرموز البرمجية التي يحتاجها تطبيقك، وبالتالي حدوث أعطال. استخدِم قواعد الاحتفاظ بالبيانات لإعلام R8 بالاحتفاظ بهذا الرمز البرمجي المستخدَم بشكل غير مباشر. في ما يلي بعض الحالات الشائعة التي من المحتمل أن تحتاج فيها إلى قواعد الاحتفاظ بالبيانات:
- الوصول إلى الرموز البرمجية من خلال الانعكاس: لا يمكن لـ R8 تحديد الحالات التي يتم فيها الوصول إلى الفئات أو الحقول أو الطرق من خلال الانعكاس. على سبيل المثال، لا يمكن لأداة R8 تحديد إجراء تم البحث السريع عنه باسمه باستخدام
Class.getDeclaredMethod()أو علامة توضيح تم استردادها باستخدامClass.getAnnotation(). وفي هذه الحالات، قد يعيد R8 تسمية هذه الطرق والتعليقات التوضيحية أو يزيلها بالكامل، ما يؤدي إلى حدوث خطأClassNotFoundExceptionأوNoSuchMethodExceptionفي وقت التشغيل. - الرمز البرمجي الذي يتم استدعاؤه من واجهة Java Native Interface (JNI): عندما يستدعي الرمز البرمجي الأصلي (C أو C++) طريقة Java أو Kotlin، أو عندما يستدعي رمز Java أو Kotlin رمز C++ باستخدام JNI، يستند الاستدعاء إلى بحث ديناميكي عن السلسلة لاسم الطريقة. لا يمكن لـ R8 رؤية طلب الإجراء الديناميكي المستند إلى السلسلة، وبالتالي قد تؤدي تحسيناته إلى تعطيل الرمز البرمجي.
هذه القائمة ليست شاملة للسيناريوهات التي تتطلّب قواعد الاحتفاظ بالبيانات، ولكنّها تغطي معظم الحالات التي قد تحتاج فيها إلى قواعد الاحتفاظ بالبيانات.
إذا كان الرمز البرمجي الخاص بك يستخدم الانعكاس أو يتم استدعاؤه من JNI، يمكنك إضافة تعليقات توضيحية إلى هذا الرمز باستخدام تعليقات Jetpack Keep التوضيحية بدلاً من كتابة قواعد الاحتفاظ يدويًا. ينشئ المكوّن الإضافي Gradle قواعد الاحتفاظ من التعليقات التوضيحية في وقت الإنشاء.
فهم تأثير قواعد الاحتفاظ بالبيانات في عملية التحسين
R8 هو أداة لتحسين البرنامج بالكامل، حيث يحلّل الرمز البرمجي لتطبيقك لإزالة الرموز غير المستخدَمة، والطرق المضمّنة، ودمج الفئات، وإخفاء المعرّفات. ومع ذلك، لا يمكن لـ R8 إجراء التحسين إلا ضمن الإعدادات التي تحدّدها.
تمثّل قواعد الاحتفاظ تعليمات صريحة للحدّ من التحسين. كل قاعدة احتفاظ تُعلن عنها تقيّد قدرة R8 على تحويل هذا الجزء من قاعدة الرموز البرمجية. تكمن قيمة قاعدة الاحتفاظ المصمَّمة بشكل جيد في مدى دقتها:
تتيح قواعد الاحتفاظ المحدودة تحقيق أقصى قدر من التحسين: من خلال استهداف نقاط الدخول الدقيقة التي يتم الوصول إليها ديناميكيًا فقط (مثل دالة إنشائية انعكاسية أو حقل متسلسل)، يمكنك السماح لـ R8 بتحسين بقية الرمز البرمجي.
قواعد الاحتفاظ الواسعة النطاق تمنع التحسين: يؤدي تحديد قواعد على مستوى الحزمة أو استخدام أحرف بدل واسعة النطاق إلى منع R8 من تحسين فئات كاملة وجميع عناصرها. لا يمكن لأداة R8 إزالة هذا الرمز أو تضمينه أو دمجه أو تشويشه.
تؤدي قواعد الاحتفاظ الواسعة النطاق بشكل مفرط إلى تضخّم ملفات DEX الثنائية، وزيادة استهلاك الذاكرة في التطبيق، وبطء أوقات بدء التشغيل (TTID وTTFD)، وارتفاع نسبة أخطاء ANR. يجب ألا يكون هدفك هو الاحتفاظ بالفئات "تحسّبًا لأي احتمال"، بل تحديد الحد الأدنى من العقد المطلوب للتنفيذ الديناميكي.
للعثور على قواعد الاحتفاظ بالبيانات الواسعة أو غير الضرورية، بما في ذلك القواعد الواردة من مكتبات تابعة لجهات خارجية، استخدِم أداة تحليل إعدادات R8. وتُقدّم تقارير عن نتائج تقليص حجم الرموز البرمجية وتحسينها وإخفائها، ما يوضّح مقدار الرموز البرمجية التي يمكن لأداة R8 تحسينها.
كيفية إضافة قواعد الاحتفاظ إلى تطبيقك
تعتمد إعدادات قواعد الاحتفاظ على إصدار AGP الذي تستخدمه.
تحتوي التطبيقات الأكبر حجمًا عادةً على رموز برمجية في وحدات مكتبات متعددة. وفي هذه الحالات، من الأفضل غالبًا وضع قواعد الاحتفاظ بجانب الرمز الذي تنطبق عليه ضمن وحدة المكتبة المحدّدة. يكمن الاختلاف الأساسي في الحفاظ على قواعد الاحتفاظ بالمكتبات في كيفية تعريف هذه القواعد ضمن ملف build.gradle.kts (أو build.gradle) الخاص بوحدة المكتبة. لمزيد من المعلومات، يمكنك الاطّلاع على تحسين الأداء لمؤلفي المكتبات.
بالنسبة إلى الإصدارات 9.3 من AGP والإصدارات الأحدث
أضِف القواعد إلى ملف يحمل اللاحقة .keep في الدليل src/<variant>/keepRules. على سبيل المثال:
src/main/keepRules/custom-rules.keep. يُرجى العِلم أنّ استخدام DSL المعدَّل للإصدار 9.3 من AGP والإصدارات الأحدث يتيح تحسين الرموز البرمجية والموارد، ولا يتطلّب منك تحديد ملف قواعد الاحتفاظ التلقائي في Android (proguard-android-optimize.txt) بشكل صريح، لأنّه يتم تضمينه تلقائيًا ما لم يتم حذفه صراحةً.
Kotlin
android {
buildTypes {
release {
optimization {
enable = true // Enables code and resource optimizations.
}
}
}
}
أنيق
android {
buildTypes {
release {
optimization {
enable = true // Enables code and resource optimizations.
}
}
}
}
تجاهُل قواعد الاحتفاظ التلقائية لنظام Android الأساسي (متقدّم)
يوفّر مكوّن AGP مجموعة من قواعد نظام Android الأساسي التلقائية. لحذف هذه القواعد من إعدادات مشروعك وإدارة جميع قواعد الاحتفاظ بنفسك، اضبط optimization.keepRules.includeDefault على false.
Kotlin
android {
buildTypes {
release {
optimization {
enable = true // Enables code and resource optimizations.
keepRules {
includeDefault = false // The file with optimization
// rules for the Android platform is included by
// default. To omit this file, set this option to false.
}
}
}
}
}
أنيق
android {
buildTypes {
release {
optimization {
enable = true // Enables code and resource optimizations.
keepRules {
includeDefault = false // The file with optimization
// rules for the Android platform is included by
// default. To omit this file, set this option to false.
}
}
}
}
}
لغة DSL القديمة لإصدارات AGP الأقدم من 9.3
أضِف قواعدك إلى ملف proguard-rules.pro في الدليل الجذري لوحدة التطبيق. قد يكون الملف موجودًا بالفعل، ولكن إذا لم يكن كذلك، فأنشئه. لتطبيق القواعد في الملف، يجب الإعلان عن الملف في ملف build.gradle.kts (أو build.gradle) على مستوى الوحدة.
يتضمّن ملف الإصدار أيضًا ملف proguard-android-optimize.txt تلقائيًا. يتضمّن هذا الملف القواعد المطلوبة لمعظم مشاريع Android، لذا
يجب تركه في ملف الإصدار. يستند هذا الملف إلى ملف proguard-common.txt ويشارك المحتوى معه.
لغة DSL القديمة (Kotlin)
android {
buildTypes {
release {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
// Default file with default optimization rules.
getDefaultProguardFile("proguard-android-optimize.txt"),
...
)
}
}
}
لغة DSL القديمة (Groovy)
android {
buildTypes {
release {
minifyEnabled = true
shrinkResources = true
// Default file with default optimization rules.
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
...
}
}
}
إضافة قاعدة احتفاظ
عند إضافة قواعد الاحتفاظ بالبيانات، يمكنك تضمين خيارات عامة بالإضافة إلى تحديد قواعد الاحتفاظ بالبيانات الخاصة بك.
الخيارات العامة: هي توجيهات عامة تؤثر في طريقة عمل R8 على قاعدة الرموز البرمجية بالكامل. لمزيد من المعلومات، يُرجى الاطّلاع على الخيارات العامة.
قواعد الاحتفاظ: يجب تصميم قواعد الاحتفاظ بعناية لضمان تحقيق التوازن الصحيح بين تحسين الرمز البرمجي إلى أقصى حدّ وعدم تعطيل تطبيقك عن غير قصد. لمعرفة كيفية كتابة قواعد الاحتفاظ، يُرجى الاطّلاع على مقالة إضافة قواعد الاحتفاظ.
قواعد الاحتفاظ بالبيانات لمؤلفي المكتبات
بعد التعرّف على الخيارات العامة وبنية قواعد الاحتفاظ، يمكنك الاطّلاع على التحسين لمؤلفي المكتبات لمزيد من التفاصيل.