كما هو الحال مع الإصدارات السابقة، يتضمّن Android 14 تغييرات في السلوك قد تؤثّر في تطبيقك. تنطبق تغييرات السلوك التالية حصريًا على التطبيقات التي تستهدف الإصدار 14 من نظام التشغيل Android (المستوى 34 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث. إذا كان تطبيقك يستهدف الإصدار 14 من نظام التشغيل Android أو الإصدارات الأحدث، عليك تعديل تطبيقك ليتوافق مع هذه السلوكيات بشكل صحيح، حيثما ينطبق ذلك.
احرص أيضًا على مراجعة قائمة التغييرات في السلوك التي تؤثّر في جميع التطبيقات
التي تعمل على Android 14 بغض النظر عن
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
IllegalArgumentExceptionis thrown by thejava.util.regex.Matcherclass, 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_REFERENCEflag 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 anIllegalArgumentExceptionduring deserialization. To enable or disable this change while testing, toggle theENABLE_STRICT_VALIDATIONflag using the compatibility framework tools. - ProGuard issues: In some cases, the addition of the
java.lang.ClassValueclass 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.ClassValueclass available, then these optimizations might remove thecomputeValuemethod 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
For apps targeting 14 and higher,
TileService#startActivityAndCollapse(Intent) is deprecated and now throws
an exception when called. If your app launches activities from tiles, use
TileService#startActivityAndCollapse(PendingIntent) instead.
الخصوصية
الوصول الجزئي إلى الصور والفيديوهات
Android 14 introduces Selected Photos Access, which allows users to grant apps access to specific images and videos in their library, rather than granting access to all media of a given type.
This change is only enabled if your app targets Android 14 (API level 34) or higher. If you don't use the photo picker yet, we recommend implementing it in your app to provide a consistent experience for selecting images and videos that also enhances user privacy without having to request any storage permissions.
If you maintain your own gallery picker using storage permissions and need to
maintain full control over your implementation, adapt your implementation
to use the new READ_MEDIA_VISUAL_USER_SELECTED permission. If your app
doesn't use the new permission, the system runs your app in a compatibility
mode.
تجربة المستخدم
إشعارات آمنة بوضع العرض بملء الشاشة
في الإصدار 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.
تحميل الرموز الديناميكية بشكل أكثر أمانًا
If your app targets Android 14 (API level 34) or higher and uses Dynamic Code Loading (DCL), all dynamically-loaded files must be marked as read-only. Otherwise, the system throws an exception. We recommend that apps avoid dynamically loading code whenever possible, as doing so greatly increases the risk that an app can be compromised by code injection or code tampering.
If you must dynamically load code, use the following approach to set the dynamically-loaded file (such as a DEX, JAR, or APK file) as read-only as soon as the file is opened and before any content is written:
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);
Handle dynamically-loaded files that already exist
To prevent exceptions from being thrown for existing dynamically-loaded files, we recommend deleting and recreating the files before you try to dynamically load them again in your app. As you recreate the files, follow the preceding guidance for marking the files read-only at write time. Alternatively, you can re-label the existing files as read-only, but in this case, we strongly recommend that you verify the integrity of the files first (for example, by checking the file's signature against a trusted value), to help protect your app from malicious actions.
قيود إضافية على بدء الأنشطة من الخلفية
بالنسبة إلى التطبيقات التي تستهدف الإصدار 14 من نظام التشغيل Android (المستوى 34 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، يفرض النظام المزيد من القيود على الحالات التي يُسمح للتطبيقات فيها ببدء الأنشطة من الخلفية:
- عندما يُرسِل تطبيق طلبًا باستخدام
PendingIntentPendingIntent#send()أو طُرق مشابهة، يجب أن يوافق التطبيق على منح امتيازات بدء النشاط في الخلفية لبدء الطلب المعلّق. للموافقة على الميزة، يجب أن يُرسل التطبيقActivityOptionsحزمة تحتوي علىsetPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED). - عندما يربط تطبيق مرئي خدمة تطبيق آخر يعمل في الخلفية
باستخدام طريقة
bindService()، يجب أن يوافق التطبيق المرئي الآن على ذلك إذا كان يريد منح امتيازات تشغيل النشاط في الخلفية الخاصة به للخدمة المرتبطة. للموافقة على الميزة، يجب أن يتضمّن التطبيق العلامةBIND_ALLOW_ACTIVITY_STARTSعند استدعاء الأسلوبbindService().
تعمل هذه التغييرات على توسيع مجموعة القيود الحالية لحماية المستخدِمين من خلال منع التطبيقات الضارة من إساءة استخدام واجهات برمجة التطبيقات لبدء أنشطة مزعجة من الخلفية.
مسح مسار ملفات Zip
For apps targeting Android 14 (API level 34) or higher, Android prevents the Zip
Path Traversal Vulnerability in the following way:
ZipFile(String) and
ZipInputStream.getNextEntry() throws a
ZipException if zip file entry names contain ".." or start
with "/".
Apps can opt-out from this validation by calling
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 لإحدى الميزات في تطبيقك، عليك طلب واجهة برمجة تطبيقات عامة جديدة.
To learn more about the changes in this release of Android, see Updates to non-SDK interface restrictions in Android 14. To learn more about non-SDK interfaces generally, see Restrictions on non-SDK interfaces.