التغييرات في سلوك الإصدار Android 8.0

بالإضافة إلى الميزات والإمكانات الجديدة، يتضمّن Android 8.0 (المستوى 26 لواجهة برمجة التطبيقات) مجموعة متنوعة من التغييرات في النظام وسلوك واجهة برمجة التطبيقات. يوضّح هذا المستند بعض التغييرات الرئيسية التي يجب فهمها وأخذها في الاعتبار في تطبيقاتك.

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

تغييرات لجميع التطبيقات

تنطبق تغييرات السلوك هذه على جميع التطبيقات عند تشغيلها على نظام Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات)، بغض النظر عن مستوى واجهة برمجة التطبيقات الذي تستهدفه. وعلى جميع المطوّرين مراجعة هذه التغييرات وتعديل تطبيقاتهم للتوافق مع هذه التغييرات بشكل صحيح، حيثما ينطبق ذلك.

حدود التنفيذ في الخلفية

من بين التغييرات التي أدخلها Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) لتحسين عمر البطارية، عندما يدخل تطبيقك في حالة التخزين المؤقت بدون أي مكوّنات نشطة، يصدر النظام أي عمليات قفل تنشيط محفوظة في التطبيق.

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

  • تُفرَض الآن قيود على حرية التطبيقات التي تعمل في الخلفية في الوصول إلى الخدمات التي تعمل في الخلفية.
  • لا يمكن للتطبيقات استخدام بياناتها للتسجيل في معظم عمليات البث الضمنية (أي عمليات البث التي لا تستهدف التطبيق تحديدًا).

وبشكلٍ تلقائي، لا تسري هذه القيود إلا على التطبيقات التي تستهدف O. ومع ذلك، يمكن للمستخدمين تفعيل هذه القيود لأي تطبيق من شاشة الإعدادات، حتى إذا لم يستهدف التطبيق O.

يتضمّن Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) أيضًا التغييرات التالية على طرق معيّنة:

  • تعرض الطريقة startService() الآن الخطأ IllegalStateException إذا حاول تطبيق يستهدف الإصدار 8.0 من نظام التشغيل Android استخدام هذه الطريقة في حالة لا يُسمح له بإنشاء خدمات في الخلفية.
  • تبدأ الطريقة Context.startForegroundService() الجديدة خدمة تعمل في المقدّمة. يسمح النظام للتطبيقات بالاتصال بالرقم Context.startForegroundService() حتى عندما يكون التطبيق في الخلفية. ومع ذلك، يجب أن يستدعي التطبيق طريقة startForeground() الخاصة بتلك الخدمة خلال خمس ثوانٍ من إنشاء الخدمة.

لمزيد من المعلومات، يُرجى الاطّلاع على حدود التنفيذ في الخلفية.

الحدود القصوى المسموح بها لتحديد الموقع الجغرافي في الخلفية على Android

للحفاظ على طاقة البطارية وتجربة المستخدم وسلامة النظام، تتلقّى التطبيقات في الخلفية تحديثات للموقع الجغرافي بمعدل أقل عند استخدامها على جهاز يعمل بنظام التشغيل Android 8.0. يؤثّر هذا التغيير في السلوك على جميع التطبيقات التي تتلقّى تحديثات للموقع الجغرافي، بما في ذلك "خدمات Google Play".

تؤثّر هذه التغييرات في واجهات برمجة التطبيقات التالية:

  • موفِّر الموقع المدمج (FLP)
  • وضع الحدود الجغرافية
  • قياسات GNSS
  • مدير المواقع الجغرافية
  • مدير شبكة Wi-Fi

لضمان تشغيل تطبيقك على النحو المتوقّع، يجب إكمال الخطوات التالية:

  • راجِع منطق تطبيقك وتأكَّد من أنك تستخدم أحدث واجهات برمجة التطبيقات للمواقع الجغرافية.
  • اختبِر أنّ تطبيقك يعرض السلوك الذي تتوقّعه لكل حالة استخدام.
  • ننصحك باستخدام موفِّر الموقع المدمج (FLP) أو وضع حدود جغرافية لمعالجة حالات الاستخدام التي تعتمد على الموقع الجغرافي الحالي للمستخدم.

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

اختصارات التطبيقات

يتضمّن Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) التغييرات التالية في اختصارات التطبيقات:

  • لم يعُد للبث com.android.launcher.action.INSTALL_SHORTCUT أي تأثير على تطبيقك، لأنّه أصبح الآن بثًا خاصًا وضمنًا. بدلاً من ذلك، عليك إنشاء اختصار للتطبيق باستخدام الإجراء requestPinShortcut() من الفئة ShortcutManager.
  • يمكن الآن لأداة ACTION_CREATE_SHORTCUT نية إنشاء اختصارات التطبيقات التي تديرها باستخدام الفئة ShortcutManager. يمكن لهذا الغرض أيضًا إنشاء اختصارات مشغّل تطبيقات قديمة لا تتفاعل مع ShortcutManager. في السابق، كان من الممكن أن ينشئ هذا الإجراء اختصارات مشغّل التطبيقات القديمة فقط.
  • الاختصارات التي يتم إنشاؤها باستخدام requestPinShortcut() والاختصارات التي تم إنشاؤها في نشاط يعالج الغرض ACTION_CREATE_SHORTCUT أصبحت الآن اختصارات تطبيقات كاملة. نتيجةً لذلك، يمكن للتطبيقات الآن تحديثها باستخدام الطرق الواردة في ShortcutManager.
  • تحتفظ الاختصارات القديمة بوظائفها من الإصدارات السابقة من Android، ولكن عليك تحويلها إلى اختصارات للتطبيق يدويًا في تطبيقك.

