تصغير تطبيقك وتعتيمه وتحسينه

ولجعل تطبيقك صغيرًا وسريعًا قدر الإمكان، يجب إجراء تحسينات وتصغير إصدار تطبيقك باستخدام isMinifyEnabled = true.

ويؤدي ذلك إلى تفعيل التصغير، ما يؤدي إلى إزالة الرموز والموارد غير المستخدَمة. إخفاء مفاتيح فك التشفير، الذي يختصر أسماء فئات تطبيقك وأعضائه أو التحسين، الذي يطبّق استراتيجيات أكثر صرامة لتقليل الحجم وتحسين أداء التطبيق. تصف هذه الصفحة كيف تصف R8 وتنفيذ مهام وقت التجميع هذه لمشروعك وكيف يمكنك تخصيص معهم.

عندما تنشئ مشروعك باستخدام الإصدار 3.4.0 من المكوّن الإضافي لنظام Gradle المتوافق مع Android أو الإصدارات الأحدث لم يعد المكون الإضافي يستخدم ProGuard لتحسين رمز وقت التجميع. بدلاً من ذلك، يعمل المكوّن الإضافي مع المحول البرمجي لـ R8 للتعامل مع ما يلي مهام وقت التجميع:

  • تقليص الرموز (أو اهتزاز الشجرة): يتم رصد الرموز غير المستخدَمة وإزالتها بأمان. الفئات والحقول والطرق والسمات من تطبيقك ومكتبته والتبعيات لديك (مما يجعلها أداة قيمة للعمل حول الحدّ الأقصى المرجعي 64 ألف). على سبيل المثال، إذا كنت تستخدم عدد قليل فقط من واجهات برمجة التطبيقات التابعة لتبعية مكتبة، ويمكن أن يؤدي تقليص العمل إلى تحديد رمز المكتبة أنّ تطبيقك لا يستخدم ذلك الرمز فقط ويزيله من التطبيق إلى لمعرفة المزيد، يُرجى الانتقال إلى القسم الخاص بكيفية تقليص الرمز.
  • تقلّص الموارد: لإزالة الموارد غير المستخدَمة من تطبيقك المجمّع، بما في ذلك الموارد غير المستخدَمة ضمن ملحقات مكتبة تطبيقك تعمل في مع تقليص الرمز، إذ يتم حذف الأكواد غير المستخدمة يمكن أيضًا إزالة أي موارد لم تعد مُشار إليها بأمان. للتعلّم انتقل إلى القسم الذي يتناول كيفية تقليص مواردك.
  • التحسين: يفحص الرمز البرمجي ويعيد كتابته لتحسين وقت التشغيل الأداء وتقليل حجم ملفات DEX في تطبيقك هذا النمط تحسين أداء وقت تشغيل الرمز البرمجي بنسبة تصل إلى 30%، ما يؤدي إلى تحسين أداء الرمز البرمجي بدرجة كبيرة توقيت بدء التشغيل والإطار. على سبيل المثال، إذا رصدت R8 أنّ else {} فرع لجملة if/else معينة، تزيل R8 التعليمة البرمجية فرع else {}. لمزيد من المعلومات، انتقِل إلى القسم حول تحسين الرموز.
  • الإخفاء (أو تصغير المعرّف): اختصار اسم الفئات وأعضاء الفريق، ما يؤدي إلى تقليل أحجام ملفات DEX. لمزيد من المعلومات، يُرجى الانتقال إلى القسم الذي يتناول كيفية إخفاء مفاتيح فك التشفير.

عند إنشاء إصدار إصدار تطبيقك، يمكن ضبط R8 لتنفيذ مهام وقت التجميع الموضحة أعلاه من أجلك. يمكنك أيضًا إيقاف بعض أو تخصيص سلوك R8 من خلال ملفات قواعد ProGuard. في الواقع، تعمل R8 مع جميع ملفات قواعد ProGuard الحالية، لذلك إنّ تحديث المكوّن الإضافي لنظام Gradle المتوافق مع Android لاستخدام R8 لن يتطلّب منك تغيير قواعدك الحالية.

تفعيل التقليل والتشويش والتحسين

عند استخدام الإصدار 3.4.0 من المكوّن الإضافي لنظام Gradle المتوافق مع Android أو الإصدار 3.4.0 والإصدارات الأحدث من "استوديو Android"، يكون R8 هو المحول البرمجي الافتراضي الذي يحول كود بايت 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"
            )
        }
    }
    ...
}

