لجعل تطبيقك صغيرًا وسريعًا قدر الإمكان، عليك تحسين ملف الإصدار تقليل حجمه
باستخدام isMinifyEnabled = true
.
يؤدي ذلك إلى تفعيل التصغير الذي يزيل الرموز غير المستخدَمة، والتعتيم الذي يُخفّض أسماء فئات تطبيقك وعناصره، والتحسين الذي يطبّق استراتيجيات محسّنة لتحسين الرموز من أجل تقليل حجم تطبيقك وتحسين أدائه. توضّح هذه الصفحة كيفية تنفيذ R8 لهذه المهام في وقت الترجمة لمشروعك وكيفية تخصيصها.
عند إنشاء مشروعك باستخدام الإصدار 3.4.0 من "مكوّن Android Gradle الإضافي" أو إصدار أحدث، لم يعُد المكوّن الإضافي يستخدم ProGuard لإجراء تحسين على الرموز البرمجية في وقت الترجمة. بدلاً من ذلك، يعمل المكوّن الإضافي مع مُجمِّع R8 لمعالجة المهام التالية في وقت الترجمة:
- تصغير الرموز (أو إزالة العناصر غير الضرورية من الشجرة): وهي عملية ترصد بأمان الفئات والحقول والأساليب والسمات غير المستخدَمة من تطبيقك ومكوّنات مكتبته التابعة (ما يجعلها أداة قيّمة للتعامل مع الحد الأقصى لعدد الإشارات إلى 64 ألف). على سبيل المثال، إذا كنت تستخدم بضع واجهات برمجة تطبيقات فقط من مكتبة تابعة، يمكن أن يؤدي تقليل حجم الرموز إلى تحديد رمز المكتبة الذيلا يستخدمه تطبيقك وإزالة هذا الرمز فقط من تطبيقك. لقراءة مزيد من المعلومات، انتقِل إلى القسم الذي يتناول كيفية تقليل حجم الرموز.
- تصغير حجم الموارد: تزيل هذه العملية الموارد غير المستخدمة من تطبيقك المُحزم، بما في ذلك الموارد غير المستخدمة في العناصر الاعتمادية للمكتبة في تطبيقك. ويتم ذلك بالتزامن مع تقليل حجم الرموز البرمجية، بحيث يمكن إزالة أي موارد لم يعُد يتمّ الرجوع إليها بأمان بعد إزالة الرموز البرمجية غير المستخدَمة. لمزيد من المعلومات، انتقِل إلى القسم الذي يتناول كيفية تصغير مواردك.
- التحسين: يفحص هذا الإجراء الرموز البرمجية ويعيد كتابتها لتحسين أداء وقت التشغيل
وتقليل حجم ملفات DEX في تطبيقك بشكل أكبر. يؤدي ذلك إلى تحسين أداء الرمز البرمجي أثناء التشغيل بنسبة تصل إلى %30، ما يؤدي إلى تحسين بدء التشغيل وتوقيت عرض اللقطات بشكل كبير. على سبيل المثال، إذا رصدت أداة R8 أنّه لا يتم اتّخاذ فرع
else {}
لعبارة if/else معيّنة مطلقًا، تزيل أداة R8 الرمز البرمجي لفرعelse {}
. لمزيد من المعلومات، انتقِل إلى القسم المعنيّ بتحسين الرموز البرمجية. - التشويش (أو تصغير المعرّفات): يُخفّض هذا الإجراء اسم الفصول والعناصر، ما يؤدي إلى تقليل أحجام ملفات DEX. لمزيد من المعلومات، انتقِل إلى القسم المخصص لكيفية تشويش الرمز البرمجي.
عند إنشاء إصدار التطبيق العلني، يمكن ضبط R8 لتنفيذ المهام الموضّحة أعلاه في وقت الترجمة نيابةً عنك. يمكنك أيضًا إيقاف بعض المهام أو تخصيص سلوك R8 من خلال ملفات قواعد ProGuard. في الواقع، يعمل R8 مع جميع ملفات قواعد ProGuard الحالية، لذا لن يتطلّب تعديل المكوِّن الإضافي لنظام Gradle المتوافق مع Android لاستخدام R8 تغيير قواعدك الحالية.
تفعيل ميزة تقليل الحجم وإخفاء مفاتيح فك التشفير والتحسين
عند استخدام الإصدار 3.4 من "استوديو Android" أو الإصدار 3.4.0 من المكوّن الإضافي لـ Gradle لنظام التشغيل Android والإصدارات الأحدث، يكون R8 هو compilador التلقائي الذي يحوّل الرمز الثنائي لمشروعك البرمجي المكتوب بلغة Java إلى تنسيق DEX الذي يعمل على نظام التشغيل Android. ومع ذلك، عند إنشاء مشروع جديد باستخدام Android Studio، لا يتم تفعيل تصغير الرموز البرمجية وتشويشها وتحسينها تلقائيًا. ويعود السبب في ذلك إلى أنّ عمليات التحسين هذه التي تتمّ في وقت الترجمة تزيد من مدّة إنشاء مشروعك وقد تؤدي إلى ظهور أخطاء إذا لم تتم تخصيص الرموز البرمجية التي يجب الاحتفاظ بها بشكل كافٍ.
لذلك، من الأفضل تفعيل هذه المهام في وقت الترجمة عند إنشاء الإصدار النهائي من تطبيقك الذي تختبره قبل نشره. لتفعيل التقليل والتشويه والتحسين، أدرِج ما يلي في نص إنشاء على مستوى المشروع.
Kotlin
android { buildTypes { getByName("release") { // Enables code shrinking, obfuscation, and optimization for only // your project's release build type. Make sure to use a build // variant with `isDebuggable=false`. isMinifyEnabled = true // Enables resource shrinking, which is performed by the // Android Gradle plugin. isShrinkResources = true proguardFiles( // Includes the default ProGuard rules files that are packaged with // the Android Gradle plugin. To learn more, go to the section about // R8 configuration files. getDefaultProguardFile("proguard-android-optimize.txt"), // Includes a local, custom Proguard rules file "proguard-rules.pro" ) } } ... }
رائع
android { buildTypes { release { // Enables code shrinking, obfuscation, and optimization for only // your project's release build type. Make sure to use a build // variant with `debuggable false`. minifyEnabled true // Enables resource shrinking, which is performed by the // Android Gradle plugin. shrinkResources true // Includes the default ProGuard rules files that are packaged with // the Android Gradle plugin. To learn more, go to the section about // R8 configuration files. proguardFiles getDefaultProguardFile( 'proguard-android-optimize.txt'), 'proguard-rules.pro' } } ... }
ملفات إعداد R8
يستخدم R8 ملفات قواعد ProGuard لتعديل سلوكه التلقائي ومعرفة بنية تطبيقك بشكلٍ أفضل، مثل الفئات التي تعمل كنقاط دخول إلى رمز تطبيقك. على الرغم من أنّه يمكنك تعديل بعض ملفات القواعد هذه، قد يتم إنشاء بعض القواعد تلقائيًا بواسطة أدوات وقت الترجمة، مثل AAPT2، أو القواعد المُكتسَبة من مكتبات التطبيق المُستخدَمة. يوضّح الجدول التالي مصادر ملفات قواعد ProGuard التي يستخدمها R8.
المصدر | الموقع الجغرافي | الوصف |
استوديو Android | <module-dir>/proguard-rules.pro
|
عند إنشاء وحدة جديدة باستخدام Android Studio، ينشئ "محرِّر بيئة التطوير المتكاملة" ملفًا
proguard-rules.pro في الدليل الجذر لهذه الوحدة.
لا يطبّق هذا الملف أي قواعد تلقائيًا. لذلك، أدرِج هنا قواعد ProGuard الخاصة بك، مثل قواعد الحفظ المخصّصة. |
المكوّن الإضافي لنظام Gradle المتوافق مع Android | يتم إنشاؤها بواسطة المكوّن الإضافي لنظام Gradle المتوافق مع Android في وقت الترجمة. | ينشئ المكوّن الإضافي لنظام Gradle المتوافق مع Android
proguard-android-optimize.txt ، الذي يتضمّن قواعد مفيدة
لمعظم مشاريع Android ويفعّل
@Keep*
تعليقات توضيحية.
عند إنشاء وحدة جديدة باستخدام "استوديو Android"، يتضمّن نص الإنشاء على مستوى الوحدة ملف القواعد هذا في إصدار الإصدار تلقائيًا.
ملاحظة: يتضمّن المكوّن الإضافي لنظام Gradle المتوافق مع Android ملفات قواعد ProGuard إضافية محدّدة مسبقًا، ولكن ننصحك باستخدام
|
العناصر التابعة للمكتبة |
في مكتبة AAR:
في مكتبة JAR: بالإضافة إلى هذه المواقع، يتيح المكوّن الإضافي 3.6 أو الإصدارات الأحدث من Android Gradle أيضًا قواعد التصغير المستهدفة. |
إذا تم نشر مكتبة AAR أو JAR مع ملف القواعد الخاص بها، وكنت تضمّن تلك المكتبة كعنصر تابع في وقت الترجمة، يطبّق R8 تلقائيًا هذه القواعد عند ترجمة مشروعك. بالإضافة إلى قواعد ProGuard التقليدية، يتيح المكوّن الإضافي لنظام Gradle المتوافق مع Android 3.6 أو الإصدارات الأحدث أيضًا استخدام قواعد تصغير مستهدفة. هذه هي القواعد التي تستهدف أدوات تصغير معيّنة (R8 أو ProGuard)، بالإضافة إلى إصدارات معيّنة من أدوات التصغير. يكون استخدام ملفات القواعد المُجمَّعة مع المكتبات مفيدًا إذا كانت هناك قواعد معيّنة مطلوبة لكي تعمل المكتبة بشكل صحيح، أي أنّ مطوّر المكتبة نفَّذ خطوات تحديد المشاكل وحلّها نيابةً عنك. ومع ذلك، يجب أن تكون على دراية بأنّه بما أنّ القواعد مضافة، لا يمكن إزالة قواعد معيّنة تتضمّنها مكتبة تابعة، وقد تؤثر في تجميع أجزاء أخرى من تطبيقك. على سبيل المثال، إذا كانت مكتبة تتضمّن قاعدة لإيقاف تحسينات الرموز، تعمل هذه القاعدة على إيقاف التحسينات في مشروعك بأكمله. |
أداة تجميع حِزم الموارد في Android 2 (AAPT2) | بعد إنشاء مشروعك باستخدام minifyEnabled true :
<module-dir>/build/intermediates/aapt_proguard_file/.../aapt_rules.txt
|
ينشئ AAPT2 قواعد الاحتفاظ بالبيانات استنادًا إلى الإشارات إلى الفئات فيملف التسمية والتنسيقات وموارد التطبيق الأخرى. على سبيل المثال، يتضمّن AAPT2 قاعدة للاحتفاظ بكل نشاط تسجّله في ملف بيان تطبيقك كنقطة دخول. |
ملفات الإعداد المخصّصة | عند إنشاء وحدة جديدة باستخدام Android Studio، ينشئ IDE
تلقائيًا <module-dir>/proguard-rules.pro لتتمكّن من إضافة
القواعد الخاصة بك.
|
يمكنك تضمين إعدادات إضافية، وتطبّق R8 هذه الإعدادات في وقت الترجمة. |
عند ضبط الموقع minifyEnabled
على true
، يجمع R8 القواعد من كل
المصادر المتاحة المذكورة أعلاه. من المهم تذكُّر ذلك عند
تحديد المشاكل وحلّها باستخدام R8، لأنّ التبعيات الأخرى في وقت الترجمة،
مثل تبعيات المكتبة، قد تُدخل تغييرات على سلوك R8 بدون علمك.
لعرض تقرير كامل عن جميع القواعد التي تطبّقها أداة R8 عند إنشاء
مشروعك، أدرِج ما يلي في ملف proguard-rules.pro
الخاص بالوحدة:
// You can specify any path and filename.
-printconfiguration ~/tmp/full-r8-config.txt
قواعد التصغير المستهدَفة
يتوافق الإصدار 3.6 أو الإصدارات الأحدث من "مكوّن إضافي لنظام Android Gradle" مع قواعد المكتبات التي تستهدف أدوات تصغير معيّنة (R8 أو ProGuard)، بالإضافة إلى إصدارات معيّنة من أدوات التصغير. يتيح ذلك لمطوّري المكتبات تخصيص قواعدهم للعمل على النحو الأمثل في المشاريع التي تستخدِم إصدارات جديدة من أداة تصغير الرموز البرمجية، مع السماح بمواصلة استخدام القواعد الحالية في المشاريع التي تستخدم إصدارات قديمة من أداة تصغير الرموز البرمجية.
لتحديد قواعد التصغير المستهدفة، على مطوّري المكتبات تضمينها في مواضع محدّدة داخل مكتبة AAR أو JAR، كما هو موضّح أدناه.
In an AAR library:
proguard.txt (legacy location)
classes.jar
└── META-INF
└── com.android.tools (targeted shrink rules location)
├── r8-from-<X>-upto-<Y>/<R8-rules-file>
└── proguard-from-<X>-upto-<Y>/<ProGuard-rules-file>
In a JAR library:
META-INF
├── proguard/<ProGuard-rules-file> (legacy location)
└── com.android.tools (targeted shrink rules location)
├── r8-from-<X>-upto-<Y>/<R8-rules-file>
└── proguard-from-<X>-upto-<Y>/<ProGuard-rules-file>
وهذا يعني أنّه يتم تخزين قواعد التصغير المستهدفة في الدليل META-INF/com.android.tools
لملف JAR أو في الدليل META-INF/com.android.tools
داخل
classes.jar
لملف AAR.
ضمن هذا الدليل، يمكن أن يكون هناك أدلة متعددة بأسماء على شكل
r8-from-<X>-upto-<Y>
أو proguard-from-<X>-upto-<Y>
للإشارة إلى
إصدارات برنامج التصغير التي تم كتابة القواعد داخل الأدلة لها.
يُرجى العِلم أنّ الجزءَين -from-<X>
و-upto-<Y>
اختياريان، وأنّ الإصدار <Y>
حصري، ويجب أن تكون نطاقات الإصدارات مستمرة.
على سبيل المثال، r8-upto-8.0.0
وr8-from-8.0.0-upto-8.2.0
وr8-from-8.2.0
تشكل مجموعة صالحة من قواعد التصغير المستهدَفة. ستستخدم R8 القواعد ضمن الدليل
r8-from-8.0.0-upto-8.2.0
من الإصدار 8.0.0 إلى الإصدار 8.2.0، ولكن بدون تضمين الإصدار 8.2.0.
استنادًا إلى هذه المعلومات، سيختار المكوّن الإضافي لنظام Gradle المتوافق مع Android 3.6 أو إصدار أحدث القواعد
من أدلة R8 المطابقة. إذا لم تحدّد المكتبة قواعد التقليل المستهدفة، سيختار المكوّن الإضافي لنظام Android Gradle القواعد من مواضع المعالجة القديمة (proguard.txt
لملف AAR أو
META-INF/proguard/<ProGuard-rules-file>
لملف JAR).
يمكن لمطوّري المكتبات اختيار تضمين قواعد تصغير مستهدفة أو قواعد ProGuard القديمة في مكتباتهم، أو كلا النوعَين إذا أرادوا الحفاظ على التوافق مع المكوّن الإضافي لـ Android Gradle الأقدم من 3.6 أو أدوات أخرى.
تضمين إعدادات إضافية
عند إنشاء مشروع أو وحدة جديدة باستخدام "استوديو Android"، ينشئ "محرّر بيئة التطوير المتكاملة" ملفًا بتنسيق
<module-dir>/proguard-rules.pro
لتضمين قواعدك الخاصة. يمكنك
أيضًا تضمين قواعد إضافية من ملفات أخرى من خلال إضافتها إلى سمة
proguardFiles
في نص إنشاء الوحدة.
على سبيل المثال، يمكنك إضافة قواعد خاصة بكلّ نوع من أنواع الإصدارات من خلال إضافة
موقع proguardFiles
آخر في مجموعة productFlavor
المقابلة. يضيف
ملف Gradle التالي flavor2-rules.pro
إلى نكهة المنتج flavor2
.
الآن، يستخدم flavor2
جميع قواعد ProGuard الثلاث لأنّه يتم أيضًا تطبيق القواعد من release
الحزمة.
بالإضافة إلى ذلك، يمكنك إضافة السمة testProguardFiles
التي تحدّد
قائمة بملفات ProGuard المضمّنة في حزمة APK الاختبارية فقط:
Kotlin
android { ... buildTypes { getByName("release") { isMinifyEnabled = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), // List additional ProGuard rules for the given build type here. By default, // Android Studio creates and includes an empty rules file for you (located // at the root directory of each module). "proguard-rules.pro" ) testProguardFiles( // The proguard files listed here are included in the // test APK only. "test-proguard-rules.pro" ) } } flavorDimensions.add("version") productFlavors { create("flavor1") { ... } create("flavor2") { proguardFile("flavor2-rules.pro") } } }
رائع
android { ... buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), // List additional ProGuard rules for the given build type here. By default, // Android Studio creates and includes an empty rules file for you (located // at the root directory of each module). 'proguard-rules.pro' testProguardFiles // The proguard files listed here are included in the // test APK only. 'test-proguard-rules.pro' } } flavorDimensions "version" productFlavors { flavor1 { ... } flavor2 { proguardFile 'flavor2-rules.pro' } } }
تصغير الرمز البرمجي
يتم تفعيل تصغير الرموز البرمجية باستخدام R8 تلقائيًا عند ضبط الخاصية minifyEnabled
على true
.
تصغير الرموز (يُعرف أيضًا باسم إزالة البيانات غير الضرورية) هي عملية إزالة الرموز التي يحدّد R8 أنّها غير مطلوبة في وقت التشغيل. يمكن أن تقلِّل هذه العملية بشكل كبير حجم تطبيقك إذا كان يتضمّن مثلاً العديد من مكتبات الاعتماد ولكنه يستخدم جزءًا صغيرًا فقط من وظائفها.
لتصغير رمز تطبيقك، يحدِّد R8 أولاً جميع نقاط الدخول إلى رمز تطبيقك استنادًا إلى مجموعة مُجمَّعة من ملفات الإعدادات. وتشمل نقاط الدخول هذه جميع الفئات التي قد تستخدمها منصة Android لفتح أنشطة تطبيقك أو خدماته. بدءًا من كل نقطة دخول، يفحص R8 رمز تطبيقك لإنشاء رسم بياني لجميع الطرق والمتغيّرات الأعضاء والفئات الأخرى التي قد يصل إليها تطبيقك أثناء التشغيل. يُعدّ الرمز البرمجي الذي لا يرتبط بهذا الرسم البياني غير قابل للوصول وقد تتم إزالته من التطبيق.
يعرض الشكل 1 تطبيقًا يتضمّن تبعية مكتبة وقت التشغيل. أثناء فحص
رمز التطبيق، يحدِّد R8 أنّه يمكن الوصول إلى الطرق foo()
وfaz()
وbar()
من نقطة الدخول MainActivity.class
. ومع ذلك، لا يستخدم تطبيقك فئة
OkayApi.class
أو طريقتها baz()
مطلقًا أثناء التشغيل، ويقوم الإصدار
R8 بإزالة هذا الرمز عند تصغير حجم تطبيقك.
تحدِّد R8 نقاط الدخول من خلال -keep
القواعد في
ملفات إعدادات R8 الخاصة بالمشروع. وهذا يعني أنّ قواعد الاحتفاظ تحدّد
الفئات التي يجب ألا يتخلّص منها R8 عند تصغير تطبيقك، ويعتبر R8
هذه الفئات بمثابة نقاط دخول محتملة إلى تطبيقك. ينشئ المكوّن الإضافي لـ Android Gradle
وAAPT2 تلقائيًا قواعد الاحتفاظ المطلوبة من معظم مشاريع التطبيقات، مثل الأنشطة والعروض والخدمات في تطبيقك. ومع ذلك،
إذا كنت بحاجة إلى تخصيص هذا السلوك التلقائي من خلال قواعد احتفاظ إضافية، اطّلِع على
القسم حول كيفية تخصيص الرمز الذي يجب الاحتفاظ به.
إذا كنت مهتمًا فقط بتقليل حجم موارد تطبيقك، يمكنك الانتقال إلى القسم الذي يتناول كيفية تصغير مواردك.
يُرجى العِلم أنّه في حال تصغير مشروع مكتبة، سيتضمّن التطبيق الذي يعتمد على تلك المكتبة فئات مكتبة مصغّرة. قد تحتاج إلى تعديل قواعد الاحتفاظ بالمكتبة إذا كانت هناك فئات غير متوفّرة في حزمة APK الخاصة بالمكتبة. في حال إنشاء مكتبة ونشرها بتنسيق AAR، لا يتم تصغير ملفات JAR المحلية التي تعتمد عليها مكتبتك في ملف AAR.
تخصيص الرمز المطلوب الاحتفاظ به
في معظم الحالات، يكون ملف قواعد ProGuard التلقائي (proguard-android-optimize.txt
)
كافيًا لكي يزيل R8 الرمز غير المستخدَم فقط. ومع ذلك،
يصعب على R8 تحليل بعض الحالات بشكل صحيح وقد يزيل
الرمز البرمجي الذي يحتاجه تطبيقك فعليًا. في ما يلي بعض الأمثلة على الحالات التي قد تؤدي فيها الأداة إلى إزالة الرمز البرمجي بشكل غير صحيح:
- عندما يستدعي تطبيقك طريقة من Java Native Interface (JNI)
- عندما يبحث تطبيقك عن رمز أثناء وقت التشغيل (مثلاً باستخدام ميزة "الاستكشاف")
من المفترض أن يكشف اختبار تطبيقك عن أي أخطاء ناتجة عن رمز تمت إزالته بشكل غير ملائم، ولكن يمكنك أيضًا فحص الرمز الذي تمّت إزالته من خلال إنشاء تقرير عن الرمز الذي تمّت إزالته.
لإصلاح الأخطاء وإجبار R8 على الاحتفاظ برمز معيّن، أضِف سطرًا يليه -keep
في ملف قواعد ProGuard. مثلاً:
-keep public class MyClass
بدلاً من ذلك، يمكنك إضافة التعليق التوضيحي
@Keep
إلى الرمز الذي تريده
الاحتفاظ به. تؤدي إضافة @Keep
إلى فئة إلى إبقاء الفئة بأكملها كما هي.
وتؤدي إضافتها إلى طريقة أو حقل إلى إبقاء الطريقة/الحقل (واسمها) intact
بالإضافة إلى اسم الفئة. يُرجى العلم أنّ هذا التعليق التوضيحي لا يتوفّر إلا عند استخدام
مكتبة التعليقات التوضيحية في AndroidX
وعند تضمين ملف قواعد ProGuard المُجمَّع مع المكوّن الإضافي
Gradle لنظام التشغيل Android، كما هو موضّح في القسم حول كيفية
تفعيل التقليل.
هناك العديد من الاعتبارات التي يجب مراعاتها عند استخدام الخيار -keep
. للحصول على
مزيد من المعلومات عن تخصيص ملف القواعد، يُرجى قراءة
دليل ProGuard.
يوضّح قسم
تحديد المشاكل وحلّها
المشاكل الشائعة الأخرى التي قد تواجهها عند إزالة الرمز البرمجي.
إزالة المكتبات الأصلية
يتم تلقائيًا إزالة مكتبات الرموز البرمجية الأصلية في إصدارات التطبيق العلنية. ويشمل هذا الإجراء إزالة جدول الرموز ومعلومات تصحيح الأخطاء المضمّنة في أي مكتبات أصلية يستخدمها تطبيقك. يؤدي إزالة مكتبات الرموز البرمجية الأصلية إلى تقليل حجم التطبيق بشكل كبير، ولكن لا يمكن تشخيص الأعطال على Google Play Console بسبب المعلومات غير المتوفّرة (مثل أسماء الفئات والدوالّ).
فريق الدعم المعني بالأعطال الداخلية في نظام التشغيل
تُبلغ أداة Google Play Console عن الأعطال الأصلية ضمن مؤشرات Android الحيوية. من خلال بضع خطوات، يمكنك إنشاء ملف رموز تصحيح أخطاء أصلية لتطبيقك وتحميله. يفعّل هذا الملف عمليات تتبُّع تسلسل استدعاء الدوال البرمجية الأصلية التي تم ترميزها (التي تتضمّن أسماء الفئات والوظائف) في مؤشرات Android الحيوية لمساعدتك في تصحيح أخطاء تطبيقك في قناة الإصدار العلني. تختلف هذه الخطوات حسب إصدار المكوّن الإضافي لنظام Gradle المتوافق مع Android المستخدَم في مشروعك ومخرجات التصميم لمشروعك.
الإصدار 4.1 من المكوّن الإضافي لنظام Gradle المتوافق مع Android أو إصدار أحدث
إذا كان مشروعك ينشئ حِزمة تطبيق Android، يمكنك تلقائيًا تضمين
ملف رموز تصحيح الأخطاء الأصلية فيها. لتضمين هذا الملف في إصدارات التطبيق، أضِف الخطوات التالية إلى ملف build.gradle.kts
في تطبيقك:
android.buildTypes.release.ndk.debugSymbolLevel = { SYMBOL_TABLE | FULL }
اختَر مستوى رمز تصحيح الأخطاء من الخيارات التالية:
- استخدِم
SYMBOL_TABLE
للحصول على أسماء الدوالّ في عمليات تتبُّع تسلسل استدعاء الدوالّ البرمجية التي تم ترميزها في Play Console. يتيح هذا المستوى استخدام العلامات المرجعية. - استخدِم
FULL
للحصول على أسماء الدوال البرمجية والملفات وأرقام الأسطر في ملفّات تتبُّع تسلسُل استدعاء الدوال البرمجية التي تم ترميزها في Play Console.
إذا كان مشروعك ينشئ حزمة APK، استخدِم إعداد إصدار build.gradle.kts
المعروض
أعلاه لإنشاء ملف تصحيح أخطاء الترميز الأصلي بشكل منفصل. حمِّل يدويًا
ملف تصحيح أخطاء الترميز الأصلي
إلى Google Play Console. وكجزء من عملية التصميم، يعمل المكوّن الإضافي لنظام Gradle المتوافق مع Android على إخراج هذا الملف في موقع المشروع التالي:
app/build/outputs/native-debug-symbols/variant-name/native-debug-symbols.zip
الإصدار 4.0 من المكوّن الإضافي لنظام Gradle المتوافق مع Android أو الإصدارات الأقدم (وأنظمة التصميم الأخرى)
كجزء من عملية التصميم، يحتفظ المكوّن الإضافي لنظام Gradle المتوافق مع Android بنسخة من المكتبات التي لم تتم إزالتها في دليل المشروع. تشبه بنية هذا الدليل ما يلي:
app/build/intermediates/cmake/universal/release/obj/
├── armeabi-v7a/
│ ├── libgameengine.so
│ ├── libothercode.so
│ └── libvideocodec.so
├── arm64-v8a/
│ ├── libgameengine.so
│ ├── libothercode.so
│ └── libvideocodec.so
├── x86/
│ ├── libgameengine.so
│ ├── libothercode.so
│ └── libvideocodec.so
└── x86_64/
├── libgameengine.so
├── libothercode.so
└── libvideocodec.so
اضغط محتوى هذا الدليل:
cd app/build/intermediates/cmake/universal/release/obj
zip -r symbols.zip .
حمِّل يدويًا ملف
symbols.zip
إلى Google Play Console.
تقليل الموارد
لا يعمل تصغير الموارد إلا مع تصغير الرموز البرمجية. بعد أن يزيل أداة تصغير الرموز البرمجية كل الرموز البرمجية غير المستخدَمة، يمكن لأداة تصغير الموارد تحديد موارد التطبيق التي لا يزال يستخدمها. وينطبق ذلك بشكل خاص عند إضافة مكتبات رمز برمجي تتضمّن موارد. عليك إزالة رمز المكتبة غير المستخدَم حتى تتم إزالة مرجع موارد المكتبة، وبالتالي يمكن لأداة تصغير الموارد إزالتها.
لتفعيل تصغير الموارد، اضبط السمة shrinkResources
على true
في نصّ إنشاء التطبيق (إلى جانب
minifyEnabled
لتصغير الرموز). مثلاً:
Kotlin
android { ... buildTypes { getByName("release") { isShrinkResources = true isMinifyEnabled = true proguardFiles( getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" ) } } }
رائع
android { ... buildTypes { release { shrinkResources true minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } }
إذا لم يسبق لك إنشاء تطبيقك باستخدام minifyEnabled
لتقليص حجم الكود، جرِّب ذلك قبل تفعيل shrinkResources
،
لأنّك قد تحتاج إلى تعديل ملف proguard-rules.pro
للحفاظ على الفئات أو الطرق التي يتم إنشاؤها أو استدعاؤها ديناميكيًا قبل أن تبدأ في
إزالة الموارد.
تخصيص الموارد التي تريد الاحتفاظ بها
إذا كانت هناك موارد معيّنة تريد الاحتفاظ بها أو تجاهلها، أنشئ ملف XML
في مشروعك باستخدام علامة <resources>
وحدِّد كل موارد
للاحتفاظ بها في السمة tools:keep
وكل موارد
للتجاهلها في السمة tools:discard
. تقبل كلتا السمتَين
قائمة مفصولة بفواصل لأسماء الموارد. يمكنك استخدام علامة النجمة كأحد
أحرف البدل.
مثلاً:
<?xml version="1.0" encoding="utf-8"?> <resources xmlns:tools="http://schemas.android.com/tools" tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*" tools:discard="@layout/unused2" />
احفظ هذا الملف في موارد مشروعك، على سبيل المثال، في res/raw/my.package.keep.xml
. لا يُدرج هذا الملف في حِزمة الإصدار المعنيّ من
تطبيقك.
ملاحظة: احرص على استخدام اسم فريد لملف keep
. عند ربط مكتبات مختلفة معًا، ستتعارض قواعد الاحتفاظ بها، ما قد يؤدي إلى حدوث مشاكل محتملة في القواعد التي تم تجاهلها أو الموارد التي تم الاحتفاظ بها بدون داعٍ.
قد يبدو تحديد الموارد التي تريد تجاهلها أمرًا غير منطقي عندما يمكنك بدلاً من ذلك حذفها، ولكن قد يكون ذلك مفيدًا عند استخدام أنواع الإصدارات. على سبيل المثال، يمكنك وضع جميع مواردك في دليل المشروع المشترك، ثم إنشاء ملف my.package.build.variant.keep.xml
مختلف لكل نوع
من أنواع الإصدارات عندما يكون من الواضح أنّ أحد الموارد المستخدَمة في الرمز البرمجي
(وبالتالي لا تتم إزالته بواسطة أداة تصغير الملفات) لن يتم استخدامه
في نوع الإصدار المحدّد. من الممكن أيضًا أن تكون أدوات الإنشاء قد رصدت أحد الموارد بشكل غير صحيح على النحو المطلوب، وهو أمر ممكن لأنّ المُجمِّع يضيف أرقام تعريف الموارد بشكل مضمّن، ثم قد لا يعرف محلل الموارد الفرق بين المورد المُشار إليه بشكل صحيح والقيمة الصحيحة المضمّنة في الرمز البرمجي والتي تحمل القيمة نفسها.
تفعيل عمليات التحقّق الصارمة من المراجع
في العادة، يمكن لأداة تصغير الموارد تحديد ما إذا كان المورد
يُستخدَم أم لا بدقة. ومع ذلك، إذا كان الرمز البرمجي يستدعي
Resources.getIdentifier()
(أو إذا كانت أي من مكتباتك تفعل ذلك، مثل مكتبة AppCompat
)، يعني ذلك أنّ الرمز البرمجي يبحث عن أسماء الموارد استنادًا إلى سلاسل مُنشأة ديناميكيًا. عند إجراء ذلك، يتصرف أداة تصغير الموارد بشكل دفاعي تلقائيًا ويضع علامة على جميع الموارد التي تتضمّن تنسيق اسم مطابق على أنّها قد تكون قيد الاستخدام وغير متاحة للإزالة.
على سبيل المثال، تؤدي التعليمة البرمجية التالية إلى وضع علامة على جميع الموارد التي تحتوي على البادئة
img_
على أنّها مستخدَمة.
Kotlin
val name = String.format("img_%1d", angle + 1) val res = resources.getIdentifier(name, "drawable", packageName)
Java
String name = String.format("img_%1d", angle + 1); res = getResources().getIdentifier(name, "drawable", getPackageName());
يبحث أداة تصغير الموارد أيضًا في جميع السلاسل الثابتة في
الرمز البرمجي، بالإضافة إلى موارد res/raw/
المختلفة، بحثًا عن عناوين URL
للموارد بتنسيق مشابه لfile:///android_res/drawable//ic_plus_anim_016.png
. إذا عثر على سلاسل مثل هذه أو غيرها تبدو أنّه يمكن استخدامها لإنشاء عناوين URL مماثلة، لا تتم إزالتها.
في ما يلي أمثلة على وضع التصغير الآمن الذي يكون مفعّلاً تلقائيًا.
ومع ذلك، يمكنك إيقاف هذه المعالجة "الاحتياطية" وتحديد
أن يحتفظ أداة تصغير الموارد بالموارد التي يتم استخدامها فقط. للقيام بذلك، اضبط shrinkMode
على strict
فيملف
keep.xml
، على النحو التالي:
<?xml version="1.0" encoding="utf-8"?> <resources xmlns:tools="http://schemas.android.com/tools" tools:shrinkMode="strict" />
في حال تفعيل وضع التصغير الصارم وكان الرمز يشير أيضًا إلى
موارد باستخدام سلاسل يتم إنشاؤها ديناميكيًا، كما هو موضّح أعلاه، عليك
الاحتفاظ بهذه الموارد يدويًا باستخدام السمة tools:keep
.
إزالة الموارد البديلة غير المستخدَمة
لا يزيل أداة تصغير الموارد في Gradle سوى الموارد التي لا تتم الإشارة إليها
بواسطة رمز تطبيقك، ما يعني أنّها لن تزيل
الموارد البديلة لإعدادات الأجهزة المختلفة. إذا لزم الأمر،
يمكنك استخدام سمة resConfigs
في المكوّن الإضافي لنظام Android Gradle لإزالةملفّات الموارد البديلة التي لا يحتاج إليها تطبيقك.
على سبيل المثال، إذا كنت تستخدم مكتبة تتضمّن موارد لغوية
(مثل AppCompat أو Google Play Services)، سيتضمّن تطبيقك كل
سلاسل اللغات المترجَمة للرسائل في تلك المكتبات سواء كانت
بقية أجزاء تطبيقك مترجَمة إلى اللغات نفسها أم لا. إذا أردت
الاحتفاظ فقط باللغات التي يتيح تطبيقك استخدامها رسميًا، يمكنك تحديد
هذه اللغات باستخدام السمة resConfig
. تتم إزالة أيّ موارد
للّغات غير المحدّدة.
يوضّح المقتطف التالي كيفية حصر موارد اللغة على الكلمات المتعلّقة باللغة العربية والفرنسية فقط:
Kotlin
android { defaultConfig { ... resourceConfigurations.addAll(listOf("en", "fr")) } }
رائع
android { defaultConfig { ... resConfigs "en", "fr" } }
عند إصدار تطبيق باستخدام تنسيق حِزم تطبيق Android، يتم تنزيل اللغات التي تم ضبطها على جهاز المستخدم تلقائيًا فقط عند تثبيت التطبيق. وبالمثل، لا يتم تضمين سوى الموارد التي تتطابق مع كثافة شاشة الجهاز والمكتبات المضمّنة التي تتطابق مع ABI للجهاز في عملية التنزيل. لمزيد من المعلومات، يُرجى الاطّلاع على مقالة إعداد حزم التطبيقات المتوافقة مع Android.
بالنسبة إلى التطبيقات القديمة التي يتم إصدارها باستخدام حِزم APK (التي تم إنشاؤها قبل آب/أغسطس 2021)، يمكنك تخصيص كثافة الشاشة أو موارد ABI المطلوب تضمينها في حزمة APK من خلال إنشاء حِزم APK متعددة تستهدف كلّ منها إعدادات جهاز مختلفة.
دمج المراجع المكرّرة
يُدمج Gradle أيضًا تلقائيًا الموارد التي تحمل أسماء متطابقة، مثل
ملفات drawable التي تحمل الاسم نفسه والتي قد تكون في مجلدات موارد مختلفة. لا تتحكّم الخاصية shrinkResources
في هذا السلوك، ولا يمكن إيقافه، لأنّه من الضروري تجنُّب الأخطاء عندما تتطابق عدة موارد مع الاسم الذي يبحث عنه الرمز البرمجي.
لا يحدث دمج الموارد إلا عندما يتشارك ملفان أو أكثر اسم موارد ونوعًا ومؤهّلاً متطابقَين. يختار Gradle الملف الذي يعتقد أنّه هو الخيار الأفضل بين النُسخ المكرّرة (استنادًا إلى ترتيب الأولوية الموضّح أدناه) ويمرّر هذا المورد الوحيد إلى AAPT للتوزيع في العنصر النهائي.
يبحث Gradle عن الموارد المكرّرة في المواقع التالية:
- إنّ الموارد الرئيسية المرتبطة بمجموعة المصادر الرئيسية تكون عمومًا
مضمّنة في
src/main/res/
. - تداخلات الصيغ، من نوع الإصدار ونكهاته
- تبعيات مشروع المكتبة
يُدمج Gradle الموارد المكرّرة بالترتيب التدرّجي التالي للأولوية:
التبعيات → الخيار الرئيسي → نوع النكهة → نوع التصميم
على سبيل المثال، إذا ظهر مورد مكرّر في كلّ من مواردك الرئيسية وأحد أنواع الإصدار، سيختار Gradle المورد المتوفّر في نوع الإصدار.
إذا ظهرت موارد متطابقة في مجموعة المصادر نفسها، لا يمكن لخدمة Gradle دمجها ويظهر خطأ في دمج الموارد. يمكن أن يحدث ذلك إذا حدّدت عدة
مجموعات مصادر في سمة sourceSet
من ملف
build.gradle.kts
، على سبيل المثال إذا كان كلّ من src/main/res/
وsrc/main/res2/
يحتويان على موارد متطابقة.
تشويش الرمز البرمجي
يهدف التعتيم إلى تقليل حجم تطبيقك من خلال تقصير أسماء الفئات والأساليب والحقول في تطبيقك. في ما يلي مثال على التشويش باستخدام R8:
androidx.appcompat.app.ActionBarDrawerToggle$DelegateProvider -> a.a.a.b:
androidx.appcompat.app.AlertController -> androidx.appcompat.app.AlertController:
android.content.Context mContext -> a
int mListItemLayout -> O
int mViewSpacingRight -> l
android.widget.Button mButtonNeutral -> w
int mMultiChoiceItemLayout -> M
boolean mShowTitle -> P
int mViewSpacingLeft -> j
int mButtonPanelSideLayout -> K
على الرغم من أنّ عملية التشويش لا تزيل الرموز البرمجية من تطبيقك، يمكن ملاحظة انخفاض كبير في الحجم في التطبيقات التي تحتوي على ملفات DEX فهّقت العديد من الفئات والأساليب والحقول. ومع ذلك، بما أنّ التشويش يعيد تسمية أجزاء مختلفة من الرمز البرمجي، تتطلّب مهام معيّنة، مثل فحص عمليات تتبُّع تسلسل استدعاء الدوال البرمجية، أدوات إضافية. لفهم أثر التشويش على أثر تسلسل استدعاء الدوال البرمجية، اطّلِع على القسم المخصص لكيفية فك ترميز أثر تسلسل استدعاء الدوال البرمجية المشوش.
بالإضافة إلى ذلك، إذا كان الرمز يعتمد على تسمية متوقّعة لطرق وصفوف تطبيقك، عند استخدام ميزة "الاستكشاف" مثلاً، يجب التعامل مع توقيعات هذه الطرق على أنّها نقاط دخول وتحديد قواعد الاحتفاظ بها، كما هو موضّح في القسم حول كيفية تخصيص الرمز الذي يجب الاحتفاظ به. تُطلب من R8 من خلال قواعد الحفاظ على الرمز البرمجي عدم الاحتفاظ بهذا الرمز البرمجي في حزمة DEX النهائية لتطبيقك فحسب، بل الاحتفاظ أيضًا بتسميته الأصلية.
فك ترميز تتبُّع تسلسل استدعاء الدوال البرمجية الذي يتضمّن تشويشًا
بعد أن يُعَمِّم R8 رمزك البرمجي، يصبح من الصعب فهم تتبع تسلسل استدعاء الدوال (إن لم يكن مستحيلًا) لأنّه قد تم تغيير أسماء الفئات والطُرق. للحصول على تسلسل استدعاء الدوال البرمجية الأصلي، عليك إعادة تتبُّع تسلسل استدعاء الدوال البرمجية.
تحسين الرموز
لتحسين تطبيقك بشكل أكبر، يفحص R8 رمزك البرمجي على مستوى عميق لإزالة المزيد من الرموز البرمجية غير المستخدمة أو إعادة كتابة رمزك البرمجي، إن أمكن، لجعله أقل تفصيلاً. في ما يلي بعض الأمثلة على هذه التحسينات:
- إذا لم يستخدم الرمز البرمجي الفرع
else {}
مطلقًا لعبارة if/else معيّنة، قد تزيل R8 الرمز البرمجي للفرعelse {}
. - إذا كان الرمز البرمجي يستدعي طريقة في بضعة مواضع فقط، قد يزيل R8 الطريقة ويدمجها في مواضع الاتصال القليلة.
- إذا رصدت أداة R8 أنّ فئة معيّنة تحتوي على فئة فرعية فريدة واحدة فقط، ولم يتم إنشاء مثيل للفئة (على سبيل المثال، فئة أساسية مجردة لا تستخدمها سوى فئة واحدة لتنفيذ ملموس)، يمكن لأداة R8 دمج الفئتَين وإزالة فئة من التطبيق.
- لمزيد من المعلومات، يمكنك قراءة مشاركات مدوّنة تحسين الإصدار 8 التي كتبها "جاك وارتون".
لا تسمح لك لغة R8 بإيقاف التحسينات المنفصلة أو تفعيلها أو تعديل
سلوك التحسين. في الواقع، يتجاهل R8 أي قواعد ProGuard تحاول تعديل عمليات التحسين التلقائية، مثل -optimizations
و
-optimizationpasses
. هذا القيد مهم لأنّه مع مواصلة تحسين الإصدار R8، يساعد الحفاظ على سلوك عادي للتحسينات فريق Android Studio في تحديد أي مشاكل قد تواجهك وحلّها بسهولة.
يُرجى العلم أنّ تفعيل ميزة التحسين سيؤدي إلى تغيير عمليات تتبُّع تسلسل استدعاء الدوال البرمجية لتطبيقك. على سبيل المثال، ستؤدي ميزة "العرض المضمّن" إلى إزالة إطارات الحزمة. اطّلِع على القسم المتعلق بمحاولة إعادة تتبُّع للتعرّف على كيفية الحصول على قوائم تتبُّع تسلسل استدعاء الدوال البرمجية الأصلية.
التأثير في أداء وقت التشغيل
في حال تفعيل جميع عمليات التصغير والتشويه والتحسين، سيُحسِّن R8 أداء التشغيل للرمز البرمجي (بما في ذلك وقت بدء التشغيل ووقت عرض اللقطة في سلسلة مهام واجهة المستخدم) بنسبة تصل إلى %30. يؤدي إيقاف أيّ من هذه الإعدادات إلى الحدّ بشكل كبير من مجموعة التحسينات التي يستخدمها R8.
في حال تفعيل R8، عليك أيضًا إنشاء ملفات تعريف بدء التشغيل لتحسين أداء بدء التشغيل.
تفعيل التحسينات المحسّنة
يتضمّن R8 مجموعة من التحسينات الإضافية (يُشار إليها باسم "الوضع الكامل") التي تؤدي إلى سلوكه بشكل مختلف عن ProGuard. يتم تفعيل هذه التحسينات بشكلٍ تلقائي منذ الإصدار 8.0.0 من المكوّن الإضافي لنظام Gradle المتوافق مع Android.
يمكنك إيقاف هذه التحسينات الإضافية عن طريق تضمين ما يلي فيملفgradle.properties
الخاص بمشروعك:
android.enableR8.fullMode=false
بما أنّ التحسينات الإضافية تجعل أداة R8 تتصرف بشكل مختلف عن أداة ProGuard، قد تتطلّب منك تضمين قواعد ProGuard إضافية لتجنُّب مشاكل أثناء وقت التشغيل إذا كنت تستخدم قواعد مصمّمة لأداة ProGuard. على سبيل المثال، لنفترض أنّ الرمز البرمجي يشير إلى فئة من خلال Java Reflection API. عند عدم استخدام "الوضع الكامل"، يفترض R8 أنّك تريد فحص عناصر هذه الفئة ومعالجتها أثناء وقت التشغيل، حتى إذا لم يكن الرمز البرمجي يفعل ذلك، ويحتفظ تلقائيًا بالفئة ومُنشئها الثابت.
ومع ذلك، عند استخدام "الوضع الكامل"، لا يفترض R8 هذا الافتراض، وإذا تأكد R8 من أنّ الرمز البرمجي لا يستخدم أبدًا الفئة في وقت التشغيل، سيزيل الرمز البرمجي الفئة من حزمة DEX النهائية لتطبيقك. وهذا يعني أنّه إذا أردت الاحتفاظ بالفئة ومُنشئها static، عليك تضمين قاعدة الاحتفاظ في ملف القواعد لإجراء ذلك.
إذا واجهت أي مشاكل أثناء استخدام "الوضع الكامل" في R8، يُرجى الرجوع إلى صفحة الأسئلة الشائعة حول R8 للحصول على حلّ محتمل. إذا لم تتمكّن من حلّ المشكلة، يُرجى الإبلاغ عن خطأ.
تتبُّع عمليات تتبُّع تسلسل استدعاء الدوال البرمجية
يتم تغيير الرمز الذي يعالجه R8 بطرق مختلفة يمكن أن تصعِّب فهم عمليات تتبُّع تسلسل استدعاء الدوال البرمجية لأنّها لن تتطابق تمامًا مع الرمز المصدر. وقد يحدث ذلك عند إجراء تغييرات على أرقام الأسطر في حال عدم الاحتفاظ بمعلومات تصحيح الأخطاء. وقد يرجع ذلك إلى التحسينات، مثل تضمين المحتوى وتحديد المخطط. يُعدّ التشويش هو السبب الرئيسي في ذلك، حيث يتم تغيير أسماء الفئات والطُرق.
لاسترداد تتبع تسلسل استدعاء الدوال البرمجية الأصلي، يقدّم R8 أداة سطر الأوامر retrace، والتي يتم تضمينها مع حزمة أدوات سطر الأوامر.
لتمكين إعادة تتبُّع عمليات تتبُّع تسلسل استدعاء الدوال البرمجية في تطبيقك، عليك التأكّد من أنّ عملية المعالجة تحتفظ بمعلومات كافية لإجراء عملية إعادة التتبُّع من خلال إضافة القواعد التالية إلى ملف proguard-rules.pro
في وحدتك:
-keepattributes LineNumberTable,SourceFile
-renamesourcefileattribute SourceFile
تحتفظ سمة LineNumberTable
بمعلومات مواضع العناصر
في الطرق، بحيث يتم طباعة هذه المواضع في عمليات تتبُّع تسلسل استدعاء الدوال البرمجية. تضمن السمة SourceFile
أن تطبع جميع أوقات التشغيل المحتمَلة معلومات مواضع الفواصل.
يضبط التوجيه -renamesourcefileattribute
اسم الملف المصدر في تتبعات
تسلسل استدعاء الدوال البرمجية على SourceFile
فقط. ليس من الضروري
استخدام اسم الملف المصدر الأصلي الفعلي عند إعادة التتبّع لأنّ ملف الربط يحتوي على الملف المصدر الأصلي.
ينشئ R8 ملف mapping.txt
في كل مرة يتم فيها تشغيله، والذي يحتوي على
المعلومات اللازمة لربط عمليات تتبُّع تسلسل استدعاء الدوال البرمجية بعمليات التتبُّع الأصلية
لتسلسل استدعاء الدوال البرمجية. يحفظ "استوديو Android" الملف في الدليل
<module-name>/build/outputs/mapping/<build-type>/
.
عند نشر تطبيقك على Google Play، يمكنك تحميل ملف mapping.txt
لكل إصدار من إصدارات تطبيقك. وعند النشر باستخدام حِزم تطبيق Android، يتم تضمين
هذا الملف تلقائيًا كجزء من محتوى حِزمة التطبيق. بعد ذلك، سيعيد Google
Play تتبُّع عمليات تتبُّع تسلسل استدعاء الدوال البرمجية الواردة من المشاكل التي أبلغ عنها المستخدمون حتى تتمكّن من
مراجعتها في Play Console. لمزيد من المعلومات، يُرجى الاطّلاع على مقالة "مركز المساعدة" التي تتناول كيفية إزالة تشويش عمليات تتبُّع تسلسل استدعاء الدوال البرمجية المتعلّقة بتعطُّل التطبيق.
تحديد المشاكل وحلّها باستخدام R8
يصف هذا القسم بعض الاستراتيجيات لتحديد المشاكل وحلّها عند تفعيل التصغير والتشويه والتحسين باستخدام R8. إذا لم تعثر على حلّ لمشكلتك أدناه، يمكنك أيضًا الاطّلاع على صفحة الأسئلة الشائعة حول R8 ودليل تحديد المشاكل وحلّها في ProGuard.
إنشاء تقرير عن التعليمات البرمجية التي تمّت إزالتها (أو الاحتفاظ بها)
لمساعدتك في تحديد المشاكل المتعلّقة بـ R8 وحلّها، قد يكون من المفيد الاطّلاع على تقرير يتضمن
كل الرموز البرمجية التي أزالتها أداة R8 من تطبيقك. لكل وحدة تريد
إنشاء هذا التقرير لها، أضِف -printusage <output-dir>/usage.txt
إلى ملف القواعد
المخصّصة. عند تفعيل R8 وإنشاء تطبيقك، تُخرج R8 تقريرًا بالمسار واسم الملف اللذين حددتهما. يشبه تقرير الرمز المحذوف
ما يلي:
androidx.drawerlayout.R$attr
androidx.vectordrawable.R
androidx.appcompat.app.AppCompatDelegateImpl
public void setSupportActionBar(androidx.appcompat.widget.Toolbar)
public boolean hasWindowFeature(int)
public void setHandleNativeActionModesEnabled(boolean)
android.view.ViewGroup getSubDecor()
public void setLocalNightMode(int)
final androidx.appcompat.app.AppCompatDelegateImpl$AutoNightModeManager getAutoNightModeManager()
public final androidx.appcompat.app.ActionBarDrawerToggle$Delegate getDrawerToggleDelegate()
private static final boolean DEBUG
private static final java.lang.String KEY_LOCAL_NIGHT_MODE
static final java.lang.String EXCEPTION_HANDLER_MESSAGE_SUFFIX
...
إذا كنت تريد بدلاً من ذلك الاطّلاع على تقرير عن نقاط الدخول التي تحدّدها R8 من
قواعد الاحتفاظ ببيانات مشروعك، أدرِج -printseeds <output-dir>/seeds.txt
فيملف القواعد المخصّصة. عند تفعيل R8 وإنشاء تطبيقك، يُنشئ R8
تقريرًا يتضمّن المسار واسم الملف اللذين حدّدتهما. يبدو تقرير نقاط الإدخال
المحفوظة على النحو التالي:
com.example.myapplication.MainActivity
androidx.appcompat.R$layout: int abc_action_menu_item_layout
androidx.appcompat.R$attr: int activityChooserViewStyle
androidx.appcompat.R$styleable: int MenuItem_android_id
androidx.appcompat.R$styleable: int[] CoordinatorLayout_Layout
androidx.lifecycle.FullLifecycleObserverAdapter
...
تحديد المشاكل وحلّها في ما يتعلّق بتقليص الموارد
عند تصغير الموارد، تعرض نافذة الإنشاء ملخّصًا عن الموارد التي تمت إزالتها من التطبيق. (عليك أولاً النقر على تبديل العرض على يمين النافذة لعرض نص مفصّل من Gradle). مثلاً:
:android:shrinkDebugResources
Removed unused resources: Resource data reduced from 2570KB to 1711KB: Removed 33%
:android:validateDebugSigning
ينشئ Gradle أيضًا ملف بيانات تشخيص باسم resources.txt
في
<module-name>/build/outputs/mapping/release/
(وهو المجلد
نفسه الذي تتوفّر فيه ملفات إخراج ProGuard). يتضمّن هذا الملف تفاصيل مثل موارد الويب التي تشير إلى موارد أخرى والموارد التي يتم استخدامها أو إزالتها.
على سبيل المثال، لمعرفة سبب استمرار @drawable/ic_plus_anim_016
في تطبيقك، افتح ملف resources.txt
وابحث عن اسم
الملف هذا. قد تلاحظ أنّه تمت الإشارة إليه من مصدر آخر على النحو التالي:
16:25:48.005 [QUIET] [system.out] @drawable/add_schedule_fab_icon_anim : reachable=true
16:25:48.009 [QUIET] [system.out] @drawable/ic_plus_anim_016
عليك الآن معرفة سبب إمكانية الوصول إلى @drawable/add_schedule_fab_icon_anim
، وإذا بحثت للأعلى، ستجد أنّ هذا المورد مُدرَج
ضمن "الموارد القابلة للوصول إلى الجذر هي:". وهذا يعني أنّ هناك رمزًا يشير
إلى add_schedule_fab_icon_anim
(أي أنّه تم العثور على معرّف R.drawable
في الرمز البرمجي الذي يمكن الوصول إليه).
في حال عدم استخدام التحقّق الصارم، يمكن وضع علامة على معرّفات الموارد على أنّها قابلة للوصول إذا كانت هناك ثوابت سلاسل يبدو أنّها قد يتم استخدامها لإنشاء أسماء الموارد للموارد المحمَّلة ديناميكيًا. في هذه الحالة، إذا بحثت في نتيجة الإنشاء عن اسم المورد، قد تظهر لك رسالة مثل هذه:
10:32:50.590 [QUIET] [system.out] Marking drawable:ic_plus_anim_016:2130837506
used because it format-string matches string pool constant ic_plus_anim_%1$d.
إذا ظهرت لك إحدى هذه السلاسل وكنت متأكدًا من عدم استخدام السلسلة لتحميل المورد المحدّد ديناميكيًا، يمكنك استخدام سمة tools:discard
لإعلام نظام الإنشاء بإزالتها، كما هو موضّح في القسم حول كيفية تخصيص الموارد التي يجب الاحتفاظ بها.