اختيار المكتبات بعناية

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

يُفضَّل استخدام codegen بدلاً من ميزة "العرض المرجعي".

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

لمزيد من المعلومات عن codegen مقارنةً بالاستكشاف، يُرجى الاطّلاع على مقالة التحسين لمؤلفي المكتبات.

نصائح عامة عند اختيار المكتبات

اتّبِع هذه النصائح للمساعدة في التأكّد من توافق مكتباتك مع ميزة تحسين التطبيقات.

التحقّق من المشاكل المتعلّقة بالتحسين

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

  • تعمل مكتبات AndroidX ومكتبات مثل Hilt بشكلٍ جيد مع تحسين التطبيقات لأنّها تستخدِم codegen بدلاً من ميزة "العرض المرجعي". وعند استخدام ميزة "العرض المرجعي"، يوفّرون الحد الأدنى من قواعد الاحتفاظ بالحفاظ على الرمز البرمجي الذي يحتاجون إليه فقط.
  • غالبًا ما تستخدم مكتبات التسلسل ميزة "العرض المرئي" لتجنُّب الرموز البرمجية النموذجية عند إنشاء مثيل للكائنات أو تسلسلها. بدلاً من الاعتماد على أسلوب برمجة Reflection (مثل Gson لتنسيق JSON)، ابحث عن مكتبات تستخدِم codegen لتجنُّب هذه المشاكل، على سبيل المثال باستخدام 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(). إنّ إنشاء أو استخدام klassen التي يحدّدها التطبيق بدون أيّ من الإجراءَين التاليَين يشير إلى أنّ المكتبة قد تستخدم الاستكشاف المفتوح:

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