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

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

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

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

يعدّل Android 15 أو يوسّع إمكانات أساسية مختلفة في نظام Android.

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

نحن بصدد إجراء التغييرات التالية على الخدمات التي تعمل في المقدّمة في Android 15.

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

يقدّم 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 (ما دام التطبيق يعمل على جهاز Android 15). لتفعيل المهلات، شغِّل الأمر 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 (المستوى 35 لواجهة برمجة التطبيقات) والإصدارات الأحدث قادرة على تغيير الحالة أو السياسة الشاملة لوضع "عدم الإزعاج" على الجهاز (إما عن طريق تعديل إعدادات المستخدم أو إيقاف وضع "عدم الإزعاج"). بدلاً من ذلك، يجب أن توفّر التطبيقات ملفًا بعنوان AutomaticZenRule، والذي يجمعه النظام في سياسة عامة وفقًا لأسلوب السياسة الأكثر تقييدًا هي السائدة. تؤدي طلبات البيانات من واجهات برمجة التطبيقات الحالية التي أثرت في السابق في الحالة العامة (setInterruptionFilter، setNotificationPolicy) إلى إنشاء AutomaticZenRule ضمني أو تعديله، ويتم تفعيله أو إيقافه استنادًا إلى دورة طلبات بيانات واجهة برمجة التطبيقات.

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

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

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