Groovy

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"، تنشئ بيئة التطوير المتكاملة (IDE) proguard-rules.pro في الدليل الجذر لتلك الوحدة.

لا يطبّق هذا الملف أي قواعد تلقائيًا. لذلك، قم بتضمين خياراتك قواعد ProGuard هنا، مثل مخصّص الاحتفاظ بالقواعد.

المكوّن الإضافي لنظام Gradle المتوافق مع Android يتم إنشاؤه باستخدام المكوّن الإضافي لنظام Gradle المتوافق مع Android في وقت التجميع. ينشئ المكوّن الإضافي لنظام Gradle المتوافق مع Android proguard-android-optimize.txt، بما في ذلك القواعد مفيدة لمعظم مشروعات Android @Keep* التعليقات التوضيحية.

بشكل افتراضي، عند إنشاء وحدة جديدة باستخدام استوديو Android، يمكن تعيين يتضمن نص الإصدار ملف القواعد هذا في إصدار الإصدار لك.

ملاحظة: يتضمّن المكوّن الإضافي لنظام Gradle المتوافق مع Android حزمة ProGuard إضافية محدّدة مسبقًا ولكن يوصى باستخدام proguard-android-optimize.txt

تبعيات المكتبة مكتبات AAR: <library-dir>/proguard.txt

مكتبات JAR: <library-dir>/META-INF/proguard/

في حال نشر مكتبة AAR باستخدام ملف قواعد ProGuard الخاص بها، يجب أن AAR كتبعية لوقت التجميع، فإن R8 تطبق القواعد عند تجميع مشروعك.

يُعد استخدام ملفات القواعد التي يتم تضمينها مع مكتبات AAR مفيدًا في حالة الاحتفاظ هناك قواعد مطلوبة حتى تعمل المكتبة بشكل صحيح - أي مكتبة نفذ مطوّر البرامج خطوات تحديد المشاكل وحلّها نيابةً عنك.

مع ذلك، يجب الانتباه إلى ما إذا كانت قواعد ProGuard مضافة، لا يمكن إزالة قواعد معينة تتضمنها تبعية مكتبة AAR في تجميع أجزاء أخرى من تطبيقك. على سبيل المثال، إذا كانت قاعدة لإيقاف تحسينات الرمز البرمجي، وتعمل هذه القاعدة على إيقاف التحسينات لمشروعك بأكمله.

أداة حزمة مواد العرض في Android 2 (AAPT2) بعد إنشاء مشروعك باستخدام minifyEnabled true: <module-dir>/build/intermediates/proguard-rules/debug/aapt_rules.txt ينشئ AAPT2 القواعد استنادًا إلى الإشارات إلى الفئات في تطبيقك والبيان والتخطيطات وموارد التطبيق الأخرى. على سبيل المثال، تتضمن AAPT2 العنصر لكل نشاط تسجله في بيان تطبيقك نقطة دخول متعددة.
ملفات الإعداد المخصّصة بشكل تلقائي، عند إنشاء وحدة جديدة باستخدام "استوديو Android"، يتعاون بيئة التطوير المتكاملة (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

تضمين إعدادات إضافية

عند إنشاء مشروع أو وحدة جديدة باستخدام "استوديو Android"، تنشئ بيئة التطوير المتكاملة (IDE) <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")
        }
    }
}

Groovy

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 هذا الرمز عند تصغير تطبيقك.

الشكل 1. في وقت التجميع، تقوم R8 بإنشاء يستند إلى مجموعة قواعد الاحتفاظ بمشروعك الموحّدة لتحديد الرموز التي لا يمكن الوصول إليها.

يحدّد R8 نقاط الدخول من خلال قواعد -keep في إطار المشروع. ملفات إعداد R8. أي، اجعل القواعد تحدد والفئات التي يجب ألا تتجاهلها R8 عند تقليص التطبيق، وتراعي R8 هذه الفئات كنقاط دخول محتملة إلى تطبيقك. المكوّن الإضافي لنظام Gradle المتوافق مع Android وستنشئ AAPT2 تلقائيًا القواعد التي تطلبها معظم التطبيقات المشروعات الخاصة بك، مثل أنشطة تطبيقك ومشاهداته وخدماته. ومع ذلك، إذا كنت بحاجة إلى تخصيص هذا السلوك التلقائي باستخدام قواعد Keep الإضافية، يُرجى الاطّلاع على هذا القسم المتعلّق بكيفية تخصيص الرمز المطلوب الاحتفاظ به.

