التغييرات في السلوك: التطبيقات التي تستهدف الإصدار 15 Android أو الإصدارات الأحدث

كما هو الحال في الإصدارات السابقة، يشمل نظام التشغيل Android 15 تغييرات في السلوك قد تؤثر في تطبيقك. تنطبق التغييرات التالية في السلوك حصريًا على التطبيقات التي تستهدف الإصدار 15 من نظام التشغيل Android أو الإصدارات الأحدث. إذا كان تطبيقك يستهدف الإصدار 15 من نظام التشغيل Android أو الإصدارات الأحدث، عليك تعديل تطبيقك لتفعيل هذه السلوكيات بشكلٍ سليم، حيث ينطبق ذلك.

احرص أيضًا على مراجعة قائمة التغييرات في السلوك التي تؤثر في جميع التطبيقات التي تعمل بنظام التشغيل Android 15 بغض النظر عن targetSdkVersion تطبيقك.

الوظيفة الأساسية

يعمل Android 15 على تعديل الإمكانات الأساسية المتنوعة لنظام Android أو توسيعها.

التغييرات على الخدمات التي تعمل في المقدّمة

سنُجري التغييرات التالية على الخدمات التي تعمل في المقدّمة مع الإصدار 15 من نظام Android.

سلوك مهلة الخدمة التي تعمل في المقدّمة لمزامنة البيانات

