مثل الإصدارات السابقة، يتضمّن Android 14 تغييرات في السلوك قد تؤثر في تطبيقك، إلا أنّ التغييرات التالية المتعلّقة بالسلوك تسري حصريًا على التطبيقات التي تستهدف الإصدار 14 من Android أو الإصدارات الأحدث. إذا كان تطبيقك يستهدف الإصدار 14 من نظام التشغيل Android أو إصدارًا أحدث، عليك تعديله ليتوافق مع هذه السلوكيات بشكل صحيح، حيثما ينطبق ذلك.
تأكَّد أيضًا من مراجعة قائمة
التغييرات في السلوك التي تؤثر في جميع التطبيقات التي تعمل على الإصدار 14 من نظام التشغيل Android
بغض النظر عن
targetSdkVersion
التطبيق.
الوظيفة الأساسية
يجب إدراج أنواع الخدمات التي تعمل في المقدّمة.
إذا كان تطبيقك يستهدف نظام التشغيل Android 14، يجب تحديد نوع خدمة تعمل في المقدّمة على الأقل لكل خدمة تعمل في المقدّمة في تطبيقك. وعليك اختيار نوع خدمة في المقدّمة يمثّل حالة استخدام تطبيقك. يتوقع النظام أن تكون الخدمات التي تعمل في المقدّمة ذات نوع محدّد لتلبية حالة استخدام معيّنة.
إذا كانت حالة الاستخدام في تطبيقك غير مرتبطة بأي من هذه الأنواع، ننصحك بشدة بنقل منطقك إلى WorkManager أو مهام نقل البيانات التي يبدأها المستخدم.
فرض إذن BLUETOOTH_CONNECT في BluetoothAdapter
يفرض Android 14 إذن BLUETOOTH_CONNECT
عند استدعاء طريقة
BluetoothAdapter getProfileConnectionState()
للتطبيقات التي تستهدِف Android 14 (المستوى 34 من واجهة برمجة التطبيقات).
سبق أن تطلّبت هذه الطريقة إذن BLUETOOTH_CONNECT
، ولكن
لم يتم فرضها. تأكَّد من أنّ تطبيقك يذكر BLUETOOTH_CONNECT
في ملف
AndroidManifest.xml
الخاص به كما هو موضّح في المقتطف التالي، وتأكَّد من أنّ المستخدم قد منح الإذن قبل الاتصال بالرقم getProfileConnectionState
.
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
تحديثات OpenJDK 17
يواصل Android 14 العمل على تحديث المكتبات الأساسية لنظام Android للتوافق مع الميزات المتوفّرة في أحدث إصدارات OpenJDK LTS، بما في ذلك تحديثات المكتبة ودعم لغة Java 17 لمطوّري التطبيقات والأنظمة الأساسية.
يمكن أن تؤثر بعض هذه التغييرات في مدى توافق التطبيقات:
- التغييرات في التعبيرات العادية: أصبح الآن مسموحًا لمراجع المجموعات غير الصالحة
اتّباع دلالات OpenJDK عن كثب قد ترى حالات جديدة يتم فيها عرض
IllegalArgumentException
بواسطة الفئةjava.util.regex.Matcher
، لذا احرص على اختبار تطبيقك بحثًا عن المناطق التي تستخدم التعبيرات العادية. لتفعيل هذا التغيير أو إيقافه أثناء الاختبار، يمكنك تبديل علامةDISALLOW_INVALID_GROUP_REFERENCE
باستخدام أدوات إطار عمل التوافق. - معالجة UUID: تُجري الآن طريقة
java.util.UUID.fromString()
عمليات تحقق أكثر صرامة عند التحقق من وسيطة الإدخال، ولذلك قد يظهر لكIllegalArgumentException
أثناء إلغاء التسلسل. لتفعيل هذا التغيير أو إيقافه أثناء الاختبار، يمكنك تبديل علامةENABLE_STRICT_VALIDATION
باستخدام أدوات إطار عمل التوافق. - مشاكل ProGuard: في بعض الحالات، تؤدي إضافة فئة
java.lang.ClassValue
إلى حدوث مشكلة إذا حاولت تصغير تطبيقك وإخفاء مفاتيح فك تشفيره وتحسينه باستخدام ProGuard. تنشأ المشكلة من مكتبة Kotlin التي تغيّر سلوك وقت التشغيل استنادًا إلى ما إذا كانClass.forName("java.lang.ClassValue")
يعرض فئة أم لا. إذا تم تطوير تطبيقك بإصدار قديم من وقت التشغيل بدون توفّر الفئةjava.lang.ClassValue
، قد تزيل هذه التحسينات طريقةcomputeValue
من الفئات المشتقة منjava.lang.ClassValue
.
تعزز JobScheduler سلوك الشبكة ومعاودة الاتصال
تتوقّع خدمة JobScheduler منذ وقت تقديمها عودة تطبيقك من onStartJob
أو onStopJob
في غضون بضع ثوانٍ. قبل الإصدار Android 14، إذا كانت الوظيفة تستمر لفترة طويلة جدًا،
فإنها تتوقف وتفشل في صمت. إذا كان تطبيقك يستهدف الإصدار 14 من نظام التشغيل Android أو الإصدارات الأحدث ويتجاوز الوقت
الممنوح في سلسلة التعليمات الرئيسية، يعرض التطبيق خطأ ANR مع ظهور رسالة الخطأ "ما مِن استجابة
على onStartJob
" أو "لم يتم الردّ على onStopJob
". ننصحك بالنقل إلى
WorkManager، الذي يوفّر إمكانية معالجة البيانات غير المتزامنة أو نقل أي عمل مكثف إلى سلسلة محادثات في الخلفية.
تفرض JobScheduler
أيضًا شرطًا للإقرار بإذن ACCESS_NETWORK_STATE
في حال استخدام قيد
setRequiredNetworkType
أو setRequiredNetwork
. إذا لم يعلن تطبيقك عن
إذن ACCESS_NETWORK_STATE
عند جدولة المهمة وكان يستهدف
الإصدار 14 من نظام التشغيل Android أو إصدارًا أحدث، سيؤدي ذلك إلى الحصول على SecurityException
.
الأمان
القيود المفروضة على الأغراض الضمنية والمعلَّقة
بالنسبة إلى التطبيقات التي تستهدف الإصدار 14 من نظام التشغيل Android، يحظر نظام Android التطبيقات من إرسال أغراض ضمنية إلى مكوّنات التطبيقات الداخلية بالطرق التالية:
- يتم تسليم الأغراض الضمنية إلى المكونات التي تم تصديرها فقط. ويجب أن تستخدم التطبيقات هدفًا صريحًا للتسليم إلى مكونات لم يتم تصديرها أو تضع علامة على المكوّن للإشارة إلى أنّه تم تصديره.
- إذا أنشأ أحد التطبيقات هدفًا في انتظار المراجعة قابلاً للتغيير وهدفه لا يحدد مكونًا أو حزمة، سيطرح النظام الآن استثناءً.
تمنع هذه التغييرات التطبيقات الضارة من اعتراض الأهداف الضمنية المعدّة للاستخدام من خلال مكوّنات التطبيق الداخلية.
على سبيل المثال، إليك فلتر الغرض الذي يمكن تضمينه في ملف بيان تطبيقك:
<activity
android:name=".AppActivity"
android:exported="false">
<intent-filter>
<action android:name="com.example.action.APP_ACTION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
إذا حاول تطبيقك بدء هذا النشاط باستخدام هدف ضمني، سيتم طرح استثناء:
Kotlin
// Throws an exception when targeting Android 14. context.startActivity(Intent("com.example.action.APP_ACTION"))
Java
// Throws an exception when targeting Android 14. context.startActivity(new Intent("com.example.action.APP_ACTION"));
لتشغيل النشاط غير المُصدَّر، يجب أن يستخدم تطبيقك غرضًا صريحًا بدلاً من ذلك:
Kotlin
// This makes the intent explicit. val explicitIntent = Intent("com.example.action.APP_ACTION") explicitIntent.apply { package = context.packageName } context.startActivity(explicitIntent)
Java
// This makes the intent explicit. Intent explicitIntent = new Intent("com.example.action.APP_ACTION") explicitIntent.setPackage(context.getPackageName()); context.startActivity(explicitIntent);
على أجهزة استقبال البث المسجّلة في وقت التشغيل تحديد سلوك التصدير.
بالنسبة إلى التطبيقات والخدمات التي تستهدف الإصدار 14 من نظام التشغيل Android وتستخدم أجهزة
استقبال
مسجّلة للسياق، يجب
تحديد علامة للإشارة إلى ما إذا كان يجب تصدير
جهاز الاستقبال
إلى جميع التطبيقات الأخرى على الجهاز: إما RECEIVER_EXPORTED
أو
RECEIVER_NOT_EXPORTED
، على التوالي. يساعد هذا الشرط في حماية التطبيقات من الثغرات الأمنية من خلال الاستفادة من الميزات الخاصة بأجهزة الاستقبال هذه التي تم طرحها في Android 13.
استثناء للمستلمين الذين يستلمون عمليات بث النظام فقط
إذا كان تطبيقك يسجِّل جهاز استقبال فقط لعمليات البث من خلال النظام من خلال طرق Context#registerReceiver
، مثل Context#registerReceiver()
، يجب ألا يتم تحديد علامة عند تسجيل جهاز الاستقبال.
تحميل رموز ديناميكية أكثر أمانًا
إذا كان تطبيقك يستهدف الإصدار 14 من نظام التشغيل Android ويستخدم ميزة "تحميل الرموز الديناميكية" (DCL)، يجب وضع علامة للقراءة فقط على جميع الملفات المحمَّلة ديناميكيًا. وإلا، سيطرح النظام استثناءً. ننصح التطبيقات بتجنُّب التحميل الديناميكي للرمز كلما أمكن ذلك، لأنّ ذلك يزيد بشكل كبير من خطر اختراق التطبيق من خلال إدخال الرموز أو العبث بها.
إذا كان عليك تحميل الرمز ديناميكيًا، استخدِم الطريقة التالية لضبط الملف المحمَّل ديناميكيًا (مثل ملف DEX أو JAR أو APK) كملف للقراءة فقط بعد فتح الملف وقبل كتابة أي محتوى:
Kotlin
val jar = File("DYNAMICALLY_LOADED_FILE.jar") val os = FileOutputStream(jar) os.use { // Set the file to read-only first to prevent race conditions jar.setReadOnly() // Then write the actual file content } val cl = PathClassLoader(jar, parentClassLoader)
Java
File jar = new File("DYNAMICALLY_LOADED_FILE.jar"); try (FileOutputStream os = new FileOutputStream(jar)) { // Set the file to read-only first to prevent race conditions jar.setReadOnly(); // Then write the actual file content } catch (IOException e) { ... } PathClassLoader cl = new PathClassLoader(jar, parentClassLoader);
التعامل مع الملفات المتوفرة من قبل والتي تم تحميلها ديناميكيًا
لمنع طرح استثناءات للملفات الحالية التي تم تحميلها ديناميكيًا، ننصحك بحذف الملفات وإعادة إنشائها قبل محاولة تحميلها ديناميكيًا مرة أخرى في تطبيقك. وأثناء إعادة إنشاء الملفات، اتّبِع الإرشادات السابقة لوضع علامة على الملفات للقراءة فقط في وقت الكتابة. بدلاً من ذلك، يمكنك إعادة تسمية الملفات الحالية باعتبارها للقراءة فقط، ولكن في هذه الحالة، ننصح بشدة بالتحقق من سلامة الملفات أولاً (على سبيل المثال، من خلال التحقق من توقيع الملف مقابل قيمة موثوق بها)، للمساعدة في حماية تطبيقك من الإجراءات الضارة.
قيود إضافية على بدء الأنشطة من الخلفية
بالنسبة إلى التطبيقات التي تستهدف Android 14، يقيّد النظام أيضًا الحالات التي يتم فيها السماح للتطبيقات ببدء الأنشطة من الخلفية:
- عندما يرسل أحد التطبيقات
PendingIntent
باستخدامPendingIntent#send()
أو طرق مشابهة، يجب أن يفعّل التطبيق الآن إذا كان يريد منح امتيازات خاصة بإطلاق النشاط في الخلفية، وذلك لبدء الغرض المعلق. لتفعيل الميزة، يجب أن يجتاز التطبيق حزمةActivityOptions
تتضمّنsetPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
. - عندما يربط تطبيق مرئي خدمة بتطبيق آخر في الخلفية
باستخدام طريقة
bindService()
، يجب أن يفعّل التطبيق المرئي الآن إذا أراد منح امتيازات إطلاق النشاط في الخلفية إلى الخدمة المرتبطة. لتفعيل الميزة، يجب أن يتضمّن التطبيق العلامةBIND_ALLOW_ACTIVITY_STARTS
عند طلب البيانات باستخدام طريقةbindService()
.
تؤدّي هذه التغييرات إلى توسيع مجموعة القيود الحالية لحماية المستخدمين من خلال منع التطبيقات الضارة من إساءة استخدام واجهات برمجة التطبيقات لبدء أنشطة مزعجة من الخلفية.
مسح مسار ملفات Zip
بالنسبة إلى التطبيقات التي تستهدف الإصدار 14 من نظام التشغيل Android، يمنع Android الثغرة الأمنية "مسح مسار ملفات Zip" بالطريقة التالية: ZipFile(String)
وZipInputStream.getNextEntry()
يعرضان الخطأ ZipException
إذا كانت أسماء إدخالات ملفات ZIP تحتوي على ".." أو تبدأ بـ "/".
يمكن للتطبيقات إيقاف عملية التحقّق هذه من خلال الاتصال بالرقم dalvik.system.ZipPathValidator.clearCallback()
.
موافقة المستخدم مطلوبة لكل جلسة التقاط MediaProjection
بالنسبة إلى التطبيقات التي تستهدف Android 14 (المستوى 34 لواجهة برمجة التطبيقات)، يتم عرض SecurityException
في حال استخدام MediaProjection#createVirtualDisplay
في أي من السيناريوهين التاليين:
- يخزّن تطبيقك مؤقتًا
Intent
التي يعرضهاMediaProjectionManager#createScreenCaptureIntent
، ويمررها عدة مرات إلىMediaProjectionManager#getMediaProjection
. - يستدعي تطبيقك
MediaProjection#createVirtualDisplay
عدة مرات على نفس مثيلMediaProjection
.
يجب أن يطلب تطبيقك من المستخدم منح الموافقة قبل كل جلسة تسجيل. وجلسة الالتقاط الفردية هي استدعاء واحد في MediaProjection#createVirtualDisplay
، ويجب استخدام كل مثيل MediaProjection
مرة واحدة فقط.
التعامل مع التغييرات في الإعدادات
إذا كان تطبيقك يحتاج إلى استدعاء MediaProjection#createVirtualDisplay
للتعامل مع
تغييرات الضبط (مثل تغيير اتجاه الشاشة أو تغيير حجم الشاشة)،
يمكنك اتّباع الخطوات التالية لتعديل VirtualDisplay
لمثيل
MediaProjection
الحالي:
- استدعِ
VirtualDisplay#resize
بالعرض والارتفاع الجديدين. - أضِف عنصر
Surface
جديدَين يتضمّن قيمة العرض والارتفاع الجديدةVirtualDisplay#setSurface
.
تسجيل مكالمة معاودة الاتصال
يجب أن يسجّل تطبيقك معاودة الاتصال للتعامل مع الحالات التي لا يمنح فيها المستخدم موافقته على متابعة جلسة التسجيل. لتنفيذ ذلك، نفِّذ السمة
Callback#onStop
واطلب من تطبيقك إصدار أي موارد ذات صلة (مثل
VirtualDisplay
وSurface
).
إذا لم يسجِّل تطبيقك معاودة الاتصال هذه،
سيطرح MediaProjection#createVirtualDisplay
علامة IllegalStateException
عندما يستدعي التطبيق.
القيود المعدّلة غير المرتبطة بحزمة تطوير البرامج (SDK)
يتضمّن نظام التشغيل Android 14 قوائم معدَّلة للواجهات المحظورة غير المستنِدة إلى حزمة تطوير برامج (SDK) استنادًا إلى التعاون مع مطوّري تطبيقات Android وأحدث الاختبارات الداخلية. كلّما أمكن، نحرص على توفّر البدائل المتاحة للجميع قبل حظر الواجهات غير المستندة إلى حزمة SDK.
إذا لم يكن تطبيقك يستهدف الإصدار 14 من نظام التشغيل Android، قد لا تؤثر بعض هذه التغييرات في تطبيقك على الفور. ومع ذلك، يمكنك حاليًا استخدام بعض الواجهات غير المستندة إلى SDK (بناءً على مستوى واجهة برمجة التطبيقات المستهدف في تطبيقك)، إلا أنّ استخدام أي حقل أو طريقة غير SDK يؤدي دائمًا إلى كسر تطبيقك.
إذا لم تكن متأكدًا مما إذا كان تطبيقك يستخدم واجهات غير متوفرة في SDK، يمكنك اختبار تطبيقك لمعرفة ذلك. إذا كان تطبيقك يعتمد على واجهات غير متوفرة في حزمة SDK، عليك البدء في التخطيط للنقل إلى بدائل SDK. ومع ذلك، ندرك أن بعض التطبيقات لديها حالات استخدام صالحة لاستخدام الواجهات غير المستندة إلى SDK. إذا لم تتمكن من العثور على بديل لاستخدام واجهة غير متوفرة في حزمة SDK لميزة في تطبيقك، يجب طلب واجهة برمجة تطبيقات عامة جديدة.
لمعرفة المزيد من المعلومات عن التغييرات في هذا الإصدار من نظام التشغيل Android، يمكنك الاطّلاع على تعديلات على القيود المفروضة على الواجهة غير المستندة إلى حزمة تطوير البرامج (SDK) في نظام التشغيل Android 14. للحصول على مزيد من المعلومات عن الواجهات غير المتوفرة في حزمة SDK بوجهٍ عام، يُرجى الاطّلاع على مقالة القيود المفروضة على الواجهات التي لا تتضمن حزمة SDK.