لمزيد من المعلومات حول التغييرات التي تطرأ على اختصارات التطبيقات، اطّلِع على دليل ميزة تثبيت الاختصارات والتطبيقات المصغّرة.

اللغات والتدويل

قدّم Android 7.0 (المستوى 24 من واجهة برمجة التطبيقات) مفهوم إمكانية تحديد لغة فئة تلقائية، إلا أنّ بعض واجهات برمجة التطبيقات واصلت استخدام طريقة Locale.getDefault() العامة بدون وسيطات، إذ كان يجب عليها استخدام لغة الفئة DISPLAY التلقائية بدلاً من ذلك. في Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات)، تستخدم الطرق التالية الآن Locale.getDefault(Category.DISPLAY) بدلاً من Locale.getDefault():

تعود Locale.getDisplayScript(Locale) أيضًا إلى Locale.getDefault() عندما تكون قيمة displayScript المحددة للوسيطة Locale غير متوفرة.

في ما يلي التغييرات الإضافية المتعلقة باللغة والانتشار على نطاق عالمي:

  • يؤدي طلب الرمز Currency.getDisplayName(null) إلى إنشاء خطأ NullPointerException، مطابق للسلوك الموثَّق.
  • تم تغيير تحليل اسم المنطقة الزمنية. في السابق، كانت أجهزة Android تستخدم قيمة ساعة النظام المستندة إلى عيّنة في وقت التشغيل لتخزين أسماء المناطق الزمنية المستخدَمة لتحليل أوقات التواريخ في ذاكرة التخزين المؤقت. ونتيجةً لذلك، يمكن أن يتأثر التحليل سلبًا إذا كانت ساعة النظام غير صحيحة في وقت التشغيل أو في حالات أخرى نادرة.

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

  • يعمل نظام Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) على تحديث إصدار وحدة ICU إلى الإصدار 58.

نوافذ التنبيهات

إذا كان أحد التطبيقات يستخدم إذن SYSTEM_ALERT_WINDOW واستخدم أحد أنواع النوافذ التالية لمحاولة عرض نوافذ التنبيه فوق التطبيقات ونوافذ النظام الأخرى:

...فستظهر هذه النوافذ دائمًا أسفل النوافذ التي تستخدم نوع النافذة TYPE_APPLICATION_OVERLAY. إذا كان التطبيق يستهدف الإصدار Android 8.0 (المستوى 26 لواجهة برمجة التطبيقات)، يستخدم التطبيق نوع النافذة TYPE_APPLICATION_OVERLAY لعرض نوافذ التنبيهات.

لمزيد من المعلومات، يمكنك الاطّلاع على القسم أنواع النوافذ الشائعة لنوافذ التنبيهات ضمن تغييرات السلوك للتطبيقات التي تستهدف الإصدار 8.0 من نظام التشغيل Android.

الإدخال والتنقل

مع ظهور تطبيقات Android على ChromeOS وغير ذلك من أشكال الأجهزة الكبيرة، مثل الأجهزة اللوحية، نشهد عودة استخدام التنقّل باستخدام لوحة المفاتيح في تطبيقات Android من جديد. في الإصدار Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات)، أُعيد معالجة استخدام لوحة المفاتيح كجهاز إدخال للتنقّل، ما أدى إلى إنشاء نموذج أكثر موثوقية يمكن توقّعه للتنقّل باستخدام السهم أو علامة التبويب.

وعلى وجه الخصوص، أجرينا التغييرات التالية على سلوك التركيز على العنصر:

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

    إذا كنت لا تريد أن يستخدم الكائن View التمييز التلقائي عند التركيز عليه، يمكنك ضبط السمة android:defaultFocusHighlightEnabled على false في ملف XML الخاص بالتنسيق الذي يحتوي على View، أو ضبط السمة false إلى setDefaultFocusHighlightEnabled() في منطق واجهة المستخدم الخاصة بالتطبيق.

  • لاختبار تأثير إدخال لوحة المفاتيح على تركيز عنصر واجهة المستخدم، يمكنك تفعيل خيار مطوّر البرامج رسم > عرض حدود التنسيق. في نظام التشغيل Android 8.0، يعرض هذا الخيار رمز "X" فوق العنصر الذي يتم التركيز عليه حاليًا.

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

للتعرف على مزيد من المعلومات حول كيفية تحسين دعم التنقل بلوحة المفاتيح داخل تطبيقك، اقرأ دليل دعم التنقل باستخدام لوحة المفاتيح.

الملء التلقائي لنموذج الويب

الآن وبعد أن توفّر إطار عمل الملء التلقائي لنظام التشغيل Android دعمًا مضمّنًا لوظائف الملء التلقائي، تغيّرت الطرق التالية المتعلّقة بكائنات WebView في التطبيقات المثبّتة على الأجهزة التي تعمل بنظام التشغيل Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات):

WebSettings
  • تعرض الطريقة getSaveFormData() الآن القيمة false. وكانت هذه الطريقة في السابق تعرض true بدلاً منها.
  • لم يعُد للاتصال بالرقم setSaveFormData() أي تأثير.
WebViewDatabase
  • لم يعُد للاتصال بالرقم clearFormData() أي تأثير.
  • تعرض الطريقة hasFormData() الآن القيمة false. في السابق، كانت هذه الطريقة تعرض رمز الاستجابة true عندما كان النموذج يحتوي على بيانات.

تسهيل الاستخدام

