كما هو الحال مع الإصدارات السابقة، يتضمّن Android 14 تغييرات في السلوك قد تؤثّر في تطبيقك. تنطبق تغييرات السلوك التالية حصريًا على التطبيقات التي تستهدف الإصدار 14 من نظام التشغيل Android (المستوى 34 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث. إذا كان تطبيقك يستهدف الإصدار 14 من نظام التشغيل Android أو الإصدارات الأحدث، عليك تعديل تطبيقك ليتوافق مع هذه السلوكيات بشكل صحيح، حيثما ينطبق ذلك.
احرص أيضًا على مراجعة قائمة التغييرات في السلوك التي تؤثّر في جميع التطبيقات
التي تعمل على الإصدار 14 من نظام التشغيل Android بغض النظر عن
targetSdkVersion
للتطبيق.
الوظيفة الأساسية
أنواع الخدمات التي تعمل في المقدّمة مطلوبة
If your app targets Android 14 (API level 34) or higher, it must specify at least one foreground service type for each foreground service within your app. You should choose a foreground service type that represents your app's use case. The system expects foreground services that have a particular type to satisfy a particular use case.
If a use case in your app isn't associated with any of these types, it's strongly recommended that you migrate your logic to use WorkManager or user-initiated data transfer jobs.
فرض إذن 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 العمل على تحديث المكتبات الأساسية في 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 (المستوى 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 ميزة "الوصول إلى الصور المحدّدة" التي تتيح للمستخدمين منح التطبيقات إذنًا بالوصول إلى صور وفيديوهات معيّنة في مكتبتهم، بدلاً من منح إذن بالوصول إلى كل الوسائط من نوع معيّن.
لا يتم تفعيل هذا التغيير إلا إذا كان تطبيقك يستهدف الإصدار 14 من نظام التشغيل Android (المستوى 34 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث. إذا لم تكن تستخدِم أداة اختيار الصور بعد، ننصحك بإضافتها إلى تطبيقك لتوفير تجربة متّسقة لاختيار الصور والفيديوهات، وذلك أيضًا لتعزيز خصوصية المستخدم بدون الحاجة إلى طلب أي أذونات تخزين.
إذا كنت تحافظ على أداة اختيار معرض الصور باستخدام أذونات التخزين وتحتاج إلى
الحفاظ على التحكّم الكامل في عملية التنفيذ، عليك تعديل عملية التنفيذ
لاستخدام الإذن الجديد READ_MEDIA_VISUAL_USER_SELECTED
. إذا كان تطبيقك
لا يستخدم الإذن الجديد، سيشغّل النظام تطبيقك في وضع ملف التوافق.
تجربة المستخدم
إشعارات آمنة بملء الشاشة
With Android 11 (API level 30), it was possible for any app to use
Notification.Builder.setFullScreenIntent
to send full-screen
intents while the phone is locked. You could auto-grant this on app install by
declaring USE_FULL_SCREEN_INTENT
permission in the
AndroidManifest.
Full-screen intent notifications are designed for extremely high-priority
notifications demanding the user's immediate attention, such as an incoming
phone call or alarm clock settings configured by the user. For apps targeting
Android 14 (API level 34) or higher, apps that are allowed to use this
permission are limited to those that provide calling and alarms only. The Google
Play Store revokes default USE_FULL_SCREEN_INTENT
permissions for any apps
that don't fit this profile. The deadline for these policy changes is May 31,
2024.
This permission remains enabled for apps installed on the phone before the user updates to Android 14. Users can turn this permission on and off.
You can use the new API
NotificationManager.canUseFullScreenIntent
to check if your app
has the permission; if not, your app can use the new intent
ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT
to launch the settings
page where users can grant the permission.
الأمان
القيود المفروضة على الأهداف الضمنية والمعلّقة
For apps targeting Android 14 (API level 34) or higher, Android restricts apps from sending implicit intents to internal app components in the following ways:
- Implicit intents are only delivered to exported components. Apps must either use an explicit intent to deliver to unexported components, or mark the component as exported.
- If an app creates a mutable pending intent with an intent that doesn't specify a component or package, the system throws an exception.
These changes prevent malicious apps from intercepting implicit intents that are intended for use by an app's internal components.
For example, here is an intent filter that could be declared in your app's manifest file:
<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>
If your app tried to launch this activity using an implicit intent, an
ActivityNotFoundException
exception would be thrown:
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"));
To launch the non-exported activity, your app should use an explicit intent instead:
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);
التعامل مع الملفات الحالية التي يتم تحميلها ديناميكيًا
لمنع ظهور استثناءات في الملفات الحالية التي يتم تحميلها ديناميكيًا، ننصح بحذف الملفات وإعادة إنشائها قبل محاولة تحميلها مجددًا في تطبيقك ديناميكيًا. وعند إعادة إنشاء الملفات، اتّبِع التوجيهات السابقة لوضع علامة "للقراءة فقط" على الملفات في وقت الكتابة. بدلاً من ذلك، يمكنك إعادة تصنيف الملفات الحالية على أنها للقراءة فقط، ولكن في هذه الحالة، أنصحك بالتحقّق من سلامة الملفات أولاً (على سبيل المثال، من خلال التحقّق من توقيع الملف مقابل قيمة موثوق بها)، للمساعدة في حماية تطبيقك من الإجراءات الضارة.
قيود إضافية على بدء الأنشطة من الخلفية
For apps targeting Android 14 (API level 34) or higher, the system further restricts when apps are allowed to start activities from the background:
- When an app sends a
PendingIntent
usingPendingIntent#send()
or similar methods, the app must opt in if it wants to grant its own background activity launch privileges to start the pending intent. To opt in, the app should pass anActivityOptions
bundle withsetPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
. - When a visible app binds a service of another app that's in the background
using the
bindService()
method, the visible app must now opt in if it wants to grant its own background activity launch privileges to the bound service. To opt in, the app should include theBIND_ALLOW_ACTIVITY_STARTS
flag when calling thebindService()
method.
These changes expand the existing set of restrictions to protect users by preventing malicious apps from abusing APIs to start disruptive activities from the background.
مسح مسار ملفات Zip
بالنسبة إلى التطبيقات التي تستهدف الإصدار 14 من نظام التشغيل Android (المستوى 34 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، يمنع Android ثغرة ملف ZIP
Path Traversal بالطريقة التالية: يعرض كل من
ZipFile(String)
و
ZipInputStream.getNextEntry()
خطأ
ZipException
إذا كانت أسماء إدخالات ملفات ZIP تحتوي على ".." أو تبدأ
بـ "/".
يمكن للتطبيقات إيقاف عملية التحقّق هذه من خلال الاتصال بالرقم
dalvik.system.ZipPathValidator.clearCallback()
.
يجب الحصول على موافقة المستخدم لكل جلسة التقاط MediaProjection
For apps targeting Android 14 (API level 34) or higher, a SecurityException
is
thrown by MediaProjection#createVirtualDisplay
in either of the following
scenarios:
- Your app caches the
Intent
that is returned fromMediaProjectionManager#createScreenCaptureIntent
, and passes it multiple times toMediaProjectionManager#getMediaProjection
. - Your app invokes
MediaProjection#createVirtualDisplay
multiple times on the sameMediaProjection
instance.
Your app must ask the user to give consent before each capture session. A single
capture session is a single invocation on
MediaProjection#createVirtualDisplay
, and each MediaProjection
instance must
be used only once.
Handle configuration changes
If your app needs to invoke MediaProjection#createVirtualDisplay
to handle
configuration changes (such as the screen orientation or screen size changing),
you can follow these steps to update the VirtualDisplay
for the existing
MediaProjection
instance:
- Invoke
VirtualDisplay#resize
with the new width and height. - Provide a new
Surface
with the new width and height toVirtualDisplay#setSurface
.
Register a callback
Your app should register a callback to handle cases where the user doesn't grant
consent to continue a capture session. To do this, implement
Callback#onStop
and have your app release any related resources (such as
the VirtualDisplay
and Surface
).
If your app doesn't register this callback,
MediaProjection#createVirtualDisplay
throws an IllegalStateException
when your app invokes it.
تعديل القيود المفروضة على استخدام واجهات برمجة التطبيقات غير التابعة لحزمة SDK
يتضمّن نظام التشغيل Android 14 قوائم معدَّلة لواجهات غير حزمة تطوير البرامج (SDK) المحظورة استنادًا إلى التعاون مع مطوّري تطبيقات Android وأحدث الاختبارات الداخلية. نحرص دائمًا على توفير بدائل عامة قبل فرض قيود على الواجهات غير المتوفّرة في حزمة SDK.
إذا كان تطبيقك لا يستهدف الإصدار 14 من نظام التشغيل Android، قد لا تؤثّر بعض هذه التغييرات فيك على الفور. ومع ذلك، على الرغم من أنّه يمكنك حاليًا استخدام بعض الواجهات غير التابعة لحزمة SDK (حسب مستوى واجهة برمجة التطبيقات المستهدَف في تطبيقك)، فإنّ استخدام أي طريقة أو حقل غير تابع لحزمة SDK ينطوي دائمًا على خطر كبير بتعطُّل تطبيقك.
إذا لم تكن متأكدًا مما إذا كان تطبيقك يستخدم واجهات غير متوفرة في حزمة SDK، يمكنك اختبار تطبيقك لمعرفة ذلك. إذا كان تطبيقك يعتمد على واجهات غير متوفرة في حزمة SDK، عليك البدء في التخطيط لنقل البيانات إلى بدائل حزمة SDK. ومع ذلك، ندرك أنّ بعض التطبيقات لديها حالات استخدام صالحة لواجهات غير متوفرة في حزمة SDK. إذا لم تتمكّن من العثور على بديل لاستخدام واجهة غير متوفّرة في حزمة SDK لإحدى الميزات في تطبيقك، عليك طلب واجهة برمجة تطبيقات عامة جديدة.
لمزيد من المعلومات عن التغييرات في هذا الإصدار من Android، اطّلِع على تعديلات على القيود المفروضة على الواجهات غير المستندة إلى حزمة SDK في Android 14. للاطّلاع على مزيد من المعلومات حول الواجهات غير المتوفرة في حزمة SDK بشكل عام، اطّلِع على مقالة القيود المفروضة على الواجهات غير المتوفرة في حزمة SDK.