اتّباع أفضل الممارسات

عند العمل باستخدام قواعد الاحتفاظ، من المهم تحقيق القدر المناسب من الدقة لضمان الاستفادة من المزايا مع الحفاظ على سلوك تطبيقك. راجِع الأقسام التالية للتعرّف على الأنماط الجيدة والأشياء التي يجب تجنُّبها في قواعد الاحتفاظ.

الأنماط الجيدة في قواعد الاحتفاظ

تكون قواعد الحفظ المحدّدة جيدًا دقيقة قدر الإمكان وتلتزم بالأنماط التالية:

  • بالنسبة إلى مواصفات الفئة، حدِّد دائمًا فئة معيّنة أو فئة أساسية أو فئة مزوّدة بتعليقات توضيحية إذا كان ذلك ممكنًا، كما هو موضّح في الأمثلة التالية:

    -keepclassmembers class com.example.MyClass {
      void someSpecificMethod();
    }
    
    -keepclassmembers ** extends com.example.MyBaseClass {
      void someSpecificMethod();
    }
    
    -keepclassmembers @com.example.MyAnnotation class ** {
      void someSpecificMethod();
    }
    
  • استخدِم التعليقات التوضيحية في رمز المصدر كلما أمكن ذلك، ثم استهدِف هذه التعليقات التوضيحية مباشرةً في قواعد الاحتفاظ. يؤدي ذلك إلى إنشاء رابط واضح وصريح بين الرمز والقواعد التي تحافظ عليه، ما يجعل عملية الإعداد أكثر فعالية وأسهل في الفهم وأقل عرضةً لحدوث مشاكل عند تغيير الرمز.

    على سبيل المثال، يوضّح المقتطف التالي كيف يمكنك الاحتفاظ بالفئة MyClass، بالإضافة إلى الفئات الأخرى التي تمّت إضافة التعليق التوضيحي @com.example.DisplayComponent إليها:

    // In the source code
    @com.example.DisplayComponent
    class MyClass { /* ... */ }
    
    // In the keep rules
    -keep @com.example.DisplayComponent class * {*;}
    

    ننصحك بتسمية التعليقات التوضيحية بطريقة تقدّم سياقًا ذا مغزى حول سبب الاحتفاظ بأجزاء من الرمز. على سبيل المثال، استخدِم @DisplayComponent لتطبيق تتطلّب فيه مكوّنات العرض الاحتفاظ ببعض الأجزاء.

  • ويجب الإفصاح عن مواصفات العضو كلما أمكن ذلك، والإشارة فقط إلى أجزاء الفئة التي يجب الاحتفاظ بها لكي يعمل التطبيق. يُنصح بعدم تطبيق قاعدة على فئة بأكملها من خلال تحديد نطاق العضو الاختياري على أنّه { *; } إلا إذا كان ذلك ضروريًا.

    -keepclassmembers com.example.MyClass {
      void someSpecificMethod();
      void @com.example.MyAnnotation *;
    }
    
  • إذا كنت تستخدم الخيار العام repackageclasses، تجنَّب تحديد اسم الحزمة الاختياري. ويؤدي ذلك إلى إنشاء ملفات DEX أصغر حجمًا لأنّه يتم حذف البادئة الخاصة بالحزمة من أسماء الفئات التي تمت إعادة تجميعها.

  • الحفاظ على قواعد الاحتفاظ بجميع العناصر التي يتم الوصول إليها باستخدام الانعكاس وحتى إذا احتفظت أداة R8 بهذه العناصر بدون قواعد احتفاظ صريحة، يظل الحفاظ على القواعد الفعلية أمرًا بالغ الأهمية لأنّ التغييرات المستقبلية في الرمز البرمجي قد تؤدي إلى عدم احتفاظ أداة R8 بهذه العناصر.

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

-keepclassmembers class com.example.pkg.** { *; }

أمور يجب تجنّبها

تتضمّن بنية قاعدة الاحتفاظ بالبيانات العديد من الخيارات، ولكن لتحقيق فوائد مستدامة وقابلة للقياس في الأداء، ننصح بعدم استخدام ما يلي:

  • لا تستخدِم قواعد الاحتفاظ على مستوى الحزمة، مثل -keep class com.example.pkg.** { *; } على المدى الطويل. ويمكن استخدامها مؤقتًا لتجنُّب المشاكل عند إعداد R8. لمزيد من المعلومات، يُرجى الاطّلاع على تحديد نطاق التحسين. بشكل عام، يجب توخّي الحذر عند استخدام أحرف البدل، والتأكّد من الاحتفاظ فقط بالرمز الذي تحتاج إليه.
  • تجنَّب قدر الإمكان استخدام المكتبات التي تقترح عليك نسخ قواعد الاحتفاظ ولصقها عند استخدامها، خاصةً قواعد الاحتفاظ على مستوى الحزمة. يجب أن تتجنّب المكتبات المصمَّمة لتحقيق أداء جيد على Android استخدام الانعكاس حيثما أمكن، وأن تضمِّن قواعد الاحتفاظ بالمستهلك عند الضرورة.
  • تجنَّب استخدام عامل النفي ! في قواعد الحفاظ على الفئات لأنّك قد تطبّق قاعدة عن غير قصد على كل فئة تقريبًا في تطبيقك.

إذا تعذّر عليك اتّباع هذه القواعد، من المحتمل أنّك تستخدم الكثير من عمليات الانعكاس المفتوحة، ويجب إما تجنُّب الانعكاس أو تجنُّب المكتبة باستخدام الانعكاس (راجِع دراسة حالة Gson).