يتضمّن Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) التغييرات التالية المتعلّقة بأدوات تسهيل الاستخدام:

  • يحوّل إطار عمل تسهيل الاستخدام جميع إيماءات النقر مرّتين إلى إجراءات ACTION_CLICK. يسمح هذا التغيير لميزة TalkBack بأن تعمل بشكل مشابه لخدمات تسهيل الاستخدام الأخرى.

    إذا كانت عناصر View في تطبيقك تستخدم معالجة مخصّصة باللمس، عليك التأكّد من أنّها لا تزال تعمل مع ميزة TalkBack. قد تحتاج فقط إلى تسجيل معالج النقرات الذي تستخدمه كائنات View. إذا لم تتمكّن ميزة TalkBack من التعرّف على الإيماءات التي تم تنفيذها على عناصر View هذه، عليك إلغاء performAccessibilityAction().

  • تتعرّف خدمات تسهيل الاستخدام الآن على جميع مثيلات ClickableSpan ضمن كائنات TextView في تطبيقك.

لمعرفة المزيد من المعلومات حول طريقة تسهيل الوصول إلى تطبيقك، اطّلِع على مقالة تسهيل الاستخدام.

الاتصال بالشبكات واتصال HTTP(S)

يتضمن الإصدار Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) التغييرات التالية في السلوك المتعلق بالشبكات واتصال HTTP(S):

  • تتضمّن طلبات OPTIONS بدون نص عنوان Content-Length: 0. وفي السابق، لم يكن هناك عنوان Content-Length.
  • تعمل ميزة HttpURLConnection على تسوية عناوين URL التي تحتوي على مسارات فارغة من خلال إلحاق شرطة مائلة بعد اسم المضيف أو المرجع بشرطة مائلة. على سبيل المثال، يحوّل http://example.com إلى http://example.com/.
  • لا يستهدف أداة اختيار الخادم الوكيل المخصّص التي تم ضبطها من خلال ProxySelector.setDefault() عنوان URL المطلوب إلا (المخطط والمضيف والمنفذ). ونتيجةً لذلك، قد يستند اختيار الخادم الوكيل إلى هذه القيم فقط. لا يتضمّن عنوان URL الذي تم تمريره إلى أداة اختيار الخادم الوكيل المخصّص مسار عنوان URL المطلوب أو معلَمات طلب البحث أو الأجزاء.
  • لا يمكن أن تحتوي معرّفات الموارد المنتظمة (URI) على تصنيفات فارغة.

    في السابق، وفّرت المنصة حلاً بديلاً لقبول التصنيفات الفارغة في أسماء المضيفين، وهو استخدام غير قانوني لمعرّفات الموارد المنتظمة (URI). وكان هذا الحل البديل متوافقًا مع إصدارات libcore القديمة. وستظهر للمطوّرين الذين يستخدمون واجهة برمجة التطبيقات بشكل غير صحيح رسالة ADB: "يحتوي عنوان URI example.com على تصنيفات فارغة في اسم المضيف. تمت صياغة هذا العنوان بشكل غير صحيح ولن يتم قبوله في إصدارات Android المستقبلية." يزيل الإصدار Android 8.0 هذا الحل البديل، ويعرض النظام قيمة فارغة لمعرّفات الموارد المنتظمة (URI) التي تمت صياغتها بشكلٍ غير صحيح.

  • لا ينفِّذ تطبيق Android 8.0 HttpsURLConnection نسخة احتياطية غير آمنة من بروتوكول أمان طبقة النقل (TLS) أو طبقة المقابس الآمنة (SSL).
  • تم تغيير معالجة اتصالات HTTP(S) النفقية على النحو التالي:
    • عند إجراء اتصال نفقي HTTPS من خلال الاتصال، يضع النظام رقم المنفذ (:443) بشكل صحيح في سطر المضيف عند إرسال هذه المعلومات إلى خادم وسيط. وفي السابق، كان رقم المنفذ يظهر في سطر "الربط" فقط.
    • لم يعُد النظام يرسل رؤوس وكيل المستخدم والوكيل الوكيل من طلب نفقي إلى الخادم الوكيل.

      لم يعد النظام يرسل رأس تفويض الخادم الوكيل على Http(s)URLConnection إلى الخادم الوكيل عند إعداد النفق. بدلاً من ذلك، ينشئ النظام عنوان تفويض الخادم الوكيل، ويرسله إلى الخادم الوكيل عندما يرسل ذلك الخادم الوكيل HTTP 407 كاستجابة للطلب الأولي.

      وبالمثل، لن ينسخ النظام عنوان وكيل المستخدم بعد ذلك من الطلب النفقي إلى طلب الخادم الوكيل الذي يُعدّ النفق. بدلاً من ذلك، تنشئ المكتبة عنوان وكيل مستخدم لهذا الطلب.

  • تعرض الطريقة send(java.net.DatagramPacket) SocketException في حال تعذَّر تنفيذ طريقة Connect() التي تم تنفيذها سابقًا.
    • يضبط DatagramSocket.connect() دالة pendingSocketException في حال حدوث خطأ داخلي. قبل استخدام نظام التشغيل Android 8.0، كان الاستدعاء اللاحق لـ recv() أثار خطأ SocketException على الرغم من نجاح استدعاء send(). لتحقيق الاتساق، يطرح كلا الطلبين الآن SocketException.
  • يحاول InetAddress.isReachable() تجربة بروتوكول ICMP قبل العودة إلى بروتوكول TCP Echo.
    • قد يصبح بإمكان بعض الأجهزة المضيفة التي تحظر المنفذ 7 (TCP Echo) مثل google.com الوصول إلى تلك الأجهزة في حال قبول بروتوكول ICMP Echo.
    • بالنسبة إلى المضيفين الذين لا يمكن الوصول إليهم، يعني هذا التغيير أنّه يتم قضاء ضعف مقدار الوقت قبل معاودة الاتصال.

