كما هو الحال مع الإصدارات السابقة، يتضمّن Android 14 تغييرات في السلوك قد تؤثّر في تطبيقك. تنطبق تغييرات السلوك التالية حصريًا على التطبيقات التي تستهدف الإصدار 14 من نظام التشغيل Android (المستوى 34 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث. إذا كان تطبيقك يستهدف الإصدار 14 من نظام التشغيل Android أو الإصدارات الأحدث، عليك تعديل تطبيقك ليتوافق مع هذه السلوكيات بشكل صحيح، حيثما ينطبق ذلك.
احرص أيضًا على مراجعة قائمة التغييرات في السلوك التي تؤثّر في جميع التطبيقات
التي تعمل على الإصدار 14 من نظام التشغيل Android بغض النظر عن
targetSdkVersion
للتطبيق.
الوظيفة الأساسية
أنواع الخدمات التي تعمل في المقدّمة مطلوبة
إذا كان تطبيقك يستهدف الإصدار 14 من نظام التشغيل Android (المستوى 34 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، يجب تحديد نوع واحد على الأقل من الخدمات التي تعمل في المقدّمة لكل خدمة تعمل في المقدّمة ضمن تطبيقك. ويجب اختيار نوع خدمة تعمل في المقدّمة يمثّل حالة استخدام تطبيقك. يتوقّع النظام أن تستوفي الخدمات التي تعمل في المقدّمة والتي لها نوع معيّن حالة استخدام معيّنة.
إذا لم تكن حالة استخدام في تطبيقك مرتبطة بأيّ من هذه الأنواع، ننصح بشدة بنقل منطقك لاستخدام WorkManager أو مهام نقل البيانات التي يبدأها المستخدم.
فرض إذن BLUETOOTH_CONNECT في BluetoothAdapter
يفرض الإصدار 14 من نظام التشغيل Android إذن 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 continues the work of refreshing Android's core libraries to align with the features in the latest OpenJDK LTS releases, including both library updates and Java 17 language support for app and platform developers.
A few of these changes can affect app compatibility:
- Changes to regular expressions: Invalid group references are now
disallowed to more closely follow the semantics of OpenJDK. You might see
new cases where an
IllegalArgumentException
is thrown by thejava.util.regex.Matcher
class, so make sure to test your app for areas that use regular expressions. To enable or disable this change while testing, toggle theDISALLOW_INVALID_GROUP_REFERENCE
flag using the compatibility framework tools. - UUID handling: The
java.util.UUID.fromString()
method now does more strict checks when validating the input argument, so you might see anIllegalArgumentException
during deserialization. To enable or disable this change while testing, toggle theENABLE_STRICT_VALIDATION
flag using the compatibility framework tools. - ProGuard issues: In some cases, the addition of the
java.lang.ClassValue
class causes an issue if you try to shrink, obfuscate, and optimize your app using ProGuard. The problem originates with a Kotlin library that changes runtime behaviour based on whetherClass.forName("java.lang.ClassValue")
returns a class or not. If your app was developed against an older version of the runtime without thejava.lang.ClassValue
class available, then these optimizations might remove thecomputeValue
method from classes derived fromjava.lang.ClassValue
.
تعزّز JobScheduler سلوك رد الاتصال والشبكة
تتوقع أداة Jobscheduler منذ إطلاقها أن يعود تطبيقك
onStartJob
أو onStopJob
خلال بضع ثوانٍ. قبل Android 14،
إذا كانت المهمة تستغرق وقتًا طويلاً، يتم إيقاف المهمة وتفشل تلقائيًا.
إذا كان تطبيقك يستهدف الإصدار 14 من نظام التشغيل Android (المستوى 34 لواجهة برمجة التطبيقات) أو إصدارًا أحدث وتجاوز المدّة الممنوحة في سلسلة المهام الرئيسية، سيُنشئ التطبيق خطأ ANR
مع رسالة الخطأ "ما مِن استجابة لـ onStartJob
" أو
"ما مِن استجابة لـ onStopJob
".
قد يكون خطأ ANR هذا نتيجة لأحد السيناريوهَين التاليَين:
1. هناك عمل يحظر سلسلة المحادثات الرئيسية، ما يمنع عمليات معاودة الاتصال onStartJob
.
أو onStopJob
من التنفيذ والإكمال خلال المهلة الزمنية المتوقّعة.
2. ينفِّذ المطوّر عمل حظر ضمن Job Scheduler
استدعاء onStartJob
أو onStopJob
، ما يمنع معاودة الاتصال من
لإنجازها خلال الحد الزمني المتوقع.
لمعالجة رقم 1، عليك إجراء المزيد من تصحيح الأخطاء التي تمنع سلسلة التعليمات الرئيسية.
عند حدوث خطأ ANR، يمكنك القيام بذلك باستخدام
ApplicationExitInfo#getTraceInputStream()
للحصول على شاهد القبر
وتتبع حدوث خطأ ANR. إذا كان بإمكانك إعادة إنتاج خطأ ANR يدويًا،
يمكنك تسجيل تتبُّع للنظام وفحص التتبُّع باستخدام Android Studio أو Perfetto لفهم ما الذي يتم تشغيله في الخيط الرئيسي عند حدوث خطأ ANR بشكل أفضل.
يُرجى العِلم أنّ هذا يمكن أن يحدث عند استخدام واجهة برمجة التطبيقات Jobscheduler API مباشرةً.
أو استخدام WorkManager لمكتبة androidx.
لمعالجة رقم 2، ننصحك بإجراء عملية النقل إلى WorkManager، التي توفّر
توفير إمكانية إكمال أي معالجة في onStartJob
أو onStopJob
في سلسلة محادثات غير متزامنة.
تفرض JobScheduler
أيضًا شرطًا للإفصاح عن الإذن
ACCESS_NETWORK_STATE
في حال استخدام قيد setRequiredNetworkType
أو
setRequiredNetwork
. إذا لم يفصح تطبيقك عن
الحصول على إذن "ACCESS_NETWORK_STATE
" عند تحديد موعد المهمة وتحديد الاستهداف
الإصدار 14 من نظام التشغيل Android أو الإصدارات الأحدث، سيؤدي إلى حدوث SecurityException
.
Tiles launch API
بالنسبة إلى التطبيقات التي تستهدف 14 عامًا أو أعلى،
تم إيقاف TileService#startActivityAndCollapse(Intent)
نهائيًا وسيتم طرحه الآن.
استثناءً عند استدعائه. إذا كان تطبيقك يطلق الأنشطة من الشاشات، استخدِم
TileService#startActivityAndCollapse(PendingIntent)
بدلاً من ذلك.
الخصوصية
الوصول الجزئي إلى الصور والفيديوهات
Android 14 引入了“已选照片访问权限”,让用户可以向应用授予对其媒体库中特定图片和视频的访问权限,而不是授予对给定类型的所有媒体的访问权限。
只有当您的应用以 Android 14(API 级别 34)或更高版本为目标平台时,此更改才会启用。如果您尚未使用照片选择器,我们建议您在应用中实现照片选择器,以提供一致的图片和视频选择体验,同时增强用户隐私保护,而无需请求任何存储权限。
如果您使用存储权限维护自己的图库选择器,并且需要对实现保持完全控制,请调整实现以使用新的 READ_MEDIA_VISUAL_USER_SELECTED
权限。如果您的应用不使用新权限,系统会以兼容模式运行您的应用。
تجربة المستخدم
إشعارات آمنة بملء الشاشة
في الإصدار 11 من Android (المستوى 30 لواجهة برمجة التطبيقات)، كان بإمكان أي تطبيق استخدام Notification.Builder.setFullScreenIntent
لإرسال رسائل بهدف عرض المحتوى بملء الشاشة عندما يكون الهاتف مقفلاً. يمكنك منح هذا الإذن تلقائيًا عند تثبيت التطبيق من خلال
تحديد إذن USE_FULL_SCREEN_INTENT
فيملف
AndroidManifest.
تم تصميم إشعارات العرض بملء الشاشة لإرسال إشعارات مهمة للغاية
تتطلّب اهتمام المستخدم الفوري، مثل مكالمة هاتفية واردة أو إعدادات المنبّه التي ضبطها المستخدم. بالنسبة إلى التطبيقات التي تستهدف الإصدار
Android 14 (المستوى 34 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، تقتصر التطبيقات المسموح لها باستخدام
هذا الإذن على تلك التي توفّر وظائف الاتصال والمنبّهات فقط. يُلغي "متجر Google
Play" أذونات USE_FULL_SCREEN_INTENT
التلقائية لأي تطبيقات
لا تتوافق مع هذا الملف الشخصي. الموعد النهائي لتنفيذ هذه التغييرات في السياسة هو 31 أيار (مايو)
2024.
يظل هذا الإذن مفعّلاً للتطبيقات المثبَّتة على الهاتف قبل أن يصعّد المستخدم إلى الإصدار 14 من Android. يمكن للمستخدمين تفعيل هذا الإذن أو إيقافه.
يمكنك استخدام واجهة برمجة التطبيقات الجديدة
NotificationManager.canUseFullScreenIntent
للتحقّق مما إذا كان تطبيقك
يملك الإذن. وإذا لم يكن الأمر كذلك، يمكن لتطبيقك استخدام الطلب الجديد
ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT
لفتح صفحة الإعدادات
التي يمكن للمستخدمين فيها منح الإذن.
الأمان
القيود المفروضة على النوايا الضمنية والمعلّقة
بالنسبة إلى التطبيقات التي تستهدف الإصدار Android 14 (المستوى 34 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، يحظِر 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>
إذا حاول تطبيقك تشغيل هذا النشاط باستخدام نية ضمنية، سيتم طرح استثناء
ActivityNotFoundException
:
Kotlin
// Throws an ActivityNotFoundException exception when targeting Android 14. context.startActivity(Intent("com.example.action.APP_ACTION"))
Java
// Throws an ActivityNotFoundException 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);
يجب أن تحدّد مستقبِلات البث المسجّلة في وقت التشغيل سلوك التصدير
Apps and services that target Android 14 (API level 34) or higher and use
context-registered receivers are required to specify a flag
to indicate whether or not the receiver should be exported to all other apps on
the device: either RECEIVER_EXPORTED
or RECEIVER_NOT_EXPORTED
, respectively.
This requirement helps protect apps from security vulnerabilities by leveraging
the features for these receivers introduced in Android 13.
Exception for receivers that receive only system broadcasts
If your app is registering a receiver only for
system broadcasts through Context#registerReceiver
methods, such as Context#registerReceiver()
, then it
shouldn't specify a flag when registering the receiver.
تحميل الرموز الديناميكية بشكل أكثر أمانًا
إذا كان تطبيقك يستهدف الإصدار 14 من نظام التشغيل Android (المستوى 34 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث وكان يستخدم ميزة "تحميل الرمز الديناميكي" (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);
التعامل مع الملفات الحالية التي يتم تحميلها ديناميكيًا
لمنع ظهور استثناءات في الملفات الحالية التي يتم تحميلها ديناميكيًا، ننصح بحذف الملفات وإعادة إنشائها قبل محاولة تحميلها مجددًا في تطبيقك ديناميكيًا. وعند إعادة إنشاء الملفات، اتّبِع التوجيهات السابقة لوضع علامة "للقراءة فقط" على الملفات في وقت الكتابة. بدلاً من ذلك، يمكنك إعادة تصنيف الملفات الحالية على أنها للقراءة فقط، ولكن في هذه الحالة، أنصحك بالتحقّق من سلامة الملفات أولاً (على سبيل المثال، من خلال التحقّق من توقيع الملف مقابل قيمة موثوق بها)، للمساعدة في حماية تطبيقك من الإجراءات الضارة.
قيود إضافية على بدء الأنشطة من الخلفية
بالنسبة إلى التطبيقات التي تستهدف الإصدار 14 من نظام التشغيل Android (المستوى 34 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، يفرض النظام المزيد من القيود على الحالات التي يُسمح للتطبيقات فيها ببدء الأنشطة من الخلفية:
- عندما يُرسِل تطبيق طلبًا باستخدام
PendingIntent
PendingIntent#send()
أو طُرق مشابهة، يجب أن يوافق التطبيق على منح امتيازات بدء النشاط في الخلفية لبدء الطلب المعلّق. للموافقة على الميزة، يجب أن يُرسل التطبيقActivityOptions
حزمة تحتوي علىsetPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
. - عندما يربط تطبيق مرئي خدمة تطبيق آخر يعمل في الخلفية
باستخدام طريقة
bindService()
، يجب أن يوافق التطبيق المرئي الآن على ذلك إذا كان يريد منح امتيازات تشغيل النشاط في الخلفية الخاصة به للخدمة المرتبطة. للموافقة على الميزة، يجب أن يتضمّن التطبيق العلامةBIND_ALLOW_ACTIVITY_STARTS
عند استدعاء الأسلوبbindService()
.
تعمل هذه التغييرات على توسيع مجموعة القيود الحالية لحماية المستخدِمين من خلال منع التطبيقات الضارة من إساءة استخدام واجهات برمجة التطبيقات لبدء أنشطة مزعجة من الخلفية.
مسح مسار ملفات Zip
بالنسبة إلى التطبيقات التي تستهدف الإصدار 14 من نظام التشغيل Android (المستوى 34 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، يمنع Android ثغرة ملف ZIP
Path Traversal بالطريقة التالية: يعرض كل من
ZipFile(String)
و
ZipInputStream.getNextEntry()
خطأ
ZipException
إذا كانت أسماء إدخالات ملفات ZIP تحتوي على ".." أو تبدأ
بـ "/".
يمكن للتطبيقات إيقاف عملية التحقّق هذه من خلال الاتصال بالرقم
dalvik.system.ZipPathValidator.clearCallback()
.
يجب الحصول على موافقة المستخدم لكل جلسة التقاط MediaProjection
بالنسبة إلى التطبيقات التي تستهدف الإصدار 14 من نظام التشغيل Android (المستوى 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 版本中的变更,请参阅 Android 14 中有关限制非 SDK 接口的更新。如需全面了解有关非 SDK 接口的详细信息,请参阅对非 SDK 接口的限制。