على غرار الإصدارات السابقة، يتضمّن Android 15 تغييرات في السلوك قد تؤثّر في تطبيقك. تنطبق تغييرات السلوك التالية حصريًا على التطبيقات التي تستهدف Android 15 أو الإصدارات الأحدث. إذا كان تطبيقك يستهدف Android 15 أو الإصدارات الأحدث، عليك تعديله ليتوافق مع هذه السلوكيات بشكلٍ صحيح، حيثما ينطبق ذلك.
احرص أيضًا على مراجعة قائمة تغييرات السلوك التي تؤثّر في جميع التطبيقات
التي تعمل على Android 15 بغض النظر عن targetSdkVersion في تطبيقك.
الوظيفة الأساسية
يعدّل Android 15 أو يوسّع إمكانات أساسية مختلفة في نظام Android.
تغييرات على الخدمات التي تعمل في المقدّمة
نحن بصدد إجراء التغييرات التالية على الخدمات التي تعمل في المقدّمة في Android 15.
- سلوك مهلة الخدمة التي تعمل في المقدّمة لمزامنة البيانات
- نوع الخدمة الجديدة التي تعمل في المقدّمة لمعالجة الوسائط
- القيود المفروضة على
BOOT_COMPLETEDمستقبلات البث التي تبدأ الخدمات التي تعمل في المقدّمة - قيود على بدء الخدمات التي تعمل في المقدّمة عندما يكون لدى التطبيق إذن
SYSTEM_ALERT_WINDOW
سلوك مهلة الخدمة التي تعمل في المقدّمة لمزامنة البيانات
Android 15 introduces a new timeout behavior to dataSync for apps targeting
Android 15 (API level 35) or higher. This behavior also applies to the new
mediaProcessing foreground service type.
The system permits an app's dataSync services to run for a total of 6 hours
in a 24-hour period, after which the system calls the running service's
Service.onTimeout(int, int) method (introduced in Android
15). At this time, the service has a few seconds to call
Service.stopSelf(). When Service.onTimeout() is called, the
service is no longer considered a foreground service. If the service does not
call Service.stopSelf(), the system throws an internal exception. The
exception is logged in Logcat with the following message:
Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type dataSync did not stop within its timeout: [component name]"
To avoid problems with this behavior change, you can do one or more of the following:
- Have your service implement the new
Service.onTimeout(int, int)method. When your app receives the callback, make sure to callstopSelf()within a few seconds. (If you don't stop the app right away, the system generates a failure.) - Make sure your app's
dataSyncservices don't run for more than a total of 6 hours in any 24-hour period (unless the user interacts with the app, resetting the timer). - Only start
dataSyncforeground services as a result of direct user interaction; since your app is in the foreground when the service starts, your service has the full six hours after the app goes to the background. - Instead of using a
dataSyncforeground service, use an alternative API.
If your app's dataSync foreground services have run for 6 hours in the last
24, you cannot start another dataSync foreground service unless the user
has brought your app to the foreground (which resets the timer). If you try to
start another dataSync foreground service, the system throws
ForegroundServiceStartNotAllowedException
with an error message like "Time limit already exhausted for foreground service
type dataSync".
Testing
To test your app's behavior, you can enable data sync timeouts even if your app
is not targeting Android 15 (as long as the app is running on an Android 15
device). To enable timeouts, run the following adb command:
adb shell am compat enable FGS_INTRODUCE_TIME_LIMITS your-package-name
You can also adjust the timeout period, to make it easier to test how your
app behaves when the limit is reached. To set a new timeout period, run the
following adb command:
adb shell device_config put activity_manager data_sync_fgs_timeout_duration duration-in-milliseconds
نوع الخدمة الجديدة التي تعمل في المقدّمة لمعالجة الوسائط
Android 15 introduces a new foreground service type, mediaProcessing. This
service type is appropriate for operations like transcoding media files. For
example, a media app might download an audio file and need to convert it to a
different format before playing it. You can use a mediaProcessing foreground
service to make sure the conversion continues even while the app is in the
background.
The system permits an app's mediaProcessing services to run for a total of 6
hours in a 24-hour period, after which the system calls the running service's
Service.onTimeout(int, int) method (introduced in Android
15). At this time, the service has a few seconds to call
Service.stopSelf(). If the service does not
call Service.stopSelf(), the system throws an internal exception. The
exception is logged in Logcat with the following message:
Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type mediaProcessing did not stop within its timeout: [component name]"
To avoid having the exception, you can do one of the following:
- Have your service implement the new
Service.onTimeout(int, int)method. When your app receives the callback, make sure to callstopSelf()within a few seconds. (If you don't stop the app right away, the system generates a failure.) - Make sure your app's
mediaProcessingservices don't run for more than a total of 6 hours in any 24-hour period (unless the user interacts with the app, resetting the timer). - Only start
mediaProcessingforeground services as a result of direct user interaction; since your app is in the foreground when the service starts, your service has the full six hours after the app goes to the background. - Instead of using a
mediaProcessingforeground service, use an alternative API, like WorkManager.
If your app's mediaProcessing foreground services have run for 6 hours in the
last 24, you cannot start another mediaProcessing foreground service unless
the user has brought your app to the foreground (which resets the timer). If you
try to start another mediaProcessing foreground service, the system throws
ForegroundServiceStartNotAllowedException
with an error message like "Time limit already exhausted for foreground service
type mediaProcessing".
For more information about the mediaProcessing service type, see Changes to
foreground service types for Android 15: Media processing.
Testing
To test your app's behavior, you can enable media processing timeouts even if
your app is not targeting Android 15 (as long as the app is running on an
Android 15 device). To enable timeouts, run the following adb command:
adb shell am compat enable FGS_INTRODUCE_TIME_LIMITS your-package-name
You can also adjust the timeout period, to make it easier to test how your
app behaves when the limit is reached. To set a new timeout period, run the
following adb command:
adb shell device_config put activity_manager media_processing_fgs_timeout_duration duration-in-milliseconds
القيود المفروضة على تطبيقات BOOT_COMPLETED التي تستخدم مستقبلات البث لتشغيل الخدمات التي تعمل في المقدّمة
There are new restrictions on BOOT_COMPLETED broadcast receivers launching
foreground services. BOOT_COMPLETED receivers are not allowed to launch the
following types of foreground services:
dataSynccameramediaPlaybackphoneCallmediaProjectionmicrophone(this restriction has been in place formicrophonesince Android 14)
If a BOOT_COMPLETED receiver tries to launch any of those types of foreground
services, the system throws ForegroundServiceStartNotAllowedException.
Testing
To test your app's behavior, you can enable these new restrictions even if your
app is not targeting Android 15 (as long as the app is running on an Android 15
device). Run the following adb command:
adb shell am compat enable FGS_BOOT_COMPLETED_RESTRICTIONS your-package-name
To send a BOOT_COMPLETED broadcast without restarting the device,
run the following adb command:
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
تغييرات على الحالات التي يمكن فيها للتطبيقات تعديل الحالة العامة لوضع "عدم الإزعاج"
Apps that target Android 15 (API level 35) and higher can no longer change the
global state or policy of Do Not Disturb (DND) on a device (either by modifying
user settings, or turning off DND mode). Instead, apps must contribute an
AutomaticZenRule, which the system combines into a global policy with the
existing most-restrictive-policy-wins scheme. Calls to existing APIs that
previously affected global state (setInterruptionFilter,
setNotificationPolicy) result in the creation or update of an implicit
AutomaticZenRule, which is toggled on and off depending on the call-cycle of
those API calls.
Note that this change only affects observable behavior if the app is calling
setInterruptionFilter(INTERRUPTION_FILTER_ALL) and expects that call to
deactivate an AutomaticZenRule that was previously activated by their owners.
تغييرات على واجهة برمجة تطبيقات OpenJDK
Android 15 将继续更新 Android 的核心库,以与最新 OpenJDK LTS 版本中的功能保持一致。
以下变更可能会影响以 Android 15(API 级别 35)为目标平台的应用的兼容性:
对字符串格式化 API 进行了更改:现在,当使用以下
String.format()和Formatter.format()API 时,对参数索引、标志、 宽度和精度的验证要求变得更加严格:String.format(String, Object[])String.format(Locale, String, Object[])Formatter.format(String, Object[])Formatter.format(Locale, String, Object[])
例如,当使用实参索引 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]);对语言代码处理进行了更改:使用
LocaleAPI 时, 希伯来语、意第绪语和印度尼西亚语的语言代码不再转换为 其过时形式(希伯来语:iw,意第绪语:ji,印度尼西亚语:in)。 指定其中一种语言区域的语言代码时,请改用 ISO 639-1 中的代码 (希伯来语:he,意第绪语:yi,印度尼西亚语:id)。对随机 int 序列进行了更改:根据 https://bugs.openjdk.org/browse/JDK-8301574 中所做的更改,以下
Random.ints()方法现在返回的数字序列与 theRandom.nextInt()方法返回的数字序列不同:一般来说,此更改不应导致应用出现破坏性行为,但您的代码不应期望从
Random.ints()方法生成的序列与Random.nextInt()匹配。
新的 SequencedCollection API 可能会影响应用的兼容性
在应用的 build 配置中
更新 以使用
Android 15(API 级别 35)后:compileSdk
与
MutableList.removeFirst()和MutableList.removeLast()扩展函数在kotlin-stdlib中发生冲突Java 中的
List类型映射到 Kotlin 中的MutableList类型。 由于List.removeFirst()和List.removeLast()API 是在 Android 15(API 级别 35)中引入的,因此 Kotlin 编译器 会将函数调用(例如list.removeFirst())静态解析为 新的ListAPI,而不是kotlin-stdlib中的扩展函数。如果使用
compileSdk设置为35且minSdk设置为34或更低版本重新编译应用,然后在 Android 14 及更低版本上运行该应用,则会抛出运行时错误:java.lang.NoSuchMethodError: No virtual method removeFirst()Ljava/lang/Object; in class Ljava/util/ArrayList;Android Gradle 插件中现有的
NewApilint 选项可以捕获这些新的 API 用法。./gradlew lintMainActivity.kt:41: Error: Call requires API level 35 (current min is 34): java.util.List#removeFirst [NewApi] list.removeFirst()如需修复运行时异常和 lint 错误,可以将
removeFirst()和removeLast()函数调用分别替换为 Kotlin 中的removeAt(0)和removeAt(list.lastIndex)。如果您使用的是 Android Studio Ladybug | 2024.1.3 或更高版本,它还为这些错误提供了快速修复选项。如果 lint 选项已停用,请考虑移除
@SuppressLint("NewApi")和lintOptions { disable 'NewApi' }。与 Java 中的其他方法发生冲突
新的方法已添加到现有类型中,例如,
List和Deque。这些新方法可能与其他接口和类中具有相同名称和实参类型的方法不兼容。如果方法签名冲突且不兼容,javac编译器会输出 build 时错误。例如:错误示例 1:
javac MyList.javaMyList.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.javaMyList.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.javaMyList.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如需修复这些 build 错误,实现这些接口的类应使用兼容的返回值类型替换该方法。例如:
@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 introduces StrictMode for
intents.
In order to see detailed logs about Intent usage violations, use following
method:
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 إذا كان التطبيق يستهدف الإصدار 15 من نظام التشغيل Android (المستوى 35 لواجهة برمجة التطبيقات).
هذا تغيير غير متوافق قد يؤثر سلبًا في واجهة مستخدم تطبيقك. تؤثّر التغييرات في أقسام واجهة المستخدم التالية:
- شريط التنقّل باستخدام مقبض الإيماءات
- تكون شفافة تلقائيًا.
- تم إيقاف الإزاحة السفلية كي يتم عرض المحتوى خلف شريط التنقّل في النظام ما لم يتم تطبيق هوامش داخلية.
- تم إيقاف
setNavigationBarColorوR.attr#navigationBarColorنهائيًا، ولا يؤثران في التنقّل بالإيماءات. - لن يكون
setNavigationBarContrastEnforcedوR.attr#navigationBarContrastEnforcedأي تأثير على التنقّل بالإيماءات.
- التنقّل باستخدام ثلاثة أزرار
- يتم ضبط مستوى الشفافية على% 80 تلقائيًا، وقد يتطابق اللون مع لون خلفية النافذة.
- تم إيقاف الإزاحة السفلية كي يتم عرض المحتوى خلف شريط التنقّل في النظام ما لم يتم تطبيق الحواف الداخلية.
- يتم ضبط
setNavigationBarColorوR.attr#navigationBarColorتلقائيًا ليتطابقا مع خلفية النافذة. يجب أن تكون خلفية النافذة قابلة للرسم بلون حتى يتم تطبيق هذا الإعداد التلقائي. تم إيقاف هذه الواجهة نهائيًا، ولكنها لا تزال تؤثر في التنقّل باستخدام ثلاثة أزرار. - تكون قيمة
setNavigationBarContrastEnforcedوR.attr#navigationBarContrastEnforcedصحيحة تلقائيًا، ما يؤدي إلى إضافة خلفية غير شفافة بنسبة% 80 في وضع "التنقّل باستخدام ثلاثة أزرار".
- شريط الحالة
- تكون شفافة تلقائيًا.
- يتم إيقاف الإزاحة العلوية، وبالتالي يتم عرض المحتوى خلف شريط الحالة ما لم يتم تطبيق هوامش داخلية.
- تم إيقاف
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)، وقبل وبعد تطبيق المساحات الداخلية. هذا المثال ليس شاملاً، وقد يظهر بشكل مختلف على Android Auto.
ما يجب التحقّق منه إذا كان تطبيقك معروضًا من الحافة إلى الحافة
إذا كان تطبيقك يعرض المحتوى من الحافة إلى الحافة ويطبّق هوامش داخلية، لن تتأثر في معظم الحالات، باستثناء السيناريوهات التالية. ومع ذلك، حتى إذا كنت تعتقد أنّك لن تتأثر بهذا التغيير، ننصحك باختبار تطبيقك.
- لديك نافذة غير عائمة، مثل
ActivityتستخدمSHORT_EDGESأوNEVERأوDEFAULTبدلاً منLAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS. إذا كان تطبيقك يتعطّل عند تشغيله، قد يكون ذلك بسبب شاشة البداية. يمكنك إما ترقية تبعية شاشة البداية الأساسية إلى الإصدار 1.2.0-alpha01 أو إصدار أحدث، أو ضبطwindow.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutInDisplayCutoutMode.always. - قد تكون هناك شاشات ذات عدد زيارات أقل مع واجهة مستخدم محجوبة. تأكَّد من أنّ الشاشات الأقل زيارة لا تتضمّن واجهة مستخدم محجوبة. تشمل الشاشات التي تسجّل عددًا أقل من الزيارات ما يلي:
- شاشات الإعداد أو تسجيل الدخول
- صفحات الإعدادات
الإجراءات التي يجب اتّخاذها إذا لم يكن تطبيقك معروضًا من الحافة إلى الحافة
إذا لم يكن تطبيقك معروضًا من الحافة إلى الحافة، من المرجّح أن تتأثّر بذلك. بالإضافة إلى سيناريوهات التطبيقات التي تعرض المحتوى من الحافة إلى الحافة، يجب مراعاة ما يلي:
- إذا كان تطبيقك يستخدم "مكوّنات Material 3" (
androidx.compose.material3) في Compose، مثلTopAppBarوBottomAppBarوNavigationBar، من المحتمل ألا تتأثر هذه المكوّنات لأنّها تتعامل تلقائيًا مع الهوامش الداخلية. - إذا كان تطبيقك يستخدم مكوّنات Material 2 (
androidx.compose.material) في Compose، لن تتعامل هذه المكوّنات تلقائيًا مع الحواف الداخلية. ومع ذلك، يمكنك الوصول إلى الحواف الداخلية وتطبيقها يدويًا. في androidx.compose.material الإصدار 1.6.0 والإصدارات الأحدث، استخدِم المَعلمةwindowInsetsلتطبيق الهوامش الداخلية يدويًا علىBottomAppBarوTopAppBarوBottomNavigationوNavigationRail. وبالمثل، استخدِم المَعلمةcontentWindowInsetsمعScaffold. - إذا كان تطبيقك يستخدم طرق العرض ومكوّنات Material
(
com.google.android.material)، فإنّ معظم مكوّنات Material المستندة إلى طرق العرض، مثلBottomNavigationViewأوBottomAppBarأوNavigationRailViewأوNavigationView، تتعامل مع الحواف الداخلية ولا تتطلّب أي عمل إضافي. ومع ذلك، عليك إضافةandroid:fitsSystemWindows="true"إذا كنت تستخدمAppBarLayout. - بالنسبة إلى العناصر القابلة للإنشاء المخصّصة، طبِّق عمليات الإزاحة يدويًا كمسافة بادئة. إذا كان المحتوى الخاص بك ضمن
Scaffold، يمكنك استخدام الحواف الداخلية باستخدام قيم المساحة المتروكةScaffold. بخلاف ذلك، طبِّق الحشو باستخدام أحدWindowInsets. - إذا كان تطبيقك يستخدم طرق العرض و
BottomSheetأوSideSheetأو حاويات مخصّصة، طبِّق مساحة متروكة باستخدامViewCompat.setOnApplyWindowInsetsListener. بالنسبة إلىRecyclerView، طبِّق المساحة المتروكة باستخدام أداة معالجة الأحداث هذه، وأضِف أيضًاclipToPadding="false".
ما يجب التحقّق منه إذا كان تطبيقك يجب أن يوفّر حماية مخصّصة تعمل في الخلفية
إذا كان تطبيقك يوفّر حماية مخصّصة في الخلفية للتنقُّل باستخدام ثلاثة أزرار أو شريط الحالة، يجب أن يضع تطبيقك عنصرًا قابلاً للإنشاء أو عرضًا خلف شريط النظام باستخدام WindowInsets.Type#tappableElement() للحصول على ارتفاع شريط التنقّل الذي يتضمّن 3 أزرار أو WindowInsets.Type#statusBars.
مراجع إضافية حول ميزة "من الحافة إلى الحافة"
راجِع الدليلَين طرق العرض من الحافة إلى الحافة وCompose من الحافة إلى الحافة للاطّلاع على اعتبارات إضافية بشأن تطبيق الحواف الداخلية.
واجهات برمجة التطبيقات المتوقّفة نهائيًا
تم إيقاف واجهات برمجة التطبيقات التالية نهائيًا ولكن لم يتم إيقافها:
R.attr#enforceStatusBarContrastR.attr#navigationBarColor(للتنقّل باستخدام ثلاثة أزرار، مع 80% قيمة ألفا)Window#isStatusBarContrastEnforcedWindow#setNavigationBarColor(للتنقّل باستخدام ثلاثة أزرار، مع قيمة ألفا بنسبة% 80)Window#setStatusBarContrastEnforced
تم إيقاف واجهات برمجة التطبيقات التالية:
R.attr#navigationBarColor(للتنقّل بالإيماءات)R.attr#navigationBarDividerColorR.attr#statusBarColorWindow#setDecorFitsSystemWindowsWindow#getNavigationBarColorWindow#getNavigationBarDividerColorWindow#getStatusBarColorWindow#setNavigationBarColor(للتنقّل بالإيماءات)Window#setNavigationBarDividerColorWindow#setStatusBarColor
稳定配置
如果您的应用以 Android 15(API 级别 35)或更高版本为目标平台,Configuration 不再排除系统栏。如果您在 Configuration 类中使用屏幕尺寸进行布局计算,则应根据需要将其替换为更好的替代方案,例如适当的 ViewGroup、WindowInsets 或 WindowMetricsCalculator。
Configuration 自 API 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更改的影响。此方法已从 API 级别 30 开始被弃用。- 自 API 级别 33 起,
Display.getMetrics()的运作方式已是如此。
القيمة التلقائية للسمة 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 确定宽度的方式,因此如果应用以 Android 15(API 级别 35)或更高版本为目标平台,TextView 会默认分配更多宽度。您可以通过对 TextView 调用 setUseBoundsForWidth API 来启用或停用此行为。
由于添加左内边距可能会导致现有布局未对齐,因此默认情况下不会添加内边距,即使以 Android 15 或更高版本为目标平台的应用也是如此。不过,您可以通过调用 setShiftDrawingOffsetForStartOverhang 添加额外的内边距以防止剪裁。
以下示例展示了这些更改如何改进某些字体和语言的文本布局。
<TextView android:fontFamily="cursive" android:text="java" />
<TextView android:fontFamily="cursive" android:text="java" android:useBoundsForWidth="true" android:shiftDrawingOffsetForStartOverhang="true" />
<TextView android:text="คอมพิวเตอร์" />
<TextView android:text="คอมพิวเตอร์" android:useBoundsForWidth="true" android:shiftDrawingOffsetForStartOverhang="true" />
ارتفاع السطر التلقائي الذي يراعي اللغة في EditText
在较低版本的 Android 中,文本布局会拉伸文本的高度,以满足与当前语言区域匹配的字体的行高。例如,如果内容是日语,由于日语字体的行高略高于拉丁字体,因此文本的高度会略高。不过,尽管行高存在这些差异,但无论使用的是哪种语言区域,EditText 元素的大小都是统一的,如下图所示:
EditText 元素。EditText 的高度相同,即使这些语言的行高各不相同。对于以 Android 15(API 级别 35)为目标平台的应用,现在为 EditText 预留了最小行高,以匹配指定语言区域的参考字体,如下图所示:
EditText 元素。EditText 的高度现在包含足够的空间来容纳这些语言字体的默认行高。如有需要,您的应用可以将 useLocalePreferredLineHeightForMinimum 属性指定为 false,以恢复之前的行为;您的应用还可以在 Kotlin 和 Java 中使用 setMinimumFontMetrics API 设置自定义最小垂直指标。
الكاميرا والوسائط
يُجري Android 15 التغييرات التالية على سلوك الكاميرا والوسائط للتطبيقات التي تستهدف Android 15 أو الإصدارات الأحدث.
القيود المفروضة على طلب أولويّة الصوت
Apps that target Android 15 (API level 35) must be the top app or running a
foreground service in order to request audio focus. If an app
attempts to request focus when it does not meet one of these requirements, the
call returns AUDIOFOCUS_REQUEST_FAILED.
You can learn more about audio focus at Manage audio focus.
القيود المعدَّلة على واجهات برمجة التطبيقات غير الأساسية في حزمة تطوير البرامج (SDK)
يتضمّن Android 15 قوائم معدَّلة لواجهات برمجة التطبيقات غير المتوفّرة في حزمة SDK والمقيّدة، استنادًا إلى التعاون مع مطوّري Android وأحدث الاختبارات الداخلية. نحرص قدر الإمكان على توفير بدائل عامة قبل تقييد واجهات برمجة التطبيقات غير المتوفّرة في حزمة SDK.
إذا كان تطبيقك لا يستهدف Android 15، قد لا تؤثّر بعض هذه التغييرات فيك على الفور. ومع ذلك، على الرغم من إمكانية وصول تطبيقك إلى بعض واجهات برمجة التطبيقات غير المتوفّرة في حزمة SDK استنادًا إلى مستوى واجهة برمجة التطبيقات المستهدَف في تطبيقك، فإنّ استخدام أي طريقة أو حقل غير متوفّر في حزمة SDK يحمل دائمًا خطرًا كبيرًا بتعطُّل تطبيقك.
إذا لم تكن متأكدًا مما إذا كان تطبيقك يستخدم واجهات برمجة تطبيقات غير متوفّرة في حزمة SDK، يمكنك اختباره لمعرفة ذلك. إذا كان تطبيقك يعتمد على واجهات برمجة تطبيقات غير متوفّرة في حزمة SDK، عليك البدء في التخطيط لنقل البيانات إلى بدائل حزمة SDK. ومع ذلك، ندرك أنّ بعض التطبيقات لديها حالات استخدام صالحة لاستخدام واجهات برمجة تطبيقات غير متوفّرة في حزمة SDK. إذا لم تتمكّن من العثور على بديل لاستخدام واجهة برمجة تطبيقات غير متوفّرة في حزمة SDK لميزة في تطبيقك، عليك طلب واجهة برمجة تطبيقات عامة جديدة.
To learn more about the changes in this release of Android, see Updates to non-SDK interface restrictions in Android 15. To learn more about non-SDK interfaces generally, see Restrictions on non-SDK interfaces.