إذا كنت مهتمًا فقط بتقليل حجم موارد تطبيقك، الانتقال إلى القسم الخاص بكيفية تقليل الموارد.

لاحظ أنه إذا تم تقليص مشروع مكتبة، فإن تطبيق يعتمد على تلك المكتبة فصول مكتبة صغيرة. قد تحتاج إلى تعديل قواعد الاحتفاظ بالمكتبة في حال هناك صفوف غير متوفّرة في حِزمة APK للمكتبة. إذا كنت تنشئ وتنشر ليست مكتبة بتنسيق AAR، وملفات JAR محلية تعتمد عليها مكتبتك ملف في ملف AAR.

تخصيص الرمز الذي تريد الاحتفاظ به

في معظم الحالات، يكون ملف قواعد ProGuard التلقائي (proguard-android- optimize.txt) كافيًا لكي تزيل R8 الرمز غير المستخدَم فقط. ومع ذلك، يصعب على R8 تحليل بعض المواقف بشكل صحيح وقد تزيل الرمز الذي يحتاجه تطبيقك. بعض الأمثلة على الحالات التي قد تتم فيها الإزالة بشكل غير صحيح ما يلي:

  • عندما يستدعي تطبيقك إحدى الطرق من واجهة Java الأصلية (JNI)
  • عند بحث التطبيق عن الرمز في وقت التشغيل (على سبيل المثال، عند البحث عن الرمز)

من المفترض أن يكشف اختبار تطبيقك عن أي أخطاء ناتجة عن إزالته بشكل غير صحيح. ولكن يمكنك أيضًا فحص الرمز الذي تمت إزالته عن طريق إنشاء تقرير بالرمز البرمجي الذي تمت إزالته.

لإصلاح الأخطاء وإجبار R8 على الاحتفاظ برمز معين، أضف -keep سطر في ملف قواعد ProGuard. مثلاً:

-keep public class MyClass

وبدلاً من ذلك، يمكنك إضافة @Keep إضافة تعليق توضيحي إلى الرمز البرمجي الذي أدخلته الاحتفاظ به. تؤدي إضافة @Keep إلى صف دراسي إلى إبقاء الصف بأكمله كما هو. ستؤدي إضافته إلى طريقة أو حقل إلى الاحتفاظ بالطريقة/الحقل (واسمه) أيضًا كاسم الفئة سليمًا. لاحظ أن هذا التعليق التوضيحي لا يتوفر إلا عند استخدام الـ مكتبة التعليقات التوضيحية في AndroidX وعند تضمين ملف قواعد ProGuard ضمن حزمة المكوّن الإضافي Gradle، كما هو موضح في القسم الخاص بكيفية إتاحة تقليص البيانات

هناك العديد من الاعتبارات التي يجب مراعاتها عند استخدام خيار "-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. يتوافق هذا المستوى مع ملفات Tombstone.
  • استخدام "FULL" للحصول على أسماء الوظائف والملفات وأرقام الأسطر في أداة Play Console عمليات تتبع تسلسل استدعاء الدوال البرمجية التي يتم ترميزها.

إذا كان مشروعك ينشئ حزمة APK، استخدِم إعدادات إصدار "build.gradle.kts" المعروضة. سابقًا لإنشاء ملف تصحيح أخطاء الترميز الأصلي بشكل منفصل. يدويًّا تحميل ملف تصحيح أخطاء الترميز المحلي إلى Google Play Console. وكجزء من عملية التصميم، يتم استخدام واجهة برمجة التطبيقات Android Gradle يعمل المكون الإضافي على إخراج هذا الملف في موقع المشروع التالي:

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
  1. اضغط محتوى هذا الدليل:

    cd app/build/intermediates/cmake/universal/release/obj
    zip -r symbols.zip .
    
  2. يدويًّا تحميل ملف 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"
            )
        }
    }
}

Groovy

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. فعندما يتم ربط مكتبات مختلفة معًا فقد تتعارض قواعد 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 في المكوّن الإضافي لنظام Gradle المتوافق مع Android إزالة ملفات الموارد البديلة التي لا يحتاجها تطبيقك.