يمكن أن تؤثّر بعض هذه التغييرات في توافق التطبيقات التي تستهدف الإصدار 15 من نظام التشغيل Android (المستوى 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 في إعدادات التصميم في تطبيقك لاستخدام الإصدار 15 من نظام التشغيل Android (المستوى 35 لواجهة برمجة التطبيقات):

  • تعارض مع وظائف الإضافات MutableList.removeFirst() وMutableList.removeLast() في kotlin-stdlib

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

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

    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. إذا كنت تستخدم الإصدار 2024.1.3 من استوديو Android Ladybug أو إصدارًا أحدث، سيتوفّر لك أيضًا خيار إصلاح سريع لهذه الأخطاء.

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

  • التعارض مع طرق أخرى في 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 تغييرات تعزّز أمان النظام للمساعدة في حماية التطبيقات والمستخدمين من التطبيقات الضارّة.

إصدارات بروتوكول أمان طبقة النقل (TLS) المحظورة

Android 15 限制了对 TLS 版本 1.0 和 1.1 的使用。这些版本之前已在 Android 中被弃用,但现在不允许面向 Android 15 的应用使用。

عمليات إطلاق الأنشطة في الخلفية الآمنة

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

تغييرات أخرى

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

الأهداف الأكثر أمانًا

يقدّم نظام التشغيل Android 15 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(API 级别 35)为目标平台,则在搭载 Android 15 的设备上默认以无边框显示。

以 Android 14 为目标平台且在 Android 15 设备上未以无边框显示的应用。


以 Android 15(API 级别 35)为目标平台且以无边框显示 的 Android 15 设备上的应用。此应用主要使用会自动应用边衬区的 Material 3 Compose 组件 。此屏幕不会受到 Android 15 无边框强制执行的不利影响。

这是一项重大变更,可能会对应用的界面产生不利影响。这些变更会影响以下界面区域:

  • 手势提示条导航栏
    • 默认透明。
    • 底部偏移已停用,因此除非应用了边衬区,否则内容会绘制在系统导航栏后面。
    • setNavigationBarColorR.attr#navigationBarColor 已弃用,不会影响手势导航。
    • setNavigationBarContrastEnforcedR.attr#navigationBarContrastEnforced 仍不会影响手势导航。
  • 三按钮导航
    • 默认情况下,不透明度设置为 80%,颜色可能与窗口背景颜色一致。
    • 底部偏移已停用,因此除非应用了边衬区,否则内容会绘制在系统导航栏后面。
    • setNavigationBarColorR.attr#navigationBarColor 默认设置为与窗口背景颜色一致。窗口背景必须是颜色可绘制对象,才能应用此默认设置。此 API 已弃用,但仍会影响三按钮导航。
    • setNavigationBarContrastEnforcedR.attr#navigationBarContrastEnforced 默认值为 true,这会在三按钮导航中添加 80% 不透明的背景。
  • 状态栏
    • 默认透明。
    • 顶部偏移已停用,因此除非应用了边衬区,否则内容会绘制在状态栏后面。
    • setStatusBarColorR.attr#statusBarColor 已弃用,不会影响 Android 15。
    • setStatusBarContrastEnforcedR.attr#statusBarContrastEnforced 已弃用,但仍会影响 Android 15。
  • 刘海屏
    • 非浮动窗口的 layoutInDisplayCutoutMode 必须为 LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYSSHORT_EDGESNEVERDEFAULT 会被解读为 ALWAYS,这样用户就不会看到因显示屏刘海屏而产生的黑条,并且会以无边框显示。

以下示例展示了应用在以 Android 15(API 级别 35)为目标平台之前和之后,以及在应用边衬区之前和之后的效果。此示例并不全面,在 Android Auto 上可能会显示不同的效果。

以 Android 14 为目标平台且在 Android 15 设备上未以无边框显示的应用。
以 Android 15(API 级别 35)为目标平台且在 Android 15 设备上以无边框显示的应用。不过,由于 Android 15 无边框强制执行,许多元素现在会被状态栏、三按钮导航栏或刘海屏遮盖。被遮盖的界面包括 Material 2 顶部应用栏、悬浮操作按钮和列表项。
以 Android 15(API 级别 35)为目标平台且在 Android 15 设备上以无边框显示的应用,并应用了边衬区,因此界面不会被 遮盖。
如果您的应用已以无边框显示,需要检查哪些内容

如果您的应用已以 无边框 显示并应用了边衬区,则大部分情况下 不会受到影响,但在以下情形中除外。不过,即使您认为自己不会受到影响,我们也建议您测试应用。

  • 您有一个非浮动窗口,例如使用 SHORT_EDGESNEVERDEFAULT 而不是 LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYSActivity。如果您的应用在启动时崩溃,可能是因为启动画面所致。您可以将 核心 启动画面 依赖项升级到 1.2.0-alpha01 或更高版本,也可以设置 window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutInDisplayCutoutMode.always
  • 可能存在流量较低的屏幕,其界面被遮盖。验证这些访问量较少的屏幕是否没有被遮盖的界面。流量较低的屏幕包括:
    • 新手入门或登录屏幕
    • “设置”页面
如果您的应用尚未以无边框显示,需要检查哪些内容

如果您的应用尚未以无边框显示,则很可能会受到影响。除了已以无边框显示的应用的情形之外,您还应考虑以下情况:

  • 如果您的应用在 Compose 中使用了 Material 3 组件 ( androidx.compose.material3),例如 TopAppBarBottomAppBarNavigationBar,这些组件可能不会 受到影响,因为它们会自动处理边衬区。
  • 如果应用使用的是 Compose 中的 Material 2 组件 ( androidx.compose.material),这些组件 本身并不会自动处理边衬区。不过,您可以获得边衬区的访问权限,然后手动应用边衬区。在 androidx.compose.material 1.6.0 及更高版本中,使用 windowInsets 参数可为 BottomAppBarTopAppBarBottomNavigationNavigationRail 手动应用边衬区。 同样,对于 Scaffold,请使用 contentWindowInsets 参数。
  • 如果应用使用了视图和 Material 组件 (com.google.android.material),则大多数基于视图的 Material 组件(例如 BottomNavigationViewBottomAppBarNavigationRailViewNavigationView)都会处理边衬区,因此不需要执行额外的操作。不过,您需要添加 android:fitsSystemWindows="true" ,如果使用 AppBarLayout
  • 对于自定义可组合项,请手动应用边衬区作为内边距。如果您的 内容位于 Scaffold 中,则可以使用 Scaffold 内边距值来使用边衬区。否则,请使用其中一个 WindowInsets应用内边距。
  • 如果应用使用的是视图和 BottomSheetSideSheet 或自定义 容器,请使用 ViewCompat.setOnApplyWindowInsetsListener应用内边距。对于 RecyclerView,请使用此监听器应用内边距,同时添加 clipToPadding="false"
如果您的应用必须提供自定义背景保护,需要检查哪些内容

如果您的应用必须为“三按钮”导航或 状态栏提供自定义背景保护,则应用应使用 WindowInsets.Type#tappableElement() 将可组合函数或视图放置在系统栏后面 ,以获取“三按钮” 导航栏高度或 WindowInsets.Type#statusBars

其他无边框资源

如需了解有关应用边衬区的其他注意事项,请参阅无边框视图无边框 Compose 指南。

已弃用的 API

以下 API 已弃用,但未停用:

以下 API 已弃用并已停用:

稳定配置

إذا كان تطبيقك يستهدف Android 15 (المستوى 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 هي "صحيح"

بالنسبة إلى التطبيقات التي تستهدف الإصدار 15 من نظام التشغيل Android (المستوى 35 لواجهة برمجة التطبيقات)، تصبح سمة 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 متطابقًا، على الرغم من أنّ هذه اللغات لها ارتفاعات سطور مختلفة عن بعضها.

بالنسبة إلى التطبيقات التي تستهدف الإصدار 15 من Android (المستوى 35 لواجهة برمجة التطبيقات)، تم الآن تخصيص الحد الأدنى لارتفاع السطر لـ EditText لمطابقة الخط المرجعي للّغة المحدّدة، كما هو موضح في الصورة التالية:

ثلاثة مربّعات تمثّل EditText عنصرًا يمكن أن يحتوي على نص باللغة الإنجليزية (en) واليابانية (ja) والبورمية (my). يتضمّن الآن ارتفاع الرمز EditText مساحة لاستيعاب ارتفاع السطر التلقائي لخطوط هذه اللغات.

يمكن لتطبيقك استعادة السلوك السابق إذا لزم الأمر من خلال تحديد سمة useLocalePreferredLineHeightForMinimum على false، ويمكن لتطبيقك ضبط الحد الأدنى المخصّص للمقاييس العمودية باستخدام واجهة برمجة التطبيقات setMinimumFontMetrics في Kotlin وJava.

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

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

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

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

يمكنك الاطّلاع على مزيد من المعلومات حول ميزة "تركيز الصوت" في مقالة إدارة ميزة "تركيز الصوت".

القيود المعدَّلة على واجهات برمجة التطبيقات غير الأساسية في حزمة تطوير البرامج (SDK)

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

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

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

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