البلوتوث

يُجري نظام Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) التغييرات التالية على طول البيانات التي تستردها طريقة ScanRecord.getBytes():

  • لا تضع الطريقة getBytes() أي افتراضات بشأن عدد وحدات البايت التي يتم استلامها. ولذلك، يجب ألا تعتمد التطبيقات على أي حد أدنى أو أقصى لعدد وحدات البايت التي يتم عرضها. بدلاً من ذلك، عليهم تقييم طول الصفيف الناتج.
  • قد تعرض الأجهزة المتوافقة مع تقنية البلوتوث 5 طول بيانات يتجاوز الحد الأقصى السابق وهو 60 بايت تقريبًا.
  • إذا لم يوفِّر جهاز بعيد استجابة المسح، قد يتم أيضًا عرض أقل من 60 بايت.

إمكانية الاتصال بسلاسة

يجري نظام Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) عددًا من التحسينات على إعدادات Wi-Fi لتسهيل اختيار شبكة Wi-Fi التي توفّر أفضل تجربة للمستخدم. تشمل التغييرات المحددة ما يلي:

  • تحسينات على الثبات والموثوقية
  • واجهة مستخدم أكثر سهولة في القراءة
  • قائمة واحدة وموحّدة لإعدادات Wi-Fi المفضّلة.
  • التفعيل التلقائي لشبكة Wi-Fi على الأجهزة المتوافقة عندما تكون هناك شبكة محفوظة عالية الجودة بالقرب من الجهاز.

الأمان

يتضمن Android 8.0 التغييرات التالية المتعلقة بالأمان:

  • لم يعد النظام الأساسي متوافقًا مع SSLv3.
  • عند إنشاء اتصال HTTPS بخادم ينفّذ بشكل غير صحيح تفاوض إصدار بروتوكول أمان طبقة النقل (TLS)، لم يعد HttpsURLConnection يحاول الحل البديل للرجوع إلى الإصدارات السابقة من بروتوكول أمان طبقة النقل (TLS) وإعادة المحاولة.
  • يطبِّق Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) فلتر الحوسبة الآمنة (SECCOMP) على جميع التطبيقات. تقتصر قائمة أسماء النظام المسموح بها على تلك التي تظهر عن طريق النظام الثنائي. وعلى الرغم من وجود العديد من استدعاءات النظام الأخرى التي يتم توفيرها للتوافق مع الأنظمة القديمة، فإننا ننصح بعدم استخدامها.
  • يتم الآن تشغيل عناصر WebView في تطبيقك في وضع العمليات المتعدّدة. يتم التعامل مع محتوى الويب في عملية منفصلة ومعزولة عن عملية تضمين التطبيق لتحسين مستوى الأمان.
  • لم يعُد بإمكانك افتراض أنّ حِزم APK متوفّرة في أدلة تنتهي أسماؤها بـ -1 أو -2. يجب أن تستخدم التطبيقات sourceDir للحصول على الدليل، وألا تعتمد على تنسيق الدليل مباشرةً.
  • للحصول على معلومات عن تحسينات الأمان المرتبطة باستخدام المكتبات المجمّعة من رموز برمجية أصلية، يُرجى الاطّلاع على المكتبات الأصلية.

بالإضافة إلى ذلك، يوفّر Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) التغييرات التالية المتعلّقة بتثبيت التطبيقات غير المعروفة من مصادر غير معروفة:

  • أصبحت قيمة الإعداد القديم INSTALL_NON_MARKET_APPS الآن 1 دائمًا. لتحديد ما إذا كان بإمكان مصدر غير معروف تثبيت التطبيقات باستخدام أداة تثبيت الحزمة، عليك بدلاً من ذلك استخدام القيمة المعروضة canRequestPackageInstalls().
  • وإذا حاولت تغيير قيمة INSTALL_NON_MARKET_APPS باستخدام setSecureSetting()، سيتم عرض UnsupportedOperationException. ولمنع المستخدمين من تثبيت التطبيقات غير المعروفة باستخدام مصادر غير معروفة، عليك بدلاً من ذلك تطبيق القيد DISALLOW_INSTALL_UNKNOWN_SOURCES على المستخدم.
  • يتم تلقائيًا تفعيل القيد DISALLOW_INSTALL_UNKNOWN_SOURCES للمستخدمين في الملفات الشخصية المُدارة التي تم إنشاؤها على أجهزة Android 8.0 (المستوى 26 لواجهة برمجة التطبيقات). بالنسبة إلى الملفات الشخصية المُدارة الحالية على الأجهزة التي تمت ترقيتها إلى Android 8.0، يتم تفعيل تقييد المستخدم DISALLOW_INSTALL_UNKNOWN_SOURCES تلقائيًا ما لم يوقِف مالك الملف الشخصي صراحةً هذا القيد (قبل الترقية) من خلال ضبط INSTALL_NON_MARKET_APPS على 1.

لمعرفة تفاصيل إضافية حول تثبيت التطبيقات غير المعروفة، يُرجى الاطّلاع على دليل أذونات تثبيت التطبيقات غير المعروفة.

للحصول على إرشادات إضافية حول كيفية تعزيز أمان تطبيقك، يمكنك الاطّلاع على مقالة الأمان لمطوِّري تطبيقات Android.

الخصوصية