يقدّم Android 15 سلوكًا جديدًا للمهلة في dataSync للتطبيقات التي تستهدف Android 15 (المستوى 35 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث. ينطبق هذا السلوك أيضًا على نوع الخدمة الجديدة التي تعمل في المقدّمة mediaProcessing.

يسمح النظام بتشغيل خدمات dataSync للتطبيق لمدة إجمالية تبلغ 6 ساعات خلال فترة 24 ساعة، وبعد ذلك يستدعي النظام أسلوب Service.onTimeout(int, int) للخدمة التي تعمل (تم تقديمه في Android 15). في هذه المرحلة، تتوفّر للخدمة بضع ثوانٍ للاتصال بالرقم Service.stopSelf(). عند استدعاء Service.onTimeout()، لن تعود الخدمة خدمة تعمل في المقدّمة. إذا لم تُشغِّل الخدمة Service.stopSelf()، يُرسِل النظام استثناءً داخليًا. يتم تسجيل الاستثناء في Logcat مع الرسالة التالية:

Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type dataSync did not stop within its timeout: [component name]"

لتجنُّب المشاكل المتعلّقة بهذا التغيير في السلوك، يمكنك اتّخاذ إجراء أو أكثر من الإجراءات التالية:

  1. يجب أن تنفِّذ خدمتك طريقة Service.onTimeout(int, int) الجديدة. عندما يتلقّى تطبيقك المكالمة المُعاد توجيهها، احرص على الاتصال بالرقم stopSelf() في غضون بضع ثوانٍ. (إذا لم توقف التطبيق على الفور، سيُنشئ النظام حالة تعطُّل.)
  2. تأكَّد من أنّ خدمات dataSync في تطبيقك لا تعمل لأكثر من إجمالي 6 ساعات في أي فترة 24 ساعة (ما لم يتفاعل المستخدم مع التطبيق، يؤدي ذلك إلى إعادة ضبط الموقّت).
  3. يجب عدم بدء تشغيل خدمات "dataSync" التي تعمل في المقدّمة إلا نتيجة تفاعل مباشر من المستخدم. وبما أنّ تطبيقك يعمل في المقدّمة عند بدء الخدمة، تبقى الخدمة متاحة خلال الساعات الست الكاملة بعد انتقال التطبيق إلى الخلفية.
  4. بدلاً من استخدام خدمة تعمل في المقدّمة dataSync، يمكنك استخدام واجهة برمجة تطبيقات بديلة.

إذا استمر تشغيل خدمات dataSync التي تعمل في المقدّمة في تطبيقك لمدة 6 ساعات في آخر 24 ساعة، لا يمكنك بدء خدمة أخرى تعمل في المقدّمة dataSync ما لم ينقل المستخدم تطبيقك إلى المقدّمة (ما يؤدي إلى إعادة ضبط الموقّت). إذا حاولت بدء خدمة "dataSync" أخرى تعمل في المقدّمة، سيعرض النظام ForegroundServiceStartNotAllowedException رسالة خطأ مثل "سبق أن نفد الحدّ الزمني لنوع الخدمة التي تعمل في المقدّمة "dataSync".

الاختبار

لاختبار سلوك تطبيقك، يمكنك تفعيل مهلات مزامنة البيانات حتى إذا كان تطبيقك لا يستهدف الإصدار 15 من نظام التشغيل Android (ما دام التطبيق يعمل على جهاز يعمل بالإصدار 15 من نظام التشغيل Android). لتفعيل مهلات الانتظار، شغِّل الأمر adb التالي:

adb shell am compat enable FGS_INTRODUCE_TIME_LIMITS your-package-name

يمكنك أيضًا تعديل فترة المهلة لتسهيل اختبار سلوك تطبيقك عند بلوغ الحدّ الأقصى. لضبط فترة مهلة جديدة، شغِّل adb الأمر التالي:

adb shell device_config put activity_manager data_sync_fgs_timeout_duration duration-in-milliseconds

نوع جديد من الخدمة التي تعمل في المقدّمة لمعالجة الوسائط

يقدّم Android 15 نوعًا جديدًا من الخدمات التي تعمل في المقدّمة، وهو mediaProcessing. هذا نوع الخدمة مناسب لعمليات مثل تحويل ترميز ملفات الوسائط. على سبيل المثال، قد ينزِّل تطبيق وسائط ملفًا صوتيًا ويحتاج إلى تحويله إلى تنسيق مختلف قبل تشغيله. يمكنك استخدام mediaProcessing خدمة تعمل في المقدّمة للتأكّد من استمرار الإحالة الناجحة حتى عندما يكون التطبيق في الخلفية.

يسمح النظام بتشغيل خدمات mediaProcessing للتطبيق لمدة إجمالية تبلغ 6 ساعات خلال فترة 24 ساعة، وبعد ذلك يستدعي النظام أسلوب Service.onTimeout(int, int) للخدمة التي تعمل (تم تقديمه في Android 15). في هذه المرحلة، تتوفّر للخدمة بضع ثوانٍ للاتصال بالرقم Service.stopSelf(). إذا لم تُشغِّل الخدمة Service.stopSelf()، يُرسِل النظام استثناءً داخليًا. يتم تسجيل الاستثناء في Logcat مع الرسالة التالية:

Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type mediaProcessing did not stop within its timeout: [component name]"

لتجنُّب حدوث الاستثناء، يمكنك تنفيذ أحد الإجراءات التالية:

  1. اطلب من مقدّم الخدمة تنفيذ طريقة Service.onTimeout(int, int) الجديدة. عندما يتلقّى تطبيقك معاودة الاتصال، احرص على الاتصال بـ stopSelf() في غضون بضع ثوانٍ. (إذا لم توقف التطبيق على الفور، سيُنشئ النظام حالة تعطُّل.)
  2. تأكَّد من أنّ خدمات mediaProcessing في تطبيقك لا تعمل لأكثر من إجمالي 6 ساعات في أي فترة 24 ساعة (ما لم يتفاعل المستخدم مع التطبيق، يؤدي ذلك إلى إعادة ضبط الموقّت).
  3. لا تبدأ mediaProcessing الخدمات التي تعمل في المقدّمة إلا نتيجةً لتفاعل مباشر من العميل، لأنّ تطبيقك يكون في المقدّمة عند بدء الخدمة، ويكون لدى خدمتك ست ساعات كاملة بعد انتقال التطبيق إلى الخلفية.
  4. بدلاً من استخدام خدمة mediaProcessing تعمل في المقدّمة، استخدِم واجهة برمجة تطبيقات بديلة، مثل WorkManager.

إذا استمر تشغيل خدمات mediaProcessing التي تعمل في المقدّمة في تطبيقك لمدة 6 ساعات في آخر 24 ساعة، لا يمكنك بدء خدمة أخرى تعمل في المقدّمة mediaProcessing ما لم ينقل المستخدم تطبيقك إلى المقدّمة (ما يؤدي إلى إعادة ضبط الموقّت). إذا حاولت بدء خدمة "mediaProcessing" أخرى تعمل في المقدّمة، سيعرض النظام ForegroundServiceStartNotAllowedException رسالة خطأ مثل "تم استنفاد المهلة الزمنية لنوع الخدمة التي تعمل في المقدّمة mediaProcessing".

لمزيد من المعلومات عن نوع الخدمة mediaProcessing، يُرجى الاطّلاع على المقالة التغييرات التي طرأت على أنواع الخدمات التي تعمل في المقدّمة لنظام التشغيل Android 15: معالجة الوسائط.

الاختبار

لاختبار سلوك تطبيقك، يمكنك تفعيل مهلات معالجة الوسائط حتى إذا كان تطبيقك لا يستهدف الإصدار 15 من نظام التشغيل Android (ما دام التطبيق يعمل على جهاز يعمل بالإصدار 15 من نظام التشغيل Android). لتفعيل مهلات الانتظار، شغِّل الأمر adb التالي:

adb shell am compat enable FGS_INTRODUCE_TIME_LIMITS your-package-name

يمكنك أيضًا تعديل فترة المهلة لتسهيل اختبار سلوك تطبيقك عند بلوغ الحدّ الأقصى. لضبط فترة مهلة جديدة، شغِّل adb الأمر التالي:

adb shell device_config put activity_manager media_processing_fgs_timeout_duration duration-in-milliseconds

القيود المفروضة على أجهزة استقبال البث على BOOT_COMPLETED التي تشغِّل الخدمات التي تعمل في المقدّمة

هناك قيود جديدة على إطلاق أجهزة استقبال بث BOOT_COMPLETED. والخدمات التي تعمل في المقدّمة. لا يُسمح لأجهزة استقبال BOOT_COMPLETED بتشغيل الأنواع التالية من الخدمات التي تعمل في المقدّمة:

إذا حاول مستقبل BOOT_COMPLETED بدء أيّ من هذه الأنواع من الخدمات التي تعمل في المقدّمة، يُرسِل النظام الخطأ ForegroundServiceStartNotAllowedException.

الاختبار

لاختبار سلوك تطبيقك، يمكنك تفعيل هذه القيود الجديدة حتى إذا كان تطبيقك لا يستهدف الإصدار 15 من Android (ما دام التطبيق يعمل على جهاز يعمل بالإصدار 15 من Android). شغِّل الأمر adb التالي:

adb shell am compat enable FGS_BOOT_COMPLETED_RESTRICTIONS your-package-name

لإرسال بث BOOT_COMPLETED بدون إعادة تشغيل الجهاز، يُرجى اتّباع الخطوات التالية: شغِّل الأمر adb التالي:

adb shell am broadcast -a android.intent.action.BOOT_COMPLETED your-package-name

القيود المفروضة على بدء الخدمات التي تعمل في المقدّمة عندما يحصل تطبيق على إذن "SYSTEM_ALERT_WINDOW"

في السابق، إذا كان التطبيق يمتلك إذن SYSTEM_ALERT_WINDOW، كان بإمكانه بدء خدمة تعمل في المقدّمة حتى إذا كان التطبيق قيد التشغيل في الخلفية (كما هو описан في الاستثناءات من القيود المفروضة على بدء التطبيقات في الخلفية).

إذا كان التطبيق يستهدف الإصدار 15 من نظام التشغيل Android، أصبح هذا الإعفاء الآن أكثر تقييدًا. يجب أن يحصل التطبيق الآن على إذن SYSTEM_ALERT_WINDOW وأيضًا أن يتضمّن نافذة ملف شخصي مثبّت مرئية. وهذا يعني أنّ التطبيق يجب أن يفتح أولاً نافذة TYPE_APPLICATION_OVERLAY و يجب أن تكون النافذة مرئية قبل بدء خدمة تعمل في المقدّمة.

إذا حاول تطبيقك بدء خدمة تعمل في المقدّمة من الخلفية بدون استيفاء هذه المتطلبات الجديدة (وليس لديه أي استثناء آخر)، يُرسِل النظام الخطأ ForegroundServiceStartNotAllowedException.

إذا كان تطبيقك يعلن عن إذن SYSTEM_ALERT_WINDOW ويشغّل الخدمات التي تعمل في المقدّمة من الخلفية، قد يتأثّر بالتغيير الذي تم إجراؤه. إذا حصل تطبيقك على ForegroundServiceStartNotAllowedException، تحقَّق من ترتيب عمليات تطبيقك وتأكَّد من أنّ تطبيقك لديه نافذة تراكب نشطة قبل أن يحاول بدء خدمة تعمل في المقدّمة من الخلفية. يمكنك التحقّق مما إذا كانت نافذة التراكب مرئية حاليًا من خلال استدعاء View.getWindowVisibility()، أو يمكنك إلغاء View.onWindowVisibilityChanged() للحصول على إشعارات عند تغيير مستوى العرض.

الاختبار

لاختبار سلوك تطبيقك، يمكنك تفعيل هذه القيود الجديدة حتى إذا كان تطبيقك لا يستهدف الإصدار 15 من نظام التشغيل Android (ما دام التطبيق يعمل على جهاز Android 15). لتفعيل هذه القيود الجديدة على بدء الخدمات التي تعمل في المقدّمة من الخلفية، شغِّل الأمر adb التالي:

adb shell am compat enable FGS_SAW_RESTRICTIONS your-package-name

تغييرات على الوقت الذي يمكن للتطبيقات فيه تعديل الحالة العامة لوضع "عدم الإزعاج"

لم يعُد بإمكان التطبيقات التي تستهدف الإصدار 15 من نظام التشغيل Android تغيير الحالة أو السياسة العامة لميزة عدم الإزعاج (DND) على جهاز (إما من خلال تعديل إعدادات المستخدم أو إيقاف وضع DND). بدلاً من ذلك، يجب أن تساهم التطبيقات في السمة AutomaticZenRule، التي يدمجها النظام في سياسة عالمية مع المخطط الحالي الأكثر تقييدًا-policy-wins. إنّ الطلبات الموجّهة إلى واجهات برمجة التطبيقات الحالية والتي كانت تأثرت سابقًا بالحالة العامة (setInterruptionFilter, setNotificationPolicy) تؤدي إلى إنشاء أو تعديل AutomaticZenRuleضمنية، يتم إيقافها وإيقافها بناءً على دورة طلب البيانات من واجهة برمجة التطبيقات هذه.

يُرجى العلم بأنّ هذا التغيير لا يؤثّر إلا في السلوك الملحوظ فقط إذا كان التطبيق يطلب setInterruptionFilter(INTERRUPTION_FILTER_ALL) ويتوقّع أن تؤدي هذه المكالمة إلى إيقاف AutomaticZenRule الذي سبق أن فعَّله مالكو التطبيق.

التغييرات في واجهة برمجة التطبيقات OpenJDK

يواصل نظام التشغيل Android 15 العمل على إعادة تحميل المكتبات الأساسية لنظام Android لمواءمتها مع الميزات في أحدث إصدارات OpenJDK LTS.

يمكن أن تؤثّر بعض هذه التغييرات في توافق التطبيقات التي تستهدف الإصدار Android 15 (المستوى 35 لواجهة برمجة التطبيقات):

  • تغييرات على واجهات برمجة التطبيقات لتنسيق السلاسل: أصبح التحقّق من فهرس الوسيطات والأعلام والعرض والدقة أكثر صرامة عند استخدام واجهات برمجة التطبيقات التالية String.format() وFormatter.format():

    على سبيل المثال، يتم طرح الاستثناء التالي عند استخدام فهرس وسيطة يساوي 0 (%0 في سلسلة التنسيق):

    IllegalFormatArgumentIndexException: Illegal format argument index = 0
    

    في هذه الحالة، يمكن حلّ المشكلة باستخدام فهرس الوسيطة 1 (%1 في سلسلة التنسيق).

  • تغييرات على نوع المكوّن Arrays.asList(...).toArray(): عند استخدام Arrays.asList(...).toArray()، يصبح نوع المكوّن للصفيف الناتج هو Object الآن، وليس نوع عناصر الصفيف الأساسي. وبالتالي، يُعرِض الرمز التالي ClassCastException:

    String[] elements = (String[]) Arrays.asList("one", "two").toArray();
    

    في هذه الحالة، للحفاظ على String كنوع المكوّن في السلسلة الناتجة، يمكنك استخدام Collection.toArray(Object[]) بدلاً من ذلك:

    String[] elements = Arrays.asList("two", "one").toArray(new String[0]);
    
  • تغييرات في معالجة رموز اللغة: عند استخدام واجهة برمجة التطبيقات Locale، لم تعُد رموز اللغة للغة العبرية واليديشية والإندونيسية تُحوَّل إلى أشكالها القديمة (اللغة العبرية: iw، واليديشية: ji، والإندونيسية: in). عند تحديد رمز اللغة لواحدة من هذه اللغات، استخدِم الرموز من ISO 639-1 بدلاً من ذلك (اللغة العبرية: he، واليديشية: yi، والإندونيسية: id).

  • تغييرات على تسلسلات الأعداد الصحيحة العشوائية: بعد التغييرات التي تم إجراؤها في https://bugs.openjdk.org/browse/JDK-8301574، تعرض الآن Random.ints() الطرق تسلسلًا مختلفًا من الأرقام عن Random.nextInt() الطرق:

    بوجهٍ عام، من المفترض ألا يؤدي هذا التغيير إلى إيقاف عمل التطبيق، ولكن يجب ألا يتوقّع رمزك البرمجي أن يتطابق التسلسل الذي تم إنشاؤه من طرق Random.ints() مع Random.nextInt().

يمكن أن تؤثّر واجهة برمجة التطبيقات الجديدة SequencedCollection في توافق تطبيقك بعد تعديل compileSdk في إعدادات إنشاء تطبيقك لاستخدام Android 15 (المستوى 35 لواجهة برمجة التطبيقات):

  • تداخل مع دوالّ الإضافات MutableList.removeFirst() و MutableList.removeLast() في kotlin-stdlib

    يتم ربط نوع List في Java بنوع MutableList في Kotlin. بما أنّ واجهات برمجة التطبيقات List.removeFirst() وList.removeLast() تم طرحها في الإصدار 15 من Android (المستوى 35 من واجهة برمجة التطبيقات)، يحلّ مُجمِّع Kotlin طلبات بيانات الدوالّ، مثل list.removeFirst()، بشكلٍ ثابت في واجهات برمجة التطبيقات الجديدة List بدلاً من دالّات الإضافة في kotlin-stdlib.

    في حال إعادة تجميع تطبيق مع ضبط compileSdk على 35 وminSdk على 34 أو إصدار أقدم، ثم تشغيل التطبيق على Android 14 والإصدارات الأقدم، يتم طرح خطأ أثناء التشغيل:

    java.lang.NoSuchMethodError: No virtual method
    removeFirst()Ljava/lang/Object; in class Ljava/util/ArrayList;
    

    يمكن أن يرصد خيار NewApi lint الحالي في "المكوّن الإضافي لنظام Gradle المتوافق مع Android" استخدامات واجهة برمجة التطبيقات الجديدة هذه.

    ./gradlew lint
    
    MainActivity.kt:41: Error: Call requires API level 35 (current min is 34): java.util.List#removeFirst [NewApi]
          list.removeFirst()
    

    لحلّ استثناء وقت التشغيل وأخطاء Lint، يمكن استبدال استدعاءات الدالتَين removeFirst() و removeLast() بدالتَي removeAt(0) و removeAt(list.lastIndex) على التوالي في Kotlin. إذا كنت تستخدم IDE IDE Android Studio Ladybug | 2024.1.3 أو إصدارًا أحدث، يتيح لك أيضًا خيارًا لإصلاح هذه الأخطاء بشكل سريع.

    ننصحك بإزالة @SuppressLint("NewApi") وlintOptions { disable 'NewApi' } إذا تم إيقاف خيار "التنقيح".

  • تداخل مع طرق أخرى في Java

    تمت إضافة طرق جديدة إلى الأنواع الحالية، على سبيل المثال، List وDeque. قد لا تكون هذه الطرق الجديدة متوافقة مع الطرق التي تحمل الاسم نفسه وأنواع الوسيطات نفسها في الواجهات والفئات الأخرى. في حال تعارض توقيع إحدى الطرق مع عدم التوافق، يُخرج مُجمِّع javac خطأً في وقت الإنشاء. على سبيل المثال:

    مثال على الخطأ 1:

    javac MyList.java
    
    MyList.java:135: error: removeLast() in MyList cannot implement removeLast() in List
      public void removeLast() {
                  ^
      return type void is not compatible with Object
      where E is a type-variable:
        E extends Object declared in interface List
    

    مثال على الخطأ 2:

    javac MyList.java
    
    MyList.java:7: error: types Deque<Object> and List<Object> are incompatible;
    public class MyList implements  List<Object>, Deque<Object> {
      both define reversed(), but with unrelated return types
    1 error
    

    مثال على الخطأ 3:

    javac MyList.java
    
    MyList.java:43: error: types List<E#1> and MyInterface<E#2> are incompatible;
    public static class MyList implements List<Object>, MyInterface<Object> {
      class MyList inherits unrelated defaults for getFirst() from types List and MyInterface
      where E#1,E#2 are type-variables:
        E#1 extends Object declared in interface List
        E#2 extends Object declared in interface MyInterface
    1 error
    

    لإصلاح أخطاء الإنشاء هذه، يجب أن تلغي الفئة التي تنفّذ هذه الواجهات الأسلوب باستخدام نوع إرجاع متوافق. مثلاً:

    @Override
    public Object getFirst() {
        return List.super.getFirst();
    }
    

الأمان

يتضمّن Android 15 تغييرات تعزّز أمان النظام للمساعدة في حماية التطبيقات والمستخدمين من التطبيقات الضارّة.

بدء الأنشطة الآمنة في الخلفية

يحمي Android 15 المستخدمين من التطبيقات الضارة ويمنحهم إمكانية تحكُّم أكبر في أجهزته عن طريق إضافة تغييرات تمنع تطبيقات الخلفية الضارة من عرض تطبيقات أخرى في المقدّمة، ورفع امتيازاتها وإساءة استخدامها تفاعل المستخدم. تم حظر عمليات إطلاق الأنشطة في الخلفية منذ Android 10 (المستوى 29)

منع التطبيقات التي لا تتطابق مع المعرّف الفريد الأعلى في الحزمة من تشغيل الأنشطة

يمكن للتطبيقات الضارة تشغيل نشاط تطبيق آخر ضمن المهمة نفسها، ثم تداخلها فوقه، ما يخلق الوهم بأنّها هذا التطبيق. ويتجاوز هجوم "اختراق المهام" الحالي القيود المفروضة على التشغيل في الخلفية لأنّه يتم تنفيذ كل ذلك ضمن المهمة المرئية نفسها. وللتخفيف من هذه المخاطر، يضيف Android 15 علامة تمنع تشغيل التطبيقات التي لا تتطابق مع المعرّف الفريد الأعلى في الحزمة والأنشطة السابقة. للموافقة على جميع أنشطة تطبيقك، عدِّل السمة allowCrossUidActivitySwitchFromBelow في ملف AndroidManifest.xml الخاص بتطبيقك:

<application android:allowCrossUidActivitySwitchFromBelow="false" >

تكون إجراءات الأمان الجديدة نشطة في حال استيفاء جميع الشروط التالية:

  • يستهدف التطبيق مرحلة الإطلاق الإصدار 15 من نظام التشغيل Android.
  • يستهدف التطبيق أعلى حزمة المهام نظام التشغيل Android 15.
  • أي نشاط مرئي تم تفعيل عناصر الحماية الجديدة له

في حال تفعيل تدابير الأمان، قد تعود التطبيقات إلى الشاشة الرئيسية بدلاً من التطبيق الأخير المرئي، إذا أنهت مهمتها.

تغييرات أخرى

بالإضافة إلى القيود المفروضة على مطابقة المعرّف الفريد، تم أيضًا تضمين التغييرات التالية:

  • تغيير PendingIntent صانع محتوى إلى حظر عمليات إطلاق الأنشطة في الخلفية من خلال التلقائية. ويساعد هذا في منع التطبيقات من إنشاء PendingIntent الذي يمكن أن تسيء إليه الجهات المسيئة.
  • لا تعرض تطبيقًا في المقدّمة ما لم يسمح PendingIntent المُرسِل بذلك. يهدف هذا التغيير إلى منع التطبيقات الضارة من إساءة استخدام والقدرة على بدء الأنشطة في الخلفية. بشكلٍ افتراضي، لا تكون التطبيقات يُسمح له بعرض حزمة المهام في المقدّمة ما لم يسمح صانع المحتوى امتيازات تشغيل النشاط في الخلفية أو لدى المُرسِل نشاط في الخلفية امتيازات الإطلاق.
  • التحكّم في كيفية إنهاء النشاط الرئيسي في حزمة المهام لمهمته إذا كانت عند الانتهاء من تحديد "أهم نشاط"، سيعود Android إلى أي مهمة آخر نشاط. علاوة على ذلك، إذا أنهى نشاط غير بارز مهمته، فسيجري Android والعودة إلى الشاشة الرئيسية؛ لن يحجب انتهاء هذا العنصر الأخرى.
  • منع إطلاق أنشطة عشوائية من تطبيقات أخرى على تطبيقك المهمة. ويمنع هذا التغيير التطبيقات الضارة من التصيُّد الاحتيالي للمستخدمين من خلال إنشاء أنشطة تبدو وكأنها من تطبيقات أخرى.
  • حظر النوافذ غير المرئية من النظر في النشاط في الخلفية عمليات الإطلاق. يساعد ذلك على منع التطبيقات الضارة من إساءة استخدام الخلفية. نشاط عرض محتوى غير مرغوب فيه أو ضار للمستخدمين.

نوايا أكثر أمانًا

Android 15 引入了新的可选安全措施,以提高 intent 的安全性和稳健性。这些变更旨在防止潜在的漏洞以及恶意应用可能利用的 intent 滥用行为。Android 15 对 intent 的安全性进行了两项主要改进:

  • 与目标 intent 过滤器匹配:定位到特定组件的 intent 必须与目标的 intent 过滤器规范完全匹配。如果您发送 intent 来启动其他应用的 activity,目标 intent 组件需要与接收 activity 声明的 intent 过滤器保持一致。
  • intent 必须具有操作:没有操作的 intent 将不再与任何 intent 过滤器匹配。这意味着,用于启动 activity 或服务的 intent 必须具有明确定义的操作。

如需检查您的应用对这些更改的响应方式,请在应用中使用 StrictMode。如需查看有关 Intent 使用违规行为的详细日志,请添加以下方法:

Kotlin


fun onCreate() {
    StrictMode.setVmPolicy(VmPolicy.Builder()
        .detectUnsafeIntentLaunch()
        .build()
    )
}

Java


public void onCreate() {
    StrictMode.setVmPolicy(new VmPolicy.Builder()
            .detectUnsafeIntentLaunch()
            .build());
}

تجربة المستخدم وواجهة المستخدم للنظام

يتضمّن Android 15 بعض التغييرات التي تهدف إلى توفير تجربة مستخدم أكثر اتساقًا وبساطة.

تغييرات في مساحة النافذة

هناك تغييران متعلّقان بمساحات النوافذ الداخلية في Android 15: يتم فرض استخدام جميع النوافذ بشكلٍ تلقائي، كما أنّ هناك تغييرات في الإعدادات، مثل الإعدادات التلقائية لأشرطة النظام.

التنفيذ الشامل

يتم عرض التطبيقات بشكل تلقائي على الأجهزة التي تعمل بنظام التشغيل Android 15 إذا كان التطبيق يستهدف Android 15 (المستوى 35 لواجهة برمجة التطبيقات).

تطبيق يستهدف الإصدار 14 من نظام التشغيل Android ولا يشغل الشاشة بالكامل على جهاز Android 15


تطبيق يستهدف الإصدار 15 من نظام التشغيل Android (المستوى 35 لواجهة برمجة التطبيقات) ويكون مملوءًا بالشاشة على جهاز يعمل بالإصدار 15 من نظام التشغيل Android يستخدم هذا التطبيق بشكل أساسي مكوّنات Compose في Material 3 التي تطبّق الأجزاء المضمّنة تلقائيًا. لا تتأثر هذه الشاشة سلبًا بتطبيق ميزة "ملء الشاشة" في Android 15.

هذا تغيير جذري قد يؤثر سلبًا في واجهة مستخدم تطبيقك. تؤثر التغييرات في مجالات واجهة المستخدم التالية:

  • شريط التنقّل في عناصر التحكّم بالإيماءات
    • شفاف تلقائيًا.
    • يتم إيقاف الإزاحة السفلية حتى يتم رسم المحتوى خلف شريط التنقّل في النظام ما لم يتم تطبيق المكوّنات المضمّنة.
    • تمّت إيقاف setNavigationBarColor وR.attr#navigationBarColor نهائيًا ولا يؤثّران في التنقّل بالإيماءات.
    • لا يزال setNavigationBarContrastEnforced و R.attr#navigationBarContrastEnforced بدون تأثير على التنقّل باستخدام الإيماءات.
  • التنقّل باستخدام ثلاثة أزرار
    • ويتم ضبط التعتيم على 80% تلقائيًا، مع إمكانية مطابقة اللون لخلفية النافذة.
    • تم إيقاف الإزاحة السفلية حتى يتم رسم المحتوى خلف شريط التنقّل في النظام ما لم يتم تطبيق عمليات الإدراج.
    • يتم تلقائيًا ضبط setNavigationBarColor وR.attr#navigationBarColor لتطابق خلفية النافذة. يجب أن تكون خلفية النافذة قابلة للرسم بالألوان لكي يتم تطبيق هذا الخيار التلقائي. تمّت إيقاف واجهة برمجة التطبيقات هذه نهائيًا، ولكنها لا تزال تؤثر في التنقّل باستخدام 3 أزرار.
    • يكون الخياران setNavigationBarContrastEnforced و R.attr#navigationBarContrastEnforced صحيحَين تلقائيًا، ما يضيف خلفية غير شفافة بنسبة% 80 على ميزة التنقّل باستخدام 3 أزرار.
  • شريط الحالة
    • شفافة تلقائيًا
    • يكون الإزاحة العلوية غير مفعّلة حتى يتم رسم المحتوى خلف شريط الحالة ما لم يتم تطبيق العناصر المضمّنة.
    • تم إيقاف setStatusBarColor وR.attr#statusBarColor نهائيًا وليسا لهما أي تأثير على Android 15.
    • تم إيقاف setStatusBarContrastEnforced و R.attr#statusBarContrastEnforced نهائيًا، ولكن لا يزال لهما أثر في Android 15.
  • الجزء المُقتطع من الشاشة
    • يجب أن يكون layoutInDisplayCutoutMode للنوافذ غير العائمة هو LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS. يتم تفسير SHORT_EDGES وNEVER و DEFAULT على أنّها ALWAYS لكي لا يظهر للمستخدمين شريط أسود بسبب فتحة الشاشة، ولكي تظهر الشاشة من الحافة إلى الحافة.

يعرض المثال التالي تطبيقًا قبل استهداف Android 15 (المستوى 35 لواجهة برمجة التطبيقات) وبعده، وقبل تطبيق العناصر المضمّنة وبعده.

تطبيق يستهدف الإصدار 14 من نظام التشغيل Android ولا يشغل الشاشة بالكامل على جهاز Android 15
تطبيق يستهدف الإصدار 15 من نظام التشغيل Android (المستوى 35 لواجهة برمجة التطبيقات) ويكون مملوءًا بالكامل على جهاز يعمل بالإصدار 15 من نظام التشغيل Android ومع ذلك، يتم الآن إخفاء العديد من العناصر من خلال شريط الحالة أو شريط التنقّل الذي يحتوي على ثلاثة أزرار أو الصورة المقطوعة للشاشة بسبب إجراءات التنفيذ الشاملة في Android 15. تشمل واجهة المستخدم المخفية شريط التطبيق العلوي Material 2 وأزرار الإجراءات العائمة وعناصر القائمة.
التطبيق الذي يستهدف Android 15 (المستوى 35 لواجهة برمجة التطبيقات) يكون متوافقًا مع الأجهزة التي تعمل بالإصدار 15 من نظام التشغيل Android، ويستخدم مساحات داخلية كي لا يتم إخفاء واجهة المستخدم.
العناصر التي يجب التحقّق منها إذا كان تطبيقك معروضًا على الشاشة بالكامل

إذا كان تطبيقك ممتدًا من الحافة إلى الحافة ويطبّق المكوّنات المضمّنة، لن يتأثّر تطبيقك كثيرًا، باستثناء السيناريوهات التالية. ومع ذلك، حتى إذا كنت تعتقد أنّ تطبيقك غير متأثر، ننصحك باختباره.

  • إذا كانت لديك نافذة غير عائمة، مثل Activity التي تستخدم SHORT_EDGES أو NEVER أو DEFAULT بدلاً من LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS إذا تعطّل تطبيقك عند تشغيله، قد يكون السبب شاشة البداية. يمكنك ترقية الاعتماد على core splashscreen إلى 1.2.0-alpha01 أو إصدار أحدث أو ضبط window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutInDisplayCutoutMode.always.
  • قد تكون هناك شاشات ذات عدد زيارات منخفض مع واجهة مستخدم مغلقة. تحقق من أن هذه الشاشات الأقل زيارة لا تحتوي على واجهة مستخدم مغطاة. تشمل الشاشات التي تجذب عددًا أقل من الزيارات ما يلي:
    • شاشات الإعداد أو تسجيل الدخول
    • صفحات الإعدادات
العناصر التي يجب التحقّق منها إذا لم يكن تطبيقك معروضًا على الشاشة بالكامل

إذا لم يكن تطبيقك معروضًا على الشاشة بالكامل، من المرجّح أن يتأثّر بالتغيير. بالإضافة إلى سيناريوهات التطبيقات التي تظهر على الشاشة بالكامل، يجب مراعاة ما يلي:

  • إذا كان تطبيقك يستخدم مكوّنات Material 3 ( androidx.compose.material3) في الإنشاء، مثل TopAppBar BottomAppBar وNavigationBar، من المرجّح أن لا تتأثّر هذه المكوّنات لأنّها تتعامل تلقائيًا مع الأجزاء المضمّنة.
  • إذا كان تطبيقك يستخدم مكوّنات Material 2 ( androidx.compose.material) في أداة Compose، لن تعالج هذه المكوّنات العناصر المضمّنة تلقائيًا. ومع ذلك، يمكنك الوصول إلى العناصر المضمّنة وتطبيقها يدويًا. في الإصدار androidx.compose.material 1.6.0 والإصدارات الأحدث، استخدِم المَعلمة windowInsets لتطبيق المُدخلات يدويًا لعناصر BottomAppBar وTopAppBar و BottomNavigation وNavigationRail. وبالمثل، استخدِم المَعلمة contentWindowInsets لمحاولة Scaffold.
  • إذا كان تطبيقك يستخدم عناصر العرض ومكونات Material Design (com.google.android.material)، تتعامل معظم مكونات Material Design المستندة إلى عناصر العرض، مثل BottomNavigationView أو BottomAppBar أو NavigationRailView أو NavigationView، مع الأجزاء المضمّنة ولا تتطلّب أي جهد إضافي. ومع ذلك، عليك إضافة android:fitsSystemWindows="true" في حال استخدام AppBarLayout.
  • بالنسبة إلى العناصر المخصّصة القابلة للتجميع، طبِّق الأجزاء المُدمجة يدويًا كحشو. إذا كان المحتوى الخاص بك ضمن Scaffold، يمكنك استهلاك وحدات إعلانية باستخدام قيم المساحة المتروكة Scaffold. بخلاف ذلك، يمكنك تطبيق مساحة متروكة باستخدام أحد WindowInsets.
  • إذا كان تطبيقك يستخدم طرق العرض وBottomSheet أو SideSheet أو حاوية مخصّصة، يمكنك تطبيق مساحة متروكة باستخدام ViewCompat.setOnApplyWindowInsetsListener. بالنسبة إلى RecyclerView، يمكنك تطبيق الحشو باستخدام هذا المستمع وإضافة clipToPadding="false" أيضًا.
كيفية التحقّق مما إذا كان يجب أن يوفّر تطبيقك حماية مخصّصة في الخلفية

إذا كان يجب أن يوفّر تطبيقك حماية مخصّصة في الخلفية عند استخدام ميزة "التنقّل باستخدام ثلاثة أزرار" أو شريط الحالة، يجب أن يعرض تطبيقك عناصر قابلة للإنشاء أو العرض خلف شريط النظام باستخدام WindowInsets.Type#tappableElement() للحصول على ارتفاع شريط التنقّل المكوَّن من ثلاثة أزرار أو WindowInsets.Type#statusBars.

موارد إضافية من الحافة إلى الحافة

راجع دليلي Edge to Edge View وEdge to Edge Compose لمعرفة اعتبارات إضافية حول تطبيق المساحات الداخلية.

واجهات برمجة التطبيقات المتوقّفة نهائيًا

تم إيقاف واجهات برمجة التطبيقات التالية نهائيًا، ولكن لم يتم إيقافها:

تم إيقاف واجهات برمجة التطبيقات التالية نهائيًا وإيقافها:

الإعدادات الثابتة

إذا كان تطبيقك يستهدف الإصدار 15 من نظام التشغيل Android (المستوى 35 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، لن يتم Configuration استبعاد أشرطة النظام بعد الآن. إذا كنت تستخدم حجم الشاشة في الفئة Configuration لاحتساب التنسيق، عليك استبدالها ببدائل أفضل مثل ViewGroup أو WindowInsets أو WindowMetricsCalculator مناسبَين حسب حاجتك.

تتوفر Configuration منذ الإصدار 1 من واجهة برمجة التطبيقات. يتم الحصول عليه عادةً من Activity.onConfigurationChanged. ويقدّم معلومات مثل كثافة النوافذ ومقدار التمويه والأحجام. من الخصائص المهمة لأحجام النوافذ المعروضة من Configuration أنّها كانت تستبعد في السابق أشرطة النظام.

يتم استخدام حجم الإعدادات عادةً لاختيار الموارد، مثل /res/layout-h500dp، ولا يزال هذا الاستخدام صالحًا. ومع ذلك، لم يُنصح أبدًا باستخدامه في حساب التنسيق. إذا قمت بذلك، يجب عليك الابتعاد عنه الآن. وعليك استبدال استخدام Configuration بشيء أكثر ملاءمة حسب حالة استخدامك.

إذا كنت تستخدمها لاحتساب التنسيق، استخدِم ViewGroup مناسبًا، مثل CoordinatorLayout أو ConstraintLayout. وإذا كنت تستخدمه لتحديد ارتفاع شريط تنقل النظام، استخدِم WindowInsets. إذا أردت معرفة الحجم الحالي لنافذة تطبيقك، استخدِم computeCurrentWindowMetrics.

توضّح القائمة التالية الحقول المتأثرة بهذا التغيير:

  • لم يعُد حجما Configuration.screenWidthDp وscreenHeightDp يستبعدان أشرطة النظام.
  • يتأثّر Configuration.smallestScreenWidthDp بشكل غير مباشر بالتغييرات في screenWidthDp وscreenHeightDp.
  • يتأثر Configuration.orientation بشكل غير مباشر بالتغييرات التي تطرأ على screenWidthDp وscreenHeightDp على الأجهزة القريبة من المربّع.
  • يتأثر Display.getSize(Point) بشكل غير مباشر بالتغييرات في Configuration. وتم إيقاف هذه الميزة نهائيًا اعتبارًا من المستوى 30 لواجهة برمجة التطبيقات.
  • كان تطبيق Display.getMetrics() يعمل بهذه الطريقة منذ المستوى 33 لواجهة برمجة التطبيقات.

القيمة التلقائية لسمة elegantTextHeight هي true

في التطبيقات التي تستهدف الإصدار 15 من نظام التشغيل Android، تصبح السمة elegantTextHeight TextView true تلقائيًا، لتستبدل الخط المكثّف المُستخدَم تلقائيًا ببعض النصوص البرمجية ذات المقاييس العمودية الكبيرة بنص أكثر قابلية للقراءة. وقد تم تصميم الخط المكثّف لمنع تعطّل التنسيقات، ويمنع Android 13 (المستوى 33 لواجهة برمجة التطبيقات) العديد من هذه الأعطال من خلال السماح لتنسيق النص بزيادة الارتفاع العمودي باستخدام السمة fallbackLineSpacing.

في نظام التشغيل Android 15، يظل الخط المضغوط موجودًا في النظام، لذلك يمكن لتطبيقك ضبط elegantTextHeight على false للحصول على السلوك نفسه كما في السابق، ولكن من غير المحتمل أن يكون متوافقًا في الإصدارات القادمة. مثلاً، إذا كان تطبيقك متوافقًا مع النصوص التالية: العربية واللاوية وميانمار والتاميلية والغوجاراتية والكنادية والماليالامية أو الأودية أو التيلوغوية أو التايلاندية، يمكنك اختبار تطبيقك من خلال ضبط elegantTextHeight على true.

سلوك "elegantTextHeight" للتطبيقات التي تستهدف الإصدار 14 من Android (المستوى 34 لواجهة برمجة التطبيقات) والإصدارات الأقدم
elegantTextHeight سلوك التطبيقات التي تستهدف Android 15.

تغييرات في عرض TextView لأشكال الأحرف المعقّدة

في الإصدارات السابقة من Android، قد ترسم بعض الخطوط المكتوبة بخط اليد أو اللغات التي تتضمن أشكالًا معقّدةً الأحرف في منطقة الحرف السابق أو التالي. في بعض الحالات، تم اقتطاع هذه الأحرف في موضع البداية أو النهاية. بدءًا من Android 15، يخصّص TextView عرضًا لرسم مساحة كافية لهذه الأحرف ويسمح للتطبيقات بطلب مساحات إضافية على يمين الحرف لمنع اقتصاصه.

وبما أنّ هذا التغيير يؤثر في كيفية تحديد TextView للعرض، TextView يحدّد عرضًا أكبر تلقائيًا إذا كان التطبيق يستهدف الإصدار 15 من نظام التشغيل Android (المستوى 35 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث. يمكنك تفعيل هذا السلوك أو إيقافه من خلال طلب بيانات من واجهة برمجة التطبيقات setUseBoundsForWidth على TextView.

بما أنّ إضافة مساحة متروكة على يمين العنصر قد تؤدي إلى عدم محاذاة التنسيقات الحالية، لا تتم إضافة المساحة المتروكة تلقائيًا حتى للتطبيقات التي تستهدف الإصدار 15 من نظام التشغيل Android أو الإصدارات الأحدث. ومع ذلك، يمكنك إضافة مساحة متروكة إضافية لمنع الاقتصاص من خلال استدعاء setShiftDrawingOffsetForStartOverhang.

توضح الأمثلة التالية كيف يمكن لهذه التغييرات تحسين تخطيط النص لبعض الخطوط واللغات.

تنسيق عادي للنص الإنجليزي بخط مكتوب يتم اقتصاص بعض الحروف. في ما يلي ملف XML المقابل:

<TextView
    android:fontFamily="cursive"
    android:text="java" />
تنسيق النص الإنجليزي نفسه بعرض إضافي وسمّاعات في ما يلي ملف XML المقابل:

<TextView
    android:fontFamily="cursive"
    android:text="java"
    android:useBoundsForWidth="true"
    android:shiftDrawingOffsetForStartOverhang="true" />
التنسيق العادي للنص التايلاندي تم اقتصاص بعض الأحرف. في ما يلي ملف XML المقابل:

<TextView
    android:text="คอมพิวเตอร์" />
تنسيق النص التايلاندي نفسه بعرض إضافي وبمسافة ملء إضافية في ما يلي ملف XML المقابل:

<TextView
    android:text="คอมพิวเตอร์"
    android:useBoundsForWidth="true"
    android:shiftDrawingOffsetForStartOverhang="true" />

ارتفاع السطر التلقائي المراعي للّغة في EditText

在以前的 Android 版本中,文本布局拉伸了文本的高度,使其适应与当前语言区域匹配的字体的行高。例如,如果内容是日语,由于日语字体的行高比拉丁字体的行高略大,因此文本的高度就略大了。不过,尽管行高存在这些差异,但无论使用何种语言区域,EditText 元素的大小都是一致的,如下图所示:

三个表示 EditText 元素的框,这些框可以包含英语 (en)、日语 (ja) 和缅甸语 (my) 的文本。EditText 的高度相同,即使这两种语言的行高不同。

对于以 Android 15 为目标平台的应用,系统现在会为 EditText 预留最小行高,以匹配指定语言区域的参考字体,如下图所示:

三个表示 EditText 元素的框,这些框可以包含英语 (en)、日语 (ja) 和缅甸语 (my) 的文本。EditText 的高度现在包含空间,可适应这些语言字体的默认行高。

如果需要,您的应用可以通过将 useLocalePreferredLineHeightForMinimum 属性设置为 false 来恢复之前的行为,并且可以通过 Kotlin 和 Java 中的 setMinimumFontMetrics API 设置自定义最小行业指标。

الكاميرا والوسائط

يُجري نظام Android 15 التغييرات التالية على سلوك الكاميرا والوسائط للتطبيقات التي تستهدف الإصدار 15 من Android أو الإصدارات الأحدث.

القيود المفروضة على طلب تركيز الصوت

لطلب التركيز على الصوت، يجب أن تكون التطبيقات التي تستهدف الإصدار 15 من نظام التشغيل Android هي أفضل تطبيق أو تشغّل خدمة تعمل في المقدّمة. إذا حاول أحد التطبيقات طلب التركيز في حين لا يستوفي أحد هذه المتطلبات، سيتم عرض الرمز AUDIOFOCUS_REQUEST_FAILED.

يمكنك معرفة المزيد من المعلومات حول التركيز الصوتي في إدارة التركيز الصوتي.

قيود غير متاحة في حزمة SDK تم تعديلها

يتضمّن الإصدار 15 من Android قوائم معدَّلة لواجهات برمجة التطبيقات غير المتوافقة مع حِزم تطوير البرامج (SDK) والتي تم حظرها استنادًا إلى التعاون مع مطوّري تطبيقات Android وأحدث الاختبار الداخلي. نحرص كلما أمكن ذلك على توفير بدائل عامة قبل حظر الواجهات غير المستندة إلى حزمة SDK.

إذا كان تطبيقك لا يستهدف الإصدار 15 من نظام التشغيل Android، قد لا تسري بعض هذه التغييرات عليك على الفور. ومع أنّه من الممكن أن يتمكّن تطبيقك من الوصول إلى بعض الواجهات غير التابعة لحِزم SDK استنادًا إلى مستوى واجهة برمجة التطبيقات المستهدَف في تطبيقك، فإنّ استخدام أي أسلوب أو حقل غير تابع لحِزم SDK يشكّل دائمًا خطرًا كبيرًا على تطبيقك.

إذا لم تكن متأكّدًا مما إذا كان تطبيقك يستخدم واجهات غير متوفرة في حزمة SDK، يمكنك اختبار تطبيقك لمعرفة ذلك. إذا كان تطبيقك يعتمد على واجهات غير مزوّدة بحزمة SDK، عليك البدء في التخطيط للترحيل إلى بدائل حزمة SDK. ومع ذلك، ندرك أنّ بعض التطبيقات لديها حالات استخدام صالحة لاستخدام واجهات غير متوفرة في حزمة SDK. إذا لم تتمكّن من العثور على بديل لاستخدام واجهة برمجة تطبيقات غير تابعة لحزمة SDK لإحدى الميزات في تطبيقك، عليك طلب واجهة برمجة تطبيقات عامة جديدة.

لمزيد من المعلومات عن التغييرات في هذا الإصدار من Android، اطّلِع على التعديلات على قيود واجهات غير حزمة SDK في Android 15. للاطّلاع على مزيد من المعلومات حول الواجهات غير المتوفّرة في حزمة SDK بشكل عام، اطّلِع على مقالة القيود المفروضة على الواجهات غير المتوفّرة في حزمة SDK.