التغييرات في السلوك: التطبيقات التي تستهدف الإصدار 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 (ما دام التطبيق يعمل على جهاز 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 权限,即使应用当前在后台运行,也可以启动前台服务(如免于后台启动限制中所述)。

如果应用以 Android 15 为目标平台,则此豁免范围现在更窄。现在,应用需要具有 SYSTEM_ALERT_WINDOW 权限,并且需要有一个可见的叠加窗口。也就是说,应用需要先启动 TYPE_APPLICATION_OVERLAY 窗口,并且该窗口需要处于可见状态,然后您才能启动前台服务。

如果您的应用尝试从后台启动前台服务,但不符合这些新要求(并且没有其他豁免情况),系统会抛出 ForegroundServiceStartNotAllowedException

如果您的应用声明了 SYSTEM_ALERT_WINDOW 权限并从后台启动前台服务,则可能会受到此变更的影响。如果您的应用获得了 ForegroundServiceStartNotAllowedException,请检查应用的操作顺序,并确保应用在尝试从后台启动前台服务之前已具有有效的叠加层窗口。您可以通过调用 View.getWindowVisibility() 检查叠加层窗口当前是否可见,也可以替换 View.onWindowVisibilityChanged(),以便在可见性发生变化时收到通知。

测试

如需测试应用的行为,您可以启用这些新限制,即使您的应用并未以 Android 15 为目标平台(只要应用在 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).

  • التغييرات على تسلسلات Intent العشوائية: بعد إجراء التغييرات في 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() تم طرحها في 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. إذا كنت تستخدم 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 تدابير أمان اختيارية جديدة لجعل النوايا أكثر أمانًا وفعالية. تهدف هذه التغييرات إلى منع الثغرات الأمنية المحتملة وإساءة استخدام النوايا التي يمكن للتطبيقات الضارة استغلالها. هناك نوعان من التحسينات الرئيسية على أمان النوايا في Android 15:

  • مطابقة فلاتر الأهداف المستهدَفة: يجب أن تتطابق الأهداف التي تستهدف مكوّنات معيّنة بدقة مع مواصفات فلاتر الأهداف المستهدَفة. إذا أرسلت نية لإطلاق نشاط تطبيق آخر، يجب أن يتوافق عنصر intent المستهدف مع فلاتر الأهداف المُعلَن عنها لنشاط التلقي.
  • يجب أن تتضمّن الأهداف إجراءات: لن تتطابق الأهداف التي لا تتضمّن إجراءً مع أي فلاتر أهداف. وهذا يعني أنّ النِيّات المستخدَمة لبدء الأنشطة أو الخدمات يجب أن تتضمّن إجراءً محدّدًا بوضوح.

للتحقّق من استجابة تطبيقك لهذه التغييرات، استخدِم StrictMode في تطبيقك. للاطّلاع على سجلّات detailed حول انتهاكات استخدام 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 يستخدم هذا التطبيق في الغالب مكونات Material 3 Compose التي تطبّق الأجزاء الداخلية تلقائيًا. لا تتأثر هذه الشاشة سلبًا بتطبيق ميزة "ملء الشاشة" في Android 15.

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

  • شريط التنقّل في عناصر التحكّم بالإيماءات
    • شفافة تلقائيًا
    • يتم إيقاف الإزاحة السفلية حتى يتم رسم المحتوى خلف شريط التنقّل في النظام ما لم يتم تطبيق المكوّنات المضمّنة.
    • تمّت إيقاف setNavigationBarColor وR.attr#navigationBarColor نهائيًا ولا يؤثّران في التنقّل بالإيماءات.
    • لن يؤثر كلّ من setNavigationBarContrastEnforced وR.attr#navigationBarContrastEnforced في التنقُّل بالإيماءات.
  • التنقّل باستخدام 3 أزرار
    • ويتم ضبط التعتيم على 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
تطبيق يستهدف Android 15 (المستوى 35 لواجهة برمجة التطبيقات) ويتوافق مع جميع الأجهزة التي تعمل بالإصدار 15 من نظام Android. ومع ذلك، يتم الآن إخفاء العديد من العناصر بواسطة شريط الحالة أو شريط التنقّل المكوّن من 3 أزرار أو مساحة الشاشة المخصّصة للكاميرا الأمامية بسبب إجراءات فرض الشاشة الممتدة بالكامل في 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.
  • إذا كان تطبيقك يستخدم طرق العرض و"المكوّنات المادية" (com.google.android.material)، ستتعامل معظم مكوّنات المواد المستندة إلى المشاهدات، مثل BottomNavigationView أو BottomAppBar أو NavigationRailView أو NavigationView، مع الأجزاء الداخلية ولا تتطلّب أي عمل إضافي. ومع ذلك، عليك إضافة android:fitsSystemWindows="true" في حال استخدام AppBarLayout.
  • بالنسبة إلى العناصر المخصّصة القابلة للتجميع، طبِّق الأجزاء المُدمجة يدويًا كحشو. إذا كان المحتوى ضمن Scaffold، يمكنك استخدام العناصر المضمّنة باستخدام Scaffold قيم الحشو. بخلاف ذلك، طبِّق الحشو باستخدام أحد الرمزَين التاليَين: WindowInsets.
  • إذا كان تطبيقك يستخدم طرق العرض وBottomSheet أو SideSheet أو الحاويات المخصّصة، يمكنك تطبيق الحشو باستخدام ViewCompat.setOnApplyWindowInsetsListener. بالنسبة إلى RecyclerView، يمكنك تطبيق الحشو باستخدام هذا المستمع وإضافة clipToPadding="false" أيضًا.
الخطوات التي يجب اتّباعها لمعرفة ما إذا كان يجب أن يقدّم تطبيقك حماية مخصّصة للعمل في الخلفية

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

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

اطّلِع على إرشادات المشاهدات من الحافة إلى الحافة وإنشاء المحتوى من الحافة إلى الحافة للاطّلاع على اعتبارات إضافية حول تطبيق الأجزاء المُدمَجة.

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

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

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

إذا كان تطبيقك يستهدف الإصدار 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 متطابقًا، على الرغم من اختلاف ارتفاع الأسطر عن هاتين اللغتَين.

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

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

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

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

يُجري نظام 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.