يُجري Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) التغييرات التالية المتعلقة بالخصوصية على النظام الأساسي.

  • تتعامل المنصّة الآن مع المعرّفات بشكلٍ مختلف.
    • بالنسبة إلى التطبيقات التي تم تثبيتها قبل إطلاق التحديث عبر الهواء إلى إصدار Android 8.0 (المستوى 26 لواجهة برمجة التطبيقات) (المستوى 26 من واجهة برمجة التطبيقات)، تظل قيمة ANDROID_ID كما هي ما لم يتم إلغاء تثبيتها ثم إعادة تثبيتها بعد التحديث عبر الهواء. للحفاظ على القيم في جميع عمليات إلغاء التثبيت بعد التحديث عبر الهواء، يمكن للمطوّرين ربط القيم القديمة والجديدة باستخدام ميزة الاحتفاظ بنسخة احتياطية من المفتاح/القيمة.
    • في التطبيقات المثبّتة على جهاز يعمل بنظام التشغيل Android 8.0، يتم الآن تحديد قيمة ANDROID_ID لكل مفتاح توقيع تطبيق ولكل مستخدم. وتكون قيمة ANDROID_ID فريدة لكل مجموعة من مفتاح توقيع التطبيق والمستخدِم والجهاز. ونتيجةً لذلك، لن يظهر معرّف Android نفسه للتطبيقات التي تتضمّن مفاتيح توقيع مختلفة وتعمل على الجهاز نفسه (حتى للمستخدم نفسه).
    • لا تتغير قيمة ANDROID_ID عند إلغاء تثبيت الحزمة أو إعادة تثبيتها، طالما أنّ مفتاح التوقيع هو نفسه (ولم يكن التطبيق مثبَّتًا قبل إطلاقه عبر الهواء على إصدار Android 8.0).
    • لا تتغير قيمة ANDROID_ID حتى إذا تسبّب تحديث النظام في تغيير مفتاح توقيع الحزمة.
    • على الأجهزة التي يتم شحنها باستخدام "خدمات Google Play" والمعرِّف الإعلاني، عليك استخدام المعرِّف الإعلاني. المعرِّف الإعلاني هو نظام بسيط وعادي لتحقيق الربح من التطبيقات، وهو عبارة عن معرّف فريد يمكن للمستخدم إعادة ضبطه. ويتم توفيره من خلال "خدمات Google Play".

      أمّا الشركات المصنّعة الأخرى للأجهزة، فعليها مواصلة تقديم السمة ANDROID_ID.

  • ويؤدي الاستعلام عن خاصية النظام net.hostname إلى إنشاء نتيجة فارغة.

تسجيل الاستثناءات غير المرصودة

إذا ثبَّت أحد التطبيقات Thread.UncaughtExceptionHandler لا يستدعي رمز Thread.UncaughtExceptionHandler التلقائي، لن يوقف النظام التطبيق عند حدوث استثناء غير مرصود. بدءًا من Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات)، يسجّل النظام تتبع تسلسل استدعاء الدوال البرمجية الاستثناء في هذه الحالة. في الإصدارات السابقة من النظام الأساسي، لم يسجّل النظام تتبع تكديس الاستثناء.

ننصح دائمًا باستدعاء عمليات تنفيذ Thread.UncaughtExceptionHandler المخصّصة للمعالج التلقائي، لأنّ التطبيقات التي تتبع هذا الاقتراح لا تتأثر بالتغيير الذي يتم في Android 8.0.

تغيير توقيع findViewById()

تعرض جميع مثيلات الطريقة findViewById() الآن <T extends View> T بدلاً من View. وينتج عن هذا التغيير الآثار التالية:

  • قد ينتج عن ذلك أنّ الرمز الحالي أصبح له نوع عرض غامض حاليًا، على سبيل المثال إذا كان هناك كل من someMethod(View) وsomeMethod(TextView) يأخذ نتيجة الاستدعاء إلى findViewById().
  • وعند استخدام لغة المصدر Java 8، يتطلب ذلك بثًا صريحًا إلى View عندما يكون نوع الإرجاع غير محدود (على سبيل المثال، assertNotNull(findViewById(...)).someViewMethod()).
  • يجب تعديل نوع العرض في عمليات إلغاء طُرق findViewById() غير النهائية (مثل Activity.findViewById()).

تغيير إحصاءات استخدام مزود جهات الاتصال

في الإصدارات السابقة من نظام التشغيل Android، يتيح المكوّن "مزوّد خدمة جهات الاتصال" للمطوّرين الحصول على بيانات الاستخدام لكل جهة اتصال. تكشف بيانات الاستخدام هذه معلومات عن كل عنوان بريد إلكتروني وكل رقم هاتف مرتبط بجهة اتصال، بما في ذلك عدد مرات الاتصال بجهة الاتصال وآخر مرة تم فيها الاتصال بجهة الاتصال. تتمكن التطبيقات التي تطلب إذن READ_CONTACTS من قراءة هذه البيانات.

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

يؤثّر تغيير السلوك هذا في مَعلمات طلبات البحث التالية:

التعامل مع المجموعة

أصبح التنسيق AbstractCollection.removeAll() وAbstractCollection.retainAll() يطرحان الآن علامة NullPointerException بدلاً من ذلك، ولكن في السابق، لم يكن يتم طرح العلامة NullPointerException عندما كانت المجموعة فارغة. هذا التغيير يجعل السلوك متسقًا مع التوثيق.

Android Enterprise