فعلى سبيل المثال، إذا كنت تستخدم مكتبة تتضمن موارد لغوية (مثل AppCompat أو خدمات Google Play)، فسيتضمن تطبيقك جميع سلاسل اللغة المترجمة للرسائل في تلك المكتبات سواء كانت عندما تتم ترجمة بقية محتوى التطبيق إلى اللغات نفسها أو لا. إذا كنت ترغب في تتيح لك الاحتفاظ باللغات التي يتيحها تطبيقك رسميًا، يمكنك تحديد هذه اللغات باستخدام السمة resConfig. أي موارد تتم إزالة اللغات غير المحددة.

يعرض المقتطف التالي كيفية حصر موارد اللغة على الإنجليزية والفرنسية:

Kotlin

android {
    defaultConfig {
        ...
        resourceConfigurations.addAll(listOf("en", "fr"))
    }
}

Groovy

android {
    defaultConfig {
        ...
        resConfigs "en", "fr"
    }
}

عند إصدار تطبيق باستخدام تنسيق "مجموعة حزمات تطبيق Android"، يتم ذلك تلقائيًا فقط يتم تنزيل اللغات التي تم ضبطها على جهاز المستخدم عند تثبيت التطبيق. وبالمثل، لا تتوفّر إلا الموارد التي تتطابق مع كثافة شاشة الجهاز، والموارد الأصلية يتم تضمين المكتبات المطابقة لواجهة التطبيق الثنائية (ABI) للجهاز في عملية التنزيل. لمزيد من المعلومات، المعلومات تشير إلى تطبيق Android إعداد الحزمة:

بالنسبة إلى التطبيقات القديمة التي يتم إصدارها باستخدام حِزم APK (التي تم إنشاؤها قبل آب (أغسطس) 2021)، يمكنك: تخصيص كثافة الشاشة أو موارد ABI المراد تضمينها في حزمة APK من خلال إنشاء حِزم APK متعدّدة أن يستهدف كل منها تهيئة جهاز مختلفة.

دمج الموارد المكرّرة

بشكل افتراضي، تدمج Gradle أيضًا الموارد ذات الأسماء المتطابقة، مثل عناصر قابلة للرسم بالاسم ذاته والتي قد تكون في مجلدات موارد مختلفة. هذا النمط لا يتم التحكم في السلوك من خلال السمة 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 التي تفهرس العديد من الفئات والطرق والحقول. ومع ذلك، ونظرًا لأن التشويش يعيد تسمية أجزاء مختلفة من التعليمات البرمجية، فقد يتم مثل فحص تتبعات تسلسل استدعاء الدوال البرمجية، يتطلب ذلك أدوات إضافية. لفهم تتبع تسلسل استدعاء الدوال البرمجية بعد إخفاء مفاتيح فك التشفير، فاقرأ القسم الخاص بكيفية فك ترميز تتبُّع تسلسل استدعاء الدوال البرمجية مع تشويش.

بالإضافة إلى ذلك، إذا كانت التعليمات البرمجية تعتمد على تسمية يمكن توقعها لأساليب تطبيقك والفئات — عند استخدام الانعكاس، على سبيل المثال، ينبغي أن تتعامل مع تلك التوقيعات كنقاط دخول وتحديد قواعد الاحتفاظ بها، كما هو موضح في حول كيفية تخصيص الرمز المطلوب الاحتفاظ به. cannot translate توجّه R8 المستخدمين إلى الاحتفاظ بهذه الرموز في دالة DEX النهائية الخاصة بتطبيقك، بل سيحتفظون بها أيضًا. اسمه الأصلي.

فك ترميز عملية تتبُّع تسلسل استدعاء الدوال البرمجية التي تم تشويشها

بعد تشويش R8 على الرمز البرمجي، سيكون من الصعب فهم عملية تتبُّع تسلسل استدعاء الدوال البرمجية. (إذا لم يكن مستحيلاً) لأن أسماء الفئات والأساليب ربما كانت بتغييره. للحصول على تقرير تتبُّع تسلسل استدعاء الدوال البرمجية الأصلي، يجب تتبُّع عملية تتبُّع تسلسل استدعاء الدوال البرمجية.

تحسين الرمز

