بالإضافة إلى الميزات والإمكانات الجديدة، يتضمّن الإصدار 8.0 من Android (المستوى 26 من واجهة برمجة التطبيقات) مجموعة متنوعة من التغييرات في سلوك النظام وواجهة برمجة التطبيقات. ويوضّح هذا المستند بعض التغييرات الرئيسية التي يجب أن تفهمها وتراعيها في تطبيقاتك.
تؤثر معظم هذه التغييرات في جميع التطبيقات، بغض النظر عن الإصدار المستهدف من Android. ومع ذلك، ستؤثّر عدّة تغييرات في التطبيقات التي تستهدف الإصدار 8.0 من نظام التشغيل Android فقط. لزيادة الوضوح، تم تقسيم هذه الصفحة إلى قسمَين: التغييرات التي تخصّ جميع التطبيقات والتغييرات التي تخصّ التطبيقات التي تستهدف Android 8.0.
التغييرات على جميع التطبيقات
تنطبق تغييرات السلوك هذه على
حدود التنفيذ في الخلفية
في إطار التغييرات التي يقدّمها الإصدار 8.0 من Android (المستوى 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 من واجهة برمجة التطبيقات)، تستخدم ال methods التالية الآن Locale.getDefault(Category.DISPLAY)
بدلاً من Locale.getDefault()
:
يتم أيضًا
الرجوع إلى Locale.getDefault()
في Locale.getDisplayScript(Locale)
عندما تكون قيمة
displayScript المحدّدة للوسيطة Locale
غير متاحة.
في ما يلي التغييرات الإضافية المتعلقة باللغة والنشر على مستوى العالم:
- يؤدي استدعاء
Currency.getDisplayName(null)
إلى ظهورNullPointerException
، ما يتوافق مع السلوك المُسجَّل. - تم تغيير تحليل اسم المنطقة الزمنية. في السابق، كانت
أجهزة Android تستخدِم قيمة ساعة النظام التي يتم تحليل عيّنة منها عند التمهيد
لتخزين أسماء المناطق الزمنية المستخدَمة لتحليل تواريخ
وأوقاتها. نتيجةً لذلك، قد يتأثّر التحليل سلبًا إذا كانت ساعة
النظام غير صحيحة في وقت التشغيل أو في حالات أخرى نادرة.
في الحالات الشائعة، يستخدم منطق التحليل ICU و قيمة ساعة النظام الحالية عند تحليل أسماء المناطق الزمنية. يقدّم هذا التغيير نتائج أكثر دقة، وقد تختلف عن الإصدارات السابقة من Android عندما يستخدم تطبيقك فئات مثل
SimpleDateFormat
. - يُحدِّث نظام التشغيل Android 8.0 (المستوى 26 لواجهة برمجة التطبيقات) إصدار ICU إلى الإصدار 58.
نوافذ التنبيهات
إذا كان التطبيق يستخدم إذن SYSTEM_ALERT_WINDOW
ويستخدم أحد أنواع النوافذ التالية لمحاولة عرض
نوافذ تنبيه فوق التطبيقات الأخرى ونوافذ النظام:
...ثم تظهر هذه النوافذ دائمًا أسفل النوافذ التي تستخدم نوع النافذة
TYPE_APPLICATION_OVERLAY
. إذا كان التطبيق يستهدف الإصدار 8.0 من نظام التشغيل Android (المستوى 26 لواجهة برمجة التطبيقات)، يستخدم التطبيق نوع النافذة
TYPE_APPLICATION_OVERLAY
لعرض نوافذ التنبيهات.
لمزيد من المعلومات، يُرجى الاطّلاع على قسم أنواع النوافذ الشائعة لنوافذ التنبيه ضمن التغييرات في السلوك للتطبيقات التي تستهدف الإصدار 8.0 من نظام التشغيل Android.
الإدخال والتنقّل
مع ظهور تطبيقات Android على ChromeOS وغيرها من أشكال الأجهزة الكبيرة، مثل الأجهزة اللوحية، نشهد إعادة استخدام التنقل بلوحة المفاتيح ضمن تطبيقات Android. في الإصدار 8.0 من نظام التشغيل Android (المستوى 26 لواجهة برمجة التطبيقات)، أعدنا النظر في استخدام لوحة المفاتيح كجهاز إدخال للتنقّل، ما أدّى إلى توفير نموذجٍ أكثر موثوقية ويمكن التنبؤ به للتنقّل المستنِد إلى الأسهم والمفتاح التبويب.
وعلى وجه الخصوص، أجرينا التغييرات التالية على سلوك تركيز العنصر:
-
إذا لم تحدِّد أي ألوان لحالة التركيز لعنصر
View
(سواءً كان عنصرًا قابلاً للرسم في المقدّمة أو الخلفية)، سيحدِّد إطار العمل الآن لونًا تلقائيًا لتمييز التركيز لView
. عنصر التمييز هذا هو عنصر قابل للرسم يشبه التموج ويستند إلى موضوع النشاط.إذا كنت لا تريد أن يستخدم عنصر
View
تمييزًا مميّزًا بشكلٍ تلقائي عند تلقّيه التركيز، اضبط سمةandroid:defaultFocusHighlightEnabled
علىfalse
في ملف XML الخاص بالتنسيق الذي يحتوي علىView
، أو أرسِلfalse
إلىsetDefaultFocusHighlightEnabled()
في منطق واجهة المستخدم في تطبيقك. - لاختبار مدى تأثير إدخال لوحة المفاتيح في التركيز على عنصر واجهة المستخدم، يمكنك تفعيل خيار المطوّر الرسم > عرض حدود التنسيق. في الإصدار 8.0 من نظام التشغيل Android، يعرض هذا الخيار رمز "X" فوق العنصر الذي يتم عليه التركيز حاليًا.
بالإضافة إلى ذلك، يتم تلقائيًا دمج جميع عناصر شريط الأدوات في Android 8.0 في مجموعات تنقّل باستخدام لوحة المفاتيح، مما يسهّل على المستخدمين التنقل في كل شريط أدوات وخارجه بشكلٍ كامل.
للحصول على مزيد من المعلومات حول كيفية تحسين إتاحة التنقل بلوحة المفاتيح داخل التطبيق، اقرأ دليل إتاحة التنقل باستخدام لوحة المفاتيح.
الملء التلقائي للنماذج على الويب
بما أنّ إطار عمل preenchimento automático (الملء التلقائي) في 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 أو مَعلمات طلب البحث أو الأجزاء المطلوبة.
- لا يمكن أن تحتوي معرّفات الموارد المنتظمة على تصنيفات فارغة.
في السابق، كانت المنصة تتيح حلًا بديلاً لقبول التصنيفات الفارغة في أسماء المضيفين، ما يشكّل استخدامًا غير قانوني لمعرّفات الموارد المنتظمة. وكان هذا الحل المخصّص متوافقًا مع إصدارات libcore القديمة. إذا استخدم المطوّرون واجهة برمجة التطبيقات بشكل غير صحيح، ستظهر لهم رسالة ADB: "يحتوي عنوان URL example..com على تصنيفات فارغة في اسم المضيف. هذا التنسيق غير صحيح ولن يتم قبوله في الإصدارات المستقبلية من Android . يزيل نظام Android 8.0 هذا الحلّ البديل، ويعرض النظام قيمة ملف تعريف الارتباط null لعناوين URL ذات التنسيق غير الصالح.
- لا يؤدي تنفيذ HttpsURLConnection في Android 8.0 إلى استخدام إصدار غير آمن من بروتوكول أمان طبقة النقل (TLS) أو طبقة المقابس الآمنة (SSL).
- تم تغيير طريقة معالجة اتصالات 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) وإعادة المحاولة. - يطبّق الإصدار 8.0 من نظام التشغيل Android (المستوى 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
user تلقائيًا ما لم يوقِف مالك الملف الشخصي هذا القيد صراحةً (قبل الترقية) من خلال ضبطINSTALL_NON_MARKET_APPS
على 1.
لمزيد من التفاصيل حول تثبيت التطبيقات غير المعروفة، يُرجى الاطّلاع على دليل أذونات تثبيت التطبيقات غير المعروفة.
للحصول على إرشادات إضافية حول تحسين أمان تطبيقك، يُرجى الاطّلاع على مقالة الأمان لمطوّري تطبيقات Android.
الخصوصية
يُجري نظام التشغيل Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) التحسينات التالية المتعلّقة بالخصوصية في النظام الأساسي:
- تتعامل المنصة الآن مع المعرّفات بشكلٍ مختلف.
-
بالنسبة إلى التطبيقات التي تم تثبيتها قبل تحديث OTA إلى إصدار
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
.
-
بالنسبة إلى التطبيقات التي تم تثبيتها قبل تحديث OTA إلى إصدار
Android 8.0 (المستوى 26 لواجهة برمجة التطبيقات)
(المستوى 26 لواجهة برمجة التطبيقات)، تظل قيمة
- ينتج عن طلب البحث عن خاصية النظام
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 في المؤسسات.
التطبيقات التي تستهدف الإصدار 8.0 من نظام التشغيل Android
تنطبق تغييرات السلوك هذه حصريًا على التطبيقات التي تستهدف
الإصدار 8.0 من نظام التشغيل Android (المستوى 26 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث. أمّا التطبيقات التي يتم تجميعها استنادًا إلى الإصدار 8.0 من نظام التشغيل Android أو التي تم ضبط targetSdkVersion
على Android 8.0 أو إصدارًا أحدث، فيجب أن تعدّل
التطبيقات لتتوافق مع هذه السلوكيات بشكل صحيح، حيثما ينطبق ذلك على التطبيق.
نوافذ التنبيهات
لن تتمكّن التطبيقات التي تستخدم إذن SYSTEM_ALERT_WINDOW
من استخدام أنواع النوافذ التالية لعرض نوافذ التنبيه
فوق التطبيقات الأخرى ونوافذ النظام:
بدلاً من ذلك، يجب أن تستخدم التطبيقات نوع نافذة جديدًا يُعرف باسم
TYPE_APPLICATION_OVERLAY
.
عند استخدام نوع النافذة
TYPE_APPLICATION_OVERLAY
لعرض نوافذ تنبيهات لتطبيقك، يجب مراعاة السمات التالية
لنوع النافذة الجديد:
- تظهر نوافذ تنبيهات التطبيق دائمًا ضمن نوافذ النظام المهمة، مثل شريط الحالة وبرامج معالجة النصوص.
- يمكن للنظام نقل النوافذ التي تستخدم نوع النافذة
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()
في منطق واجهة المستخدم في تطبيقك.
مطابقة وكيل المستخدم في عملية اكتشاف المتصفّح
يتضمّن الإصدار 8.0 من نظام التشغيل Android (المستوى 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.
الوصول إلى الحساب وإمكانية العثور عليه
في الإصدار 8.0 من نظام التشغيل Android (المستوى 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
. تتوفّر هذه الفئات في الإصدار 5.0 من نظام التشغيل Android (المستوى 21 لواجهة برمجة التطبيقات) والإصدارات الأحدث. -
تم إيقاف العنصر Build.SERIAL نهائيًا.
على التطبيقات التي تحتاج إلى معرفة الرقم التسلسلي للأجهزة استخدام
Build.getSerial()
بدلاً من ذلك، والتي تتطلب إذنREAD_PHONE_STATE
. -
لم تعُد واجهة برمجة التطبيقات
LauncherApps
API تسمح لتطبيقات ملف العمل بالحصول على معلومات عن الملف الشخصي الأساسي. عندما يكون المستخدم في ملف شخصي للعمل، تعمل واجهة برمجة تطبيقاتLauncherApps
كما لو لم يتم تثبيت أي تطبيقات في ملفات شخصية أخرى ضمن مجموعة الملفات الشخصية نفسها. كما في السابق، يؤدي المحاولة للوصول إلى الملفات الشخصية غير ذات الصلة إلى حدوث SecurityExceptions.
الأذونات
قبل الإصدار 8.0 من Android (المستوى 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 من واجهة برمجة التطبيقات)، تختلف طريقة معالجة أحداث أزرار الوسائط:
- لم يتغيّر التعامل مع أزرار الوسائط في نشاط واجهة المستخدم: لا تزال الأنشطة التي تعمل في المقدّمة تحظى بالأولوية في التعامل مع أحداث أزرار الوسائط.
- إذا لم يعالج النشاط الذي يعمل في المقدّمة حدث زرّ الوسائط، يوجّه النظام الحدث إلى التطبيق الذي كان قد شغّل الصوت مؤخرًا على الجهاز. لا يتم أخذ الحالة النشطة والعلامات وحالة تشغيل جلسة الوسائط في الاعتبار عند تحديد التطبيق الذي يتلقّى أحداث زر الوسائط.
- إذا تم إنهاء جلسة الوسائط للتطبيق،
يرسل النظام حدث زر الوسائط إلى
MediaButtonReceiver
للتطبيق إذا كان يحتوي على زر. - وفي جميع الحالات الأخرى، يتخلّص النظام من حدث زر الوسائط.
المكتبات الأصلية
في التطبيقات التي تستهدف الإصدار 8.0 من نظام التشغيل Android (المستوى 26 من واجهة برمجة التطبيقات)، لن يتم تحميل المكتبات الأصلية بعد الآن إذا كانت تحتوي على أي جزء تحميل قابل للكتابة وقابل للتنفيذ. قد تتوقف بعض التطبيقات عن العمل بسبب هذا التغيير إذا كانت لديها مكتبات أصلية بها شرائح تحميل غير صحيحة. وهو إجراء يُعزز الأمان
لمزيد من المعلومات، اطّلِع على المقاطع القابلة للكتابة والتنفيذ.
ترتبط تغييرات الرابط بمستوى واجهة برمجة التطبيقات الذي يستهدفه التطبيق. إذا حدث تغيير في أداة الربط على مستوى واجهة برمجة التطبيقات المستهدَفة، لا يمكن للتطبيق تحميل المكتبة. إذا كنت تستهدف مستوى واجهة برمجة تطبيقات أقل من مستوى واجهة برمجة التطبيقات الذي يحدث فيه تغيير الرابط، يعرض logcat تحذيرًا.
معالجة المجموعة
وفي الإصدار Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات)،
يتم تنفيذ Collections.sort()
في
الجزء العلوي من List.sort()
. كان العكس
صحيحًا في الإصدار 7.x من نظام التشغيل Android (المستوى 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()
. على سبيل المثال، في إصدارات منصّة التشغيل التي تسبق الإصدار 8.0 من Android (المستوى 26 من واجهة برمجة التطبيقات)، كان من الممكن أن يؤدي تكرار المرور علىArrayList
واستدعاءsort()
عليه في منتصف عملية التكرار إلى حدوث خطأConcurrentModificationException
إذا تم إجراء الترتيب من خلال استدعاءList.sort()
.Collections.sort()
لم يُعرِض استثناءً.يؤدي هذا التغيير إلى جعل سلوك المنصة أكثر اتساقًا: يؤدي أي من النهجين الآن إلى
ConcurrentModificationException
.
سلوك تحميل الصف
يتحقّق نظام التشغيل Android 8.0 (المستوى 26 لواجهة برمجة التطبيقات) من أنّ أدوات تحميل الفئات لا تؤدي إلى
انتهاك افتراضات وقت التشغيل عند تحميل فئات جديدة. يتم تنفيذ عمليات التحقّق هذه سواءً كان يتم الإشارة إلى الفئة من Java (من
forName()
) أو
رمز Dalvik البرمجي أو JNI. لا تعترض المنصة المكالمات المباشرة من Java إلى loadClass()
، ولا تتحقّق من نتائج هذه المكالمات. ومن المفترض ألّا يؤثر هذا السلوك في عمل برامج تحميل الفئات ذات الأداء الجيد.
يتحقّق النظام الأساسي من أنّ واصف الفئة الذي يعرضه أداة تحميل الفئات
يتطابق مع الوصف المتوقّع. إذا لم يتطابق الوصف الذي تم إرجاعه،
تُرسِل المنصة خطأ NoClassDefFoundError
وتخزِّن في
الاستثناء رسالة تفصيلية تشير إلى التناقض.
تتحقّق المنصة أيضًا من صلاحية وصف الفئات المطلوبة. يرصد هذا الفحص استدعاءات JNI التي تُحمِّل بشكل غير مباشر فئات مثل GetFieldID()
،
وتُمرّر كلمات وصفية غير صالحة إلى تلك الفئات. على سبيل المثال، لم يتم العثور على حقل يتضمّن التوقيع
java/lang/String
لأنّ هذا التوقيع غير صالح. يجب أن يكون الحقل Ljava/lang/String;
.
يختلف ذلك عن طلب JNI إلى FindClass()
حيث يكون java/lang/String
اسمًا صالحًا مؤهلاً بالكامل.
لا يتيح نظام Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) استخدام عدة أدوات تحميل فئات لمحاولة تحديد الفِرق
باستخدام عنصر DexFile نفسه. تؤدي محاولة إجراء ذلك إلى ظهور خطأ
InternalError
في وقت تشغيل Android مع ظهور الرسالة "محاولة تسجيل ملف dex <filename>
باستخدام أدوات تحميل فئات متعددة".
تم إيقاف واجهة برمجة التطبيقات DexFile API نهائيًا، وننصحك بشدة باستخدام
أحد أداة تحميل الفئات في النظام الأساسي، بما في ذلك PathClassLoader
أو
BaseDexClassLoader
، بدلاً من ذلك.
ملاحظة: يمكنك إنشاء عدة أدوات تحميل فئات تشير إلى حاوية ملف APK أو JAR نفسها من نظام الملفات. لا يؤدي إجراء ذلك عادةً
إلى زيادة كبيرة في استخدام الذاكرة: إذا تم تخزين ملفات DEX في الحاوية بدلاً من
ضغطها، يمكن للنظام الأساسي تنفيذ عملية mmap
عليها بدلاً من
استخراجها مباشرةً. ومع ذلك، إذا كان على المنصة استخراج ملف DEX من الحاوية،
قد يؤدي الإشارة إلى ملف DEX بهذه الطريقة إلى استهلاك الكثير من الذاكرة.
في Android، تُعدّ جميع أدوات تحميل الفئات متوافقة مع التشغيل المتوازي. عندما تتسابق عدة سلاسل محادثات لتحميل الفئة نفسها باستخدام برنامج تحميل الفئة نفسه، تفوز أول سلسلة محادثات لإكمال العملية، ويتم استخدام النتيجة لسلاسل المحادثات الأخرى. يحدث هذا السلوك بغض النظر عمّا إذا كان أداة تحميل الفئات قد أرجعت الفئة نفسها أو أرجعت فئة مختلفة أو تسبّبت في حدوث استثناء. تتجاهل المنصة هذه الاستثناءات بصمت.
ملاحظة: في إصدارات النظام الأساسي الأقل من Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات)، يمكن أن يؤدي عدم الالتزام بهذه الافتراضات إلى تعريف الفئة نفسها عدة مرات، وفساد الحِزمة بسبب الخلط بين الفئات، وتأثيرات أخرى غير مرغوب فيها.