يغيّر Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) سلوك بعض واجهات برمجة التطبيقات وميزات تطبيقات المؤسسات، بما في ذلك وحدات التحكّم بسياسة الجهاز (DPC). وتشمل التغييرات ما يلي:

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

للاطّلاع على جميع التغييرات التي طرأت على المؤسسة في Android 8.0 (المستوى 26 لواجهة برمجة التطبيقات) ومعرفة مدى تأثيرها في تطبيقك، يمكنك الاطّلاع على مقالة Android in the Enterprise.

التطبيقات التي تستهدف الإصدار Android 8.0

وتنطبق هذه التغييرات في السلوك حصريًا على التطبيقات التي تستهدف Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث. أمّا التطبيقات التي تعمل على تجميع Android 8.0 أو التي تضبط targetSdkVersion على الإصدار 8.0 أو الإصدارات الأحدث من نظام التشغيل Android، فيجب تعديل تطبيقاتها لإتاحة هذه السلوكيات بشكل صحيح، حيثما ينطبق ذلك على التطبيق.

نوافذ التنبيهات

لن تتمكّن التطبيقات التي تستخدم إذن SYSTEM_ALERT_WINDOW من استخدام أنواع النوافذ التالية لعرض نوافذ التنبيهات فوق التطبيقات ونوافذ النظام الأخرى:

وبدلاً من ذلك، يجب أن تستخدم التطبيقات نوع نافذة جديدًا يُسمى TYPE_APPLICATION_OVERLAY.

عند استخدام نوع نافذة TYPE_APPLICATION_OVERLAY لعرض نوافذ التنبيهات لتطبيقك، يُرجى مراعاة الخصائص التالية لنوع النافذة الجديد:

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

إشعارات تغيير المحتوى

يغيّر Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) سلوك ContentResolver.notifyChange() وregisterContentObserver(Uri, boolean, ContentObserver) بالنسبة إلى التطبيقات التي تستهدف الإصدار 8.0 من Android.

تتطلّب واجهات برمجة التطبيقات هذه الآن تحديد قيمة ContentProvider صالحة للسلطة في جميع أنظمة Uris. يساعد تحديد ContentProvider صالح باستخدام الأذونات ذات الصلة في حماية تطبيقك من تغييرات المحتوى التي تجريها التطبيقات الضارة، ومنعك من تسريب بيانات يُحتمَل أن تكون خاصة إلى تطبيقات ضارة.

عرض التركيز

يمكن الآن أيضًا التركيز تلقائيًا على كائنات View القابلة للنقر. إذا أردت أن يكون الكائن View قابلاً للنقر ولكن غير قابل للتركيز، اضبط السمة android:focusable على false في ملف XML الخاص بالتنسيق الذي يحتوي على View، أو مرِّر false إلى setFocusable() في منطق واجهة المستخدم الخاصة بالتطبيق.

مطابقة وكيل المستخدم في رصد المتصفِّح

يتضمّن الإصدار Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) والإصدارات الأحدث سلسلة معرّف الإصدار OPR. قد تؤدي بعض مطابقات الأنماط إلى أن يخطئ منطق رصد المتصفِّح في تحديد متصفِّح غير Opera على أنّه Opera. في ما يلي مثال على مطابقة النمط:

if(p.match(/OPR/)){k="Opera";c=p.match(/OPR\/(\d+.\d+)/);n=new Ext.Version(c[1])}

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

الأمان

تؤثّر التغييرات التالية في الأمان في Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات):

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

للحصول على إرشادات إضافية حول كيفية تعزيز أمان تطبيقك، يمكنك الاطّلاع على مقالة الأمان لمطوِّري تطبيقات Android.

الوصول إلى الحساب وقابلية العثور عليه

في Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات)، لا يمكن للتطبيقات الحصول على إمكانية الوصول إلى حسابات المستخدمين ما لم يكن برنامج المصادقة يملك الحسابات أو يمنح المستخدم ذلك الإذن. لم يعُد إذن "GET_ACCOUNTS" كافيًا. ولكي يتم منحك إذن الوصول إلى حساب، يجب أن تستخدم التطبيقات AccountManager.newChooseAccountIntent() أو طريقة خاصة ببرنامج المصادقة. بعد الحصول على إمكانية الدخول إلى الحسابات، يمكن للتطبيق الاتصال AccountManager.getAccounts() للوصول إليها.

سيوقف Android 8.0 LOGIN_ACCOUNTS_CHANGED_ACTION. بدلاً من ذلك، يجب أن تستخدم التطبيقات addOnAccountsUpdatedListener() للحصول على آخر الأخبار حول الحسابات أثناء وقت التشغيل.

للحصول على معلومات عن واجهات برمجة التطبيقات والطرق الجديدة التي تمت إضافتها للوصول إلى الحساب وقابلية اكتشافه، يُرجى الاطّلاع على الوصول إلى الحساب وقابلية اكتشافه في قسم "واجهات برمجة التطبيقات الجديدة" في هذا المستند.

الخصوصية

