عند تفعيل ميزة تحسين التطبيقات باستخدام الإعدادات التلقائية، تُجري أداة R8 تحسينات مكثفة لزيادة مزايا الأداء إلى أقصى حد. يُجري R8 تعديلات مهمة على الرمز البرمجي، بما في ذلك إعادة تسمية حقول الفئات وطرقها ونقلها وإزالتها. إذا أدّى ذلك إلى حدوث أخطاء، عليك تحديد أجزاء الرمز التي يجب عدم تغييرها من خلال كتابة قواعد الاحتفاظ.
قد تزيل أداة R8 الرمز البرمجي أو تعدّله بشكل غير صحيح في الحالات التالية:
- الانعكاس: الرمز الذي يتم الوصول إليه باستخدام الانعكاس، على سبيل المثال باستخدام
Class.forName()
أوMethod.invoke()
لا يمكن عادةً لـ R8 تحديد الفئات أو methods التي سيتم الوصول إليها بهذه الطريقة. - التسلسل: قد يبدو أنّ الأدوات غير المستخدَمة في R8 (وهي شكل آخر من أشكال التأمل) هي فئات أو حقول مطلوبة للتسلسل وعكس التسلسل.
- واجهة Java الأصلية (JNI): طرق Java التي يتم استدعاؤها من الرمز البرمجي الأصلي لا يحلِّل R8 الرمز البرمجي الأصلي لمعرفة ما قد يُعيد تشغيله في Java.
تتناول هذه الصفحة كيفية الحدّ من مدى تحسينات R8. للتعرّف على كيفية تخصيص الموارد التي يتم الاحتفاظ بها، يُرجى الاطّلاع على مقالة إضافة قواعد الاحتفاظ بالموارد.
مكان إضافة قواعد الاحتفاظ بالبيانات
يجب إضافة القواعد إلى ملف proguard-rules.pro
في الدليل الجذري
للوحدة (قد يكون الملف متوفّرًا، ولكن إذا لم يكن كذلك،
أنشئ ملفًا). لتطبيق القواعد الواردة في الملف، عليك الإفصاح عن الملف في ملف build.gradle.kts
(أو build.gradle
) على مستوى الوحدة كما هو موضّح في الرمز التالي:
Kotlin
android { buildTypes { release { isMinifyEnabled = true isShrinkResources = true proguardFiles( // Default file with default optimization rules. getDefaultProguardFile("proguard-android-optimize.txt"), // File with your custom rules. "proguard-rules.pro" ) ... } } ... }
رائع
android { buildTypes { release { minifyEnabled true shrinkResources true proguardFiles( // Default file with default optimization rules. getDefaultProguardFile('proguard-android-optimize.txt'), // File with your custom rules. 'proguard-rules.pro' ) } } // ... }
يتضمّن نصّ الإنشاء تلقائيًا أيضًا ملف proguard-android-optimize.txt
. يتضمّن هذا الملف قواعد مطلوبة لمعظم مشاريع Android، لذا
يجب الاحتفاظ به في نصّ إنشاء المشروع.
كيفية كتابة قواعد الاحتفاظ بالبيانات
أثناء تجميع التطبيق، يرصد الإصدار R8 الرمز البرمجي الذي يجب الاحتفاظ به في التطبيق من خلال تحليل الرسم البياني لطلبات البيانات في تطبيقك، والذي يبدأ من إدخالات البيان (مثل أنشطتك أو خدماتك) ويتتبّع كل طلبات بيانات دالة التطبيق والمكتبة. تزيل أداة R8 الرمز البرمجي الذي لا تتم الإشارة إليه مباشرةً بهذه الطريقة، ما يمكن أن يؤدي إلى حدوث مشاكل إذا لم يكن الرمز البرمجي الذي تم تنفيذه جزءًا من هذا الرسم البياني، على سبيل المثال الرمز البرمجي الذي يتم استدعاؤه بواسطة ميزة "العرض المرجعي". من خلال كتابة قواعد الاحتفاظ الخاصة بك، يمكنك إبلاغ R8 بالرمز الذي يجب أن يظل في التطبيق.
لإضافة قاعدة الاحتفاظ، أضِف سطر -keep
في ملف proguard-rules.pro
.
الاحتفاظ ببنية القاعدة
تتّبع قواعد الاحتفاظ بشكل عام هذا التنسيق:
-<KeepOption> [OptionalModifier,...] <ClassSpecification> [{ OptionalMemberSpecification }]
على سبيل المثال، للاحتفاظ بفئة معيّنة وجميع أعضائها، استخدِم ما يلي:
-keep class com.myapp.MyClass { *; }
للاطّلاع على المزيد من الأمثلة، يُرجى الانتقال إلى قسم الأمثلة.
في ما يلي وظائف عناصر قاعدة الاحتفاظ:
<KeepOption>
تتيح لك تحديد جوانب الصف التي تريد الاحتفاظ بها:خيار الاحتفاظ الوصف -keep
يجب الاحتفاظ بالصف والأعضاء المدرَجين في
[{ OptionalMemberSpecification }]
.-keepclassmembers
السماح بتحسين الصف: في حال الحفاظ على الصف، يجب الاحتفاظ بالأعضاء المدرَجين في
[{ OptionalMemberSpecification }]
.-keepnames
اسمح بإزالة الفئة والأعضاء، ولكن لا تشوش البيانات أو تعدِّلها بطرق أخرى.
-keepclassmembernames
اسمح بإزالة الفئة والأعضاء، ولكن لا تشوش الأعضاء أو تعدّلها بطرق أخرى.
-keepclasseswithmembers
لا تتم إزالة الفئات أو تشويشها إذا كانت العناصر تتطابق مع النمط المحدّد.
ننصحك باستخدام
-keepclassmembers
في أغلب الأحيان، لأنّه يتيح معظم التحسينات، ثم-keepnames
إذا لزم الأمر. لا تسمح-keep
بأي تحسينات، لذا حاوِل استخدامها باعتدال.يتيح لك العنصر
[OptionalModifier],...]
إدراج صفرية أو أكثر من عوامل تعديل لغة Java لفئة معيّنة، مثلpublic
أوfinal
.تتيح لك سمة
<ClassSpecification>
تحديد الفئة (أو الفئة الرئيسية أو واجهة التنفيذ) التي يجب تطبيق قاعدة الاحتفاظ بها عليها. في أبسط الحالات، يمثّل ذلك فئة واحدة مؤهَّلة بالكامل.[{ OptionalMemberSpecification }]
يتيح لك فلترة السلوك المحفوظ ليشمل فقط الفئات والأساليب التي تتطابق مع أنماط معيّنة. ننصح عمومًا باستخدام هذه الميزة في معظم قواعد الاحتفاظ بالبيانات لمنع الاحتفاظ بأكثر من المطلوب.
الاحتفاظ بأمثلة القواعد
في ما يلي بعض الأمثلة على قواعد الاحتفاظ المصمّمة جيدًا.
إنشاء فئة فرعية
تم تجميع قاعدة الاحتفاظ هذه داخل androidx.room:room-runtime
للاحتفاظ
بمُنشئي قاعدة البيانات المُنشئين من خلال فحص البيانات.
-keep class * extends androidx.room.RoomDatabase { void <init>(); }
Reflection from Android Framework ObjectAnimator
يتم
تجميع قاعدة الاحتفاظ هذه داخل androidx.vectordrawable:vectordrawable-animated
ل
السماح لـ ObjectAnimator
بالاتصال بوظائف الحصول أو الضبط من الرمز الأصلي باستخدام
JNI. تجدر الإشارة إلى أنّ أنظمة الرسوم المتحركة الأحدث في Compose لا تتطلّب قواعد الاحتفاظ مثل
هذه، بل هي مجرد مثال على بنية القاعدة.
-keepclassmembers class androidx.vectordrawable.graphics.drawable.VectorDrawableCompat$* {
void set*(***);
*** get*();
}
تسجيل JNI
تم تجميع قاعدة الاحتفاظ هذه داخل androidx.graphics:graphics-path
،
وتُستخدَم للحفاظ على الطرق الأصلية. قد يكون هذا الإجراء ضروريًا إذا كانت مكتبتك تُسجِّل يدويًا methods الأصلية باستخدام env->RegisterNatives()
.
-keepclasseswithmembers class androidx.graphics.path.** {
native <methods>;
}