التغييرات في سلوك الإصدار 8.0 من نظام التشغيل Android

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

تؤثر معظم هذه التغييرات في جميع التطبيقات، بغض النظر عن إصدار Android الذي تستهدفه. ومع ذلك، هناك العديد من التغييرات تؤثر فقط في التطبيقات التي تستهدف الإصدار 8.0 من نظام التشغيل Android. لزيادة الوضوح إلى أقصى حد، تنقسم هذه الصفحة إلى قسمين: التغييرات على جميع التطبيقات والتغييرات على التطبيقات التي تستهدف الإصدار 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 مع ظهور تطبيقات Android على ChromeOS وغير ذلك من أشكال الأجهزة الكبيرة، مثل الأجهزة اللوحية. في نظام التشغيل 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) التي تمت صياغتها بشكل غير صحيح.

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

      لم يعُد النظام يرسل عنوان تفويض الخادم الوكيل على عنوان 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 كما هي ما لم يتم إلغاء تثبيتها ثم إعادة تثبيتها بعد التحديث عبر الهواء. للحفاظ على القيم في جميع عمليات إلغاء التثبيت بعد التحديث عبر الهواء، يمكن لمطوّري البرامج ربط القيم القديمة والجديدة باستخدام الاحتفاظ بنسخة احتياطية من المفتاح/القيمة.
    • بالنسبة إلى التطبيقات المثبّتة على جهاز يعمل بالإصدار 8.0 من نظام التشغيل Android، يتم الآن تحديد قيمة ANDROID_ID لكل مفتاح توقيع التطبيق ولكل مستخدم. وتكون قيمة ANDROID_ID فريدة لكل مجموعة من مفتاح توقيع التطبيق والمستخدم والجهاز. ونتيجةً لذلك، لن يظهر معرّف Android نفسه للتطبيقات التي تستخدم مفاتيح توقيع مختلفة تعمل على الجهاز نفسه (حتى للمستخدم نفسه).
    • لا تتغير قيمة ANDROID_ID عند إلغاء تثبيت الحزمة أو إعادة تثبيتها، طالما أنّ مفتاح التوقيع هو نفسه (ولم يتم تثبيت التطبيق قبل إطلاق التحديث عبر الهواء إلى الإصدار 8.0 من نظام التشغيل Android).
    • لن تتغيّر قيمة 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 في 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) في التطبيقات التي تستهدف الإصدار Android 8.0.

تتطلّب واجهات برمجة التطبيقات هذه الآن تحديد قيمة 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 API كما لو لم يتم تثبيت أي تطبيقات في ملفات شخصية أخرى ضمن مجموعة الملفات الشخصية نفسها. وكما أسلفنا، تؤدي محاولات الوصول إلى ملفات شخصية غير ذات صلة إلى SecurityExceptions.

الأذونات

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

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

على سبيل المثال، لنفترض أنّ أحد التطبيقات يدرج كلاً من 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 من واجهة برمجة التطبيقات)، كان من الممكن أن يؤدي تكرار ArrayList وطلب sort() عليه في جزء من التكرار خلال التكرار إلى عرض ConcurrentModificationException إذا تم الترتيب من خلال طلب List.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 لواجهة برمجة التطبيقات)، يمكن أن يؤدي خرق هذه الافتراضات إلى تعريف الفئة نفسها عدة مرات، وتلف كومة الذاكرة المؤقتة بسبب تضارب الفئات والتأثيرات الأخرى غير المرغوب فيها.