تؤثّر التغييرات التالية في الخصوصية في Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات).

  • لم تعُد خصائص النظام net.dns1 وnet.dns2 وnet.dns3 وnet.dns4 متاحة، وهو تغيير يحسّن الخصوصية على المنصة.
  • للحصول على معلومات الشبكات، مثل خوادم نظام أسماء النطاقات، يمكن للتطبيقات التي لديها إذن ACCESS_NETWORK_STATE تسجيل عنصر NetworkRequest أو NetworkCallback. تتوفّر هذه الفئات في الإصدار Android 5.0 (المستوى 21 من واجهة برمجة التطبيقات) والإصدارات الأحدث.
  • تم إيقاف Build.SERIAL نهائيًا. وبدلاً من ذلك، يجب على التطبيقات التي تحتاج إلى معرفة الرقم التسلسلي للجهاز استخدام طريقة Build.getSerial() الجديدة التي تتطلّب الحصول على إذن READ_PHONE_STATE.
  • لم تعُد واجهة برمجة التطبيقات LauncherApps تسمح لتطبيقات الملف الشخصي للعمل بالحصول على معلومات حول الملف الشخصي الأساسي. عندما يكون المستخدم في ملف شخصي للعمل، تعمل واجهة برمجة التطبيقات LauncherApps كما لو لم يتم تثبيت أي تطبيقات في ملفات شخصية أخرى ضمن مجموعة الملفات الشخصية نفسها. كما أسلفنا، تؤدي محاولات الوصول إلى ملفات شخصية غير ذات صلة إلى SecurityExceptions.

الأذونات

قبل الإصدار Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات)، إذا طلب أحد التطبيقات إذنًا في وقت التشغيل وتم منحه الإذن، كان النظام أيضًا قد منَح التطبيق بشكل غير صحيح باقي الأذونات التي تنتمي إلى مجموعة الأذونات نفسها والتي تم تسجيلها في ملف البيان.

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

على سبيل المثال، لنفترض أنّ أحد التطبيقات يدرج كلاً من READ_EXTERNAL_STORAGE وWRITE_EXTERNAL_STORAGE في ملف البيان. يطلب التطبيق الإضافة "READ_EXTERNAL_STORAGE" ويمنحها المستخدم. إذا كان التطبيق يستهدف المستوى 25 من واجهة برمجة التطبيقات أو أقل، سيمنح النظام أيضًا WRITE_EXTERNAL_STORAGE في الوقت نفسه، لأنّه ينتمي إلى مجموعة أذونات STORAGE نفسها وهو مسجَّل أيضًا في ملف البيان. إذا كان التطبيق يستهدف الإصدار Android 8.0 (المستوى 26 لواجهة برمجة التطبيقات)، سيمنح النظام READ_EXTERNAL_STORAGE فقط في ذلك الوقت، ومع ذلك، إذا طلب التطبيق لاحقًا WRITE_EXTERNAL_STORAGE، سيمنح النظام هذا الامتياز على الفور بدون طلب ذلك من المستخدم.

الوسائط

  • ويمكن لإطار العمل التحايل التلقائي على المحتوى الصوتي بمفرده. في هذه الحالة، عندما يتم التركيز على طلب تطبيق آخر باستخدام AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK، يخفّض التطبيق الذي يتم التركيز عليه مستوى الصوت ولكنه لا يتلقّى عادةً معاودة الاتصال بـ onAudioFocusChange() ولن يفقد تركيز الصوت. وتتوفر واجهات برمجة تطبيقات جديدة لإلغاء هذا السلوك للتطبيقات التي تحتاج إلى الإيقاف المؤقت بدلاً من تجنب التداخل.
  • عندما يجري المستخدم مكالمة هاتفية، يتم كتم صوت ساحات مشاركات الوسائط النشطة طوال مدة المكالمة.
  • يجب أن تستخدم جميع واجهات برمجة التطبيقات ذات الصلة بالصوت AudioAttributes بدلاً من أنواع البث الصوتي لوصف حالة استخدام تشغيل الصوت. مواصلة استخدام أنواع البث الصوتي لعناصر التحكّم في مستوى الصوت فقط ولا تزال الاستخدامات الأخرى لأنواع البث صالحة (على سبيل المثال، الوسيطة streamType للأداة الإنشائية AudioTrack المتوقّفة)، لكن النظام يسجّل ذلك كخطأ.
  • عند استخدام AudioTrack، إذا كان التطبيق يطلب مخزنًا مؤقتًا للصوت كبيرًا بما يكفي، سيحاول إطار العمل استخدام مخرجات المخزن المؤقت العميق إذا كان متاحًا.
  • في نظام التشغيل Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات)، تختلف طريقة التعامل مع أحداث أزرار الوسائط:
    1. لم تتغيّر طريقة التعامل مع أزرار الوسائط في نشاط واجهة المستخدم، إذ لا تزال للأنشطة التي تعمل في المقدّمة تحظى بالأولوية في التعامل مع أحداث أزرار الوسائط.
    2. إذا لم يعالج النشاط الذي تعمل في المقدّمة حدث زر الوسائط، سيوجِّه النظام الحدث إلى التطبيق الذي شغَّل الصوت مؤخرًا على الجهاز. لا يتم أخذ حالة النشاط والعلامات وحالة التشغيل لجلسة وسائط في الاعتبار عند تحديد التطبيق الذي يتلقى أحداث أزرار الوسائط.
    3. إذا تم إصدار جلسة الوسائط الخاصة بالتطبيق، يرسل النظام حدث زر الوسائط إلى MediaButtonReceiver في التطبيق، إذا كان متوفرًا.
    4. وفي جميع الحالات الأخرى، يتجاهل النظام حدث زر الوسائط.

المكتبات الأصلية

في التطبيقات التي تستهدف Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات)، لا يتم تحميل المكتبات الأصلية بعد الآن إذا كانت تحتوي على أي شريحة تحميل قابلة للكتابة والتنفيذ في الوقت نفسه. قد تتوقف بعض التطبيقات عن العمل بسبب هذا التغيير إذا كانت تحتوي على مكتبات أصلية بها أقسام تحميل غير صحيحة. وهذا إجراء تعزّز الأمن