ولتحسين تطبيقك بشكل أكبر، يفحص R8 التعليمات البرمجية لديك بشكل أعمق لإزالة المزيد من التعليمات البرمجية غير المستخدمة أو إعادة كتابة التعليمات البرمجية قدر الإمكان فإنها أقل طولاً. في ما يلي بعض الأمثلة على هذه التحسينات:

  • إذا لم يستخدم الرمز فرع else {} لعبارة if/else محددة مطلقًا، قد يزيل R8 الرمز لفرع else {}.
  • إذا يستدعي الرمز طريقة في عدد قليل من الأماكن فقط، قد يزيل R8 الطريقة وإدراجه في مواقع الاتصال القليلة.
  • إذا حددت R8 أن فئة ما بها فئة فرعية واحدة فريدة فقط، نفسها لا يتم إنشاء مثيل لها (على سبيل المثال، فئة أساس مجردة تستخدمها فقط فئة تنفيذ ملموسة)، فيمكن لـ R8 أن تجمع بين الفئتين إزالة فئة من التطبيق.
  • لمزيد من المعلومات، يُرجى قراءة مشاركات مدوّنة تحسين R8 من تأليف "جيك وارتون".

لا تسمح لك R8 بإيقاف أو تمكين تحسينات منفصلة أو تعديل طريقة التحسين. في الواقع، يتجاهل R8 أي قواعد ProGuard تحاول لتعديل التحسينات التلقائية، مثل -optimizations -optimizationpasses هذا القيد مهم لأنه، حيث تستمر R8 في التحسين المستمر، والحفاظ على سلوك عادي للتحسينات، يساعد نظام يمكن لفريق الاستوديو تحديد المشاكل وحلّها بسهولة وحلّ أي مشاكل قد تواجهها.

تجدر الإشارة إلى أنّ تفعيل التحسين سيؤدي إلى تغيير عمليات تتبُّع تسلسل استدعاء الدوال البرمجية في التطبيق. على سبيل المثال، سيؤدي الإدخال إلى إزالة إطارات تسلسل استدعاء الدوال البرمجية. راجع القسم الذي يتناول retracing لمعرفة كيفية الحصول على عمليات تتبُّع تسلسل استدعاء الدوال البرمجية الأصلية.

التأثير في أداء بيئة التشغيل

في حال تفعيل كلّ من عناصر تصغير البيانات والتشويش والتحسين، سيتم تحسين R8. أداء وقت تشغيل الرمز البرمجي (بما في ذلك وقت بدء التشغيل ووقت عرض اللقطة في سلسلة واجهة المستخدم) بنسبة تصل إلى %30 يؤدي إيقاف أي من هذه الإجراءات إلى تقييد مجموعة التحسينات بشكل كبير استخدامات R8.

إذا تم تمكين R8، فيجب عليك أيضًا إنشاء الملفات الشخصية للشركات الناشئة لتحسين أداء الشركات الناشئة.

تفعيل تحسينات أكثر صرامة

تتضمن R8 مجموعة من التحسينات الإضافية (المشار إليها باسم "الوضع الكامل") التي يجعله يتصرف بشكل مختلف عن ProGuard. تم تفعيل هذه التحسينات من خلال تلقائي منذ الإصدار 8.0.0 من المكوّن الإضافي لنظام Gradle المتوافق مع Android

يمكنك إيقاف هذه التحسينات الإضافية من خلال تضمين ما يلي في ملف gradle.properties لمشروعك:

android.enableR8.fullMode=false

ولأن التحسينات الإضافية تجعل R8 تتصرف بشكل مختلف عن ProGuard، قد تتطلب منك تضمين قواعد ProGuard إضافية لتجنب وقت التشغيل إذا كنت تستخدم قواعد مصمَّمة لـ ProGuard. على سبيل المثال، لنفترض أن إلى فئة من خلال واجهة برمجة تطبيقات Java Reclection. عند عدم استخدام و"الوضع الكامل" يفترض R8 أنك تعتزم فحص كائنات هذه الفئة في وقت التشغيل - حتى لو لم يحدث ذلك في الرمز - ويتم تحتفظ بالفئة ومهيئها الثابت.

ومع ذلك، عند استخدام "الوضع الكامل"، فإن R8 لا تضع هذا الافتراض، وإذا كانت R8 أن التعليمات البرمجية لا تستخدم الفئة أبدًا في وقت التشغيل، فإن ذلك يؤدي إلى الفئة من دالة DEX النهائية لتطبيقك. أي، إذا كنت تريد الاحتفاظ بالفئة برنامج التهيئة الثابت، يلزمك تضمين قاعدة Keep في ملف القواعد لتنفيذه ذلك.

إذا واجهت أي مشاكل أثناء استخدام "الوضع الكامل" في 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: Binary 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 لإعلام نظام التصميم بإزالتها كما هو موضَّح في القسم المتعلّق بكيفية تخصيص الموارد التي يجب الاحتفاظ بها.