لمزيد من المعلومات، اطّلِع على الشرائح القابلة للكتابة والتنفيذ.

ترتبط تغييرات الروابط بمستوى واجهة برمجة التطبيقات الذي يستهدفه التطبيق. إذا كان هناك تغيير في الرابط على مستوى واجهة برمجة التطبيقات المستهدَف، لن يتمكّن التطبيق من تحميل المكتبة. وإذا كنت تستهدِف مستوى واجهة برمجة تطبيقات أقل من مستوى واجهة برمجة التطبيقات الذي يحدث فيه تغيير الرابط، تعرض دالة logcat تحذيرًا.

التعامل مع المجموعة

في الإصدار Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات)، يتم تنفيذ Collections.sort() في أعلى List.sort(). العكس صحيح في Android 7.x (المستوى 24 و25 من واجهة برمجة التطبيقات): كان التنفيذ التلقائي لـ List.sort() يُسمى Collections.sort().

يسمح هذا التغيير لـ Collections.sort() بالاستفادة من تطبيقات List.sort() المحسّنة، ولكن مع القيود التالية:

  • يجب ألا تطلب عمليات تنفيذ List.sort() استدعاء Collections.sort()، لأنّ ذلك سيؤدي إلى تجاوز تسلسل استدعاء الدوال البرمجية بسبب التكرار اللا نهائي. بدلاً من ذلك، إذا كنت تريد السلوك التلقائي في تنفيذ List، عليك تجنُّب إلغاء sort().

    إذا نفّذت إحدى الفئات الرئيسية السمة sort() بشكل غير صحيح، يمكنك عادةً إلغاء السمة List.sort() من خلال تنفيذ عملية تنفيذ تستند إلى List.toArray() وArrays.sort() وListIterator.set(). مثلاً:

    @Override
    public void sort(Comparator<? super E> c) {
      Object[] elements = toArray();
      Arrays.sort(elements, c);
      ListIterator<E> iterator = (ListIterator<Object>) listIterator();
      for (Object element : elements) {
        iterator.next();
        iterator.set((E) element);
      }
    }
    

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

    @Override
    public void sort(Comparator<? super E> comparator) {
      if (Build.VERSION.SDK_INT <= 25) {
        Collections.sort(this);
      } else {
        super.sort(comparator);
      }
    }
    

    إذا كنت تستخدم الخيار الثاني فقط لأنّك تريد إتاحة طريقة sort() على جميع مستويات واجهة برمجة التطبيقات، ننصحك باختيار اسم فريد لها، مثل sortCompat()، بدلاً من إلغاء sort().

  • يتم الآن احتساب Collections.sort() كتعديل هيكل في عمليات تنفيذ القوائم التي تحمل الاسم sort(). على سبيل المثال، في إصدارات النظام الأساسي التي تسبق الإصدار Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات)، كان من الممكن عرض الخطأ ConcurrentModificationException في حال إجراء الترتيب من خلال طلب الرمز List.sort()، في حال تكرار طلب رمز الاستجابة ArrayList واستدعاء الرمز sort() عليه بعد إكمال عملية التكرار. لم يتم إنشاء استثناء للقاعدة Collections.sort().

    يجعل هذا التغيير سلوك المنصة أكثر اتساقًا، فأي من النهجَين يؤديان الآن إلى ConcurrentModificationException.

سلوك تحميل الفئات

يتحقّق نظام Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) للتأكّد من أنّ أدوات تحميل الفئات لا تبطل افتراضات وقت التشغيل عند تحميل فئات جديدة. يتم إجراء عمليات التحقّق هذه عمّا إذا كانت تتم الإشارة إلى الفئة من خلال Java (من forName()) أو رمز بايت Davik أو JNI. لا يعترض النظام الأساسي الطلبات المباشرة من Java إلى طريقة loadClass()، ولا يتحقق من نتائج هذه الطلبات. وينبغي ألا يؤثر هذا السلوك في أداء برامج تحميل الفئات ذات الأداء الجيد.

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

يتحقّق النظام الأساسي أيضًا من أنّ البيانات الوصفية للفئات المطلوبة صالحة. ترصد عملية الفحص هذه استدعاءات JNI التي تحمِّل فئات مثل GetFieldID() بشكل غير مباشر، ما يؤدي إلى تمرير واصفات غير صالحة إلى تلك الفئات. على سبيل المثال، تعذّر العثور على حقل يحتوي على توقيع java/lang/String لأنّ هذا التوقيع غير صالح، يجب أن يكون Ljava/lang/String;.

ويختلف هذا عن استدعاء JNI لـ FindClass() حيث يكون java/lang/String اسمًا صالحًا ومؤهلاً بالكامل.

لا يتيح Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) إمكانية استخدام أدوات تحميل متعددة للفئات لمحاولة تحديد الفئات باستخدام كائن DexFile نفسه. تؤدي محاولة إجراء ذلك إلى عرض وقت تشغيل Android للخطأ InternalError مع الرسالة "محاولة تسجيل ملف dex <filename> مع أدوات تحميل فئات متعددة".

تم إيقاف DexFile API نهائيًا الآن، وننصحك بشدة باستخدام إحدى أدوات تحميل الفئات للنظام الأساسي، بما في ذلك PathClassLoader أو BaseDexClassLoader.

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

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

تحذير: في إصدارات النظام الأساسي الأقدم من Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات)، قد يؤدي خرق هذه الافتراضات إلى تحديد الفئة نفسها عدة مرات، وتلف في الذاكرة بسبب الارتباك في الفئات، والتأثيرات الأخرى غير المرغوب فيها.