تغییرات رفتار: برنامه هایی که اندروید 15 یا بالاتر را هدف قرار می دهند

مانند نسخه‌های قبلی، اندروید ۱۵ شامل تغییرات رفتاری است که ممکن است بر برنامه شما تأثیر بگذارد. تغییرات رفتاری زیر منحصراً برای برنامه‌هایی اعمال می‌شود که اندروید ۱۵ یا بالاتر را هدف قرار می‌دهند. اگر برنامه شما اندروید ۱۵ یا بالاتر را هدف قرار می‌دهد، باید برنامه خود را اصلاح کنید تا در صورت لزوم، از این رفتارها به درستی پشتیبانی کند.

حتماً فهرست تغییرات رفتاری که صرف نظر از targetSdkVersion برنامه شما، بر همه برنامه‌های در حال اجرا در اندروید ۱۵ تأثیر می‌گذارند را نیز بررسی کنید.

عملکرد اصلی

اندروید ۱۵ قابلیت‌های اصلی مختلف سیستم اندروید را تغییر داده یا گسترش می‌دهد.

تغییرات در سرویس‌های پیش‌زمینه

ما در حال انجام تغییرات زیر در سرویس های پیش زمینه با اندروید 15 هستیم.

رفتار درنگ سرویس پیش زمینه همگام سازی داده ها

Android 15 برای برنامه‌هایی که Android 15 (سطح API 35) یا بالاتر را هدف قرار می‌دهند، رفتار مهلت زمانی جدیدی را برای dataSync معرفی می‌کند. این رفتار همچنین برای نوع جدید سرویس پیش‌زمینه mediaProcessing اعمال می‌شود.

این سیستم به سرویس‌های dataSync یک برنامه اجازه می‌دهد در یک دوره 24 ساعته در مجموع 6 ساعت اجرا شوند، پس از آن سیستم سرویس سرویس در حال اجرا را متد Service.onTimeout(int, int) (معرفی شده در اندروید 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 برنامه شما در هر دوره 24 ساعته در مجموع بیش از 6 ساعت اجرا نمی‌شوند (مگر اینکه کاربر با برنامه تعامل داشته باشد و تایمر را بازنشانی کند).
  3. خدمات پیش زمینه dataSync فقط در نتیجه تعامل مستقیم کاربر شروع کنید. از آنجایی که برنامه شما هنگام شروع سرویس در پیش زمینه است، سرویس شما شش ساعت کامل پس از رفتن برنامه به پس‌زمینه است.
  4. به جای استفاده از سرویس پیش زمینه dataSync ، از یک API جایگزین استفاده کنید.

اگر سرویس‌های پیش‌زمینه dataSync برنامه شما در 24 ساعت گذشته به مدت 6 ساعت اجرا شده است، نمی‌توانید سرویس پیش‌زمینه dataSync دیگری را راه‌اندازی کنید مگر اینکه کاربر برنامه شما را به پیش‌زمینه آورده باشد (که تایمر را بازنشانی می‌کند). اگر می‌خواهید سرویس پیش‌زمینه dataSync دیگری را راه‌اندازی کنید، سیستم ForegroundServiceStartNotAllowedException را با یک پیام خطایی مانند «محدودیت زمانی برای نوع سرویس پیش‌زمینه dataSync تمام شده است» پرتاب می‌کند.

تست کردن

برای آزمایش رفتار برنامه‌تان، می‌توانید وقفه‌های همگام‌سازی داده‌ها را فعال کنید، حتی اگر برنامه شما Android 15 را هدف قرار ندهد (تا زمانی که برنامه روی دستگاه 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 服务在 24 小时内总共运行 6 小时,之后系统会调用正在运行的服务的 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 服务在任何 24 小时内总运行时间不超过 6 小时(除非用户与应用互动,重置计时器)。
  3. 仅在有直接用户互动时启动 mediaProcessing 前台服务;由于服务启动时应用位于前台,因此您的服务在应用进入后台后有完整的 6 小时时间。
  4. 请改用 替代 API(例如 WorkManager),而不是使用 mediaProcessing 前台服务。

如果您的应用的 mediaProcessing 前台服务在过去 24 小时内运行了 6 小时,则您无法启动其他 mediaProcessing 前台服务,除非用户将您的应用切换到前台(这会重置计时器)。如果您尝试启动另一个 mediaProcessing 前台服务,系统会抛出 ForegroundServiceStartNotAllowedException,并显示类似于“前台服务类型 mediaProcessing 的时间限制已用尽”的错误消息。

如需详细了解 mediaProcessing 服务类型,请参阅 Android 15 前台服务类型变更:媒体处理

测试

如需测试应用的行为,您可以启用媒体处理超时,即使您的应用并非以 Android 15 为目标平台也是如此(前提是应用在 Android 15 设备上运行)。如需启用超时,请运行以下 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 اجرا شود). دستور 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 را هدف قرار دهد، این معافیت اکنون محدودتر شده است. اکنون برنامه باید مجوز SYSTEM_ALERT_WINDOW را داشته باشد و همچنین یک پنجره همپوشانی قابل مشاهده داشته باشد. یعنی برنامه باید ابتدا یک پنجره TYPE_APPLICATION_OVERLAY راه اندازی کند و قبل از شروع سرویس پیش زمینه باید پنجره قابل مشاهده باشد.

اگر برنامه شما سعی کند یک سرویس پیش‌زمینه را از پس‌زمینه راه‌اندازی کند، بدون اینکه این الزامات جدید را برآورده کند (و معافیت دیگری ندارد)، سیستم ForegroundServiceStartNotAllowedException را پرتاب می‌کند.

اگر برنامه شما مجوز SYSTEM_ALERT_WINDOW را اعلام کند و خدمات پیش‌زمینه را از پس‌زمینه راه‌اندازی کند، ممکن است تحت تأثیر این تغییر قرار گیرد. اگر برنامه شما یک ForegroundServiceStartNotAllowedException دریافت می کند، ترتیب عملکرد برنامه خود را بررسی کنید و مطمئن شوید که برنامه شما قبلاً یک پنجره همپوشانی فعال دارد قبل از اینکه بخواهد یک سرویس پیش زمینه را از پس زمینه راه اندازی کند. می‌توانید با فراخوانی View.getWindowVisibility() بررسی کنید که آیا پنجره همپوشانی شما قابل مشاهده است یا خیر، یا می‌توانید View.onWindowVisibilityChanged() را لغو کنید تا هر زمان که قابلیت مشاهده تغییر کرد مطلع شوید.

تست کردن

برای آزمایش رفتار برنامه‌تان، می‌توانید این محدودیت‌های جدید را فعال کنید، حتی اگر برنامه شما اندروید 15 را هدف قرار ندهد (تا زمانی که برنامه روی دستگاه Android 15 اجرا شود). برای فعال کردن این محدودیت‌های جدید برای شروع خدمات پیش‌زمینه از پس‌زمینه، دستور adb زیر را اجرا کنید:

adb shell am compat enable FGS_SAW_RESTRICTIONS your-package-name

تغییراتی در زمان‌هایی که برنامه‌ها می‌توانند وضعیت کلی حالت «مزاحم نشوید» را تغییر دهند

以 Android 15(API 级别 35)及更高版本为目标平台的应用无法再更改设备上的勿扰 (DND) 功能的全局状态或政策(无论是通过修改用户设置还是关闭勿扰模式)。相反,应用必须提供 AutomaticZenRule,系统会将其与现有的“最严格的政策优先”方案合并为一个全局政策。对之前会影响全局状态的现有 API 的调用(setInterruptionFiltersetNotificationPolicy)会导致创建或更新隐式 AutomaticZenRule,该 AutomaticZenRule 会根据这些 API 调用的调用周期开启和关闭。

请注意,只有当应用调用 setInterruptionFilter(INTERRUPTION_FILTER_ALL) 并希望该调用停用之前由其所有者激活的 AutomaticZenRule 时,此更改才会影响可观察到的行为。

تغییرات API در OpenJDK

اندروید ۱۵ همچنان به به‌روزرسانی کتابخانه‌های اصلی اندروید ادامه می‌دهد تا با ویژگی‌های جدیدترین نسخه‌های OpenJDK LTS هماهنگ شود.

برخی از این تغییرات می‌توانند بر سازگاری برنامه‌ها برای اندروید ۱۵ (سطح API ۳۵) تأثیر بگذارند:

  • تغییرات در APIهای قالب‌بندی رشته : اعتبارسنجی اندیس آرگومان، پرچم‌ها، عرض و دقت، اکنون هنگام استفاده از APIهای String.format() و Formatter.format() زیر، سختگیرانه‌تر شده است:

    برای مثال، وقتی از اندیس آرگومان ۰ استفاده می‌شود ( %0 در رشته فرمت)، خطای زیر رخ می‌دهد:

    IllegalFormatArgumentIndexException: Illegal format argument index = 0
    

    در این حالت، مشکل را می‌توان با استفاده از اندیس آرگومان ۱ ( %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]);
    
  • تغییرات در مدیریت کد زبان : هنگام استفاده از API 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() مطابقت داشته باشد.

API جدید SequencedCollection می‌تواند پس از به‌روزرسانی compileSdk در پیکربندی ساخت برنامه برای استفاده از اندروید ۱۵ (سطح API ۳۵)، بر سازگاری برنامه شما تأثیر بگذارد:

  • برخورد با توابع الحاقی MutableList.removeFirst() و MutableList.removeLast() در kotlin-stdlib

    نوع List در جاوا به نوع MutableList در کاتلین نگاشت شده است. از آنجا که APIهای List.removeFirst() و List.removeLast() در اندروید ۱۵ (سطح API ۳۵) معرفی شده‌اند، کامپایلر کاتلین فراخوانی‌های تابع، برای مثال list.removeFirst() ، را به صورت ایستا به APIهای List جدید به جای توابع افزونه در kotlin-stdlib حل می‌کند.

    اگر یک برنامه با compileSdk تنظیم شده روی 35 و minSdk تنظیم شده روی 34 یا پایین‌تر، دوباره کامپایل شود و سپس برنامه روی اندروید ۱۴ و پایین‌تر اجرا شود، یک خطای زمان اجرا رخ می‌دهد:

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

    گزینه‌ی NewApi lint موجود در افزونه‌ی Gradle اندروید می‌تواند این کاربردهای جدید API را دریافت کند.

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

    برای رفع خطاهای runtime exception و lint، فراخوانی‌های تابع removeFirst() و removeLast() را می‌توان به ترتیب با removeAt(0) و removeAt(list.lastIndex) در کاتلین جایگزین کرد. اگر از Android Studio Ladybug | 2024.1.3 یا بالاتر استفاده می‌کنید، این نسخه همچنین یک گزینه رفع سریع برای این خطاها ارائه می‌دهد.

    اگر گزینه lint غیرفعال شده است، حذف @SuppressLint("NewApi") و lintOptions { disable 'NewApi' } را در نظر بگیرید.

  • برخورد با متدهای دیگر در جاوا

    متدهای جدیدی به انواع موجود اضافه شده‌اند، برای مثال، List و Deque . این متدهای جدید ممکن است با متدهایی با نام و نوع آرگومان مشابه در رابط‌ها و کلاس‌های دیگر سازگار نباشند. در صورت برخورد امضای متد با ناسازگاری، کامپایلر javac خطای زمان ساخت را صادر می‌کند. برای مثال:

    مثال خطای ۱:

    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
    

    مثال خطای ۲:

    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
    

    مثال خطای ۳:

    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();
    }
    

امنیت

اندروید ۱۵ شامل تغییراتی است که امنیت سیستم را ارتقا می‌دهد تا به محافظت از برنامه‌ها و کاربران در برابر برنامه‌های مخرب کمک کند.

نسخه‌های محدود TLS

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

فعالیت پس‌زمینه امن راه‌اندازی می‌شود

Android 15 做出了一些变更,可防止恶意后台应用将其他应用置于前台、提升自身权限并滥用用户互动,从而保护用户免受恶意应用的侵害,并让用户更好地控制自己的设备。自 Android 10(API 级别 29)起,后台 activity 启动受到限制。

其他更改

  • PendingIntent 创建者更改为默认阻止后台活动启动。这有助于防止应用意外创建可能被恶意行为者滥用的 PendingIntent
  • 除非 PendingIntent 发送方允许,否则请勿将应用转至前台。此变更旨在防止恶意应用滥用在后台启动 activity 的功能。默认情况下,除非创建者允许后台 activity 启动权限或发送者具有后台 activity 启动权限,否则不允许应用将任务堆栈带到前台。
  • 控制任务堆栈的顶层 activity 如何完成其任务。如果顶部 activity 完成了一项任务,Android 将返回到上次处于活跃状态的任务。此外,如果非顶部 activity 完成其任务,Android 会返回到主屏幕;它不会阻止此非顶部 activity 完成。
  • 防止从其他应用启动任意 activity 进入您自己的任务。此变更可防止恶意应用通过创建看似来自其他应用的 activity 来对用户进行钓鱼式攻击。
  • 阻止将非可见窗口纳入后台 activity 启动的考虑范围。这有助于防止恶意应用滥用后台活动启动来向用户显示不必要或恶意的内容。

مقاصد امن‌تر

اندروید ۱۵ StrictMode برای intentها معرفی می‌کند.

برای مشاهده گزارش‌های دقیق در مورد تخلفات استفاده Intent ، از روش زیر استفاده کنید:

کاتلین

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

جاوا

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

تجربه کاربری و رابط کاربری سیستم

اندروید ۱۵ شامل تغییراتی است که برای ایجاد یک تجربه کاربری سازگارتر و شهودی‌تر در نظر گرفته شده‌اند.

تغییرات درج پنجره

در اندروید 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)都会处理边衬区,因此不需要执行额外的操作。不过,如果使用的是 AppBarLayout,则需要添加 android:fitsSystemWindows="true"
  • 对于自定义可组合项,请手动应用边衬区作为内边距。如果您的内容位于 Scaffold 中,则可以使用 Scaffold 内边距值来使用边衬区。否则,请使用 WindowInsets 之一应用内边距。
  • 如果应用使用的是视图和 BottomSheetSideSheet 或自定义容器,请使用 ViewCompat.setOnApplyWindowInsetsListener 应用内边距。对于 RecyclerView,请使用此监听器应用内边距,同时添加 clipToPadding="false"
如果应用必须提供自定义后台保护,您需要检查哪些方面

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

其他全屏显示资源

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

已弃用的 API

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

以下 API 已弃用并停用:

稳定配置

如果您的应用以 Android 15(API 级别 35)或更高版本为目标平台,Configuration 不再排除系统栏。如果您在 Configuration 类中使用屏幕尺寸进行布局计算,则应根据需要将其替换为更好的替代方案,例如适当的 ViewGroupWindowInsetsWindowMetricsCalculator

Configuration 自 API 1 起便已开始提供。通常从 Activity.onConfigurationChanged 获取。它提供窗口密度、方向和大小等信息。从 Configuration 返回的窗口大小的一个重要特征是,它之前不包括系统栏。

配置大小通常用于资源选择(例如 /res/layout-h500dp),这仍然是一个有效的使用情形。不过,我们一直不建议使用它进行布局计算。如果您正在这样做,请立即远离该设备。您应根据自己的使用场景,将 Configuration 的使用替换为更合适的用法。

如果您使用它来计算布局,请使用适当的 ViewGroup,例如 CoordinatorLayoutConstraintLayout。如果您使用它来确定系统导航栏的高度,请使用 WindowInsets。如果您想知道应用窗口的当前大小,请使用 computeCurrentWindowMetrics

以下列表介绍了受此变更影响的字段:

مقدار پیش‌فرض ویژگی elegantTextHeight برابر با true است.

برای برنامه‌هایی که Android 15 (سطح API 35) را هدف قرار می‌دهند، ویژگی elegantTextHeight TextView به‌طور پیش‌فرض true می‌شود و فونت فشرده‌ای را که به‌طور پیش‌فرض استفاده می‌شود با برخی از اسکریپت‌هایی که معیارهای عمودی بزرگی دارند با فونتی که بسیار خواناتر است جایگزین می‌کند. فونت فشرده برای جلوگیری از شکستن طرح‌بندی‌ها معرفی شد. Android 13 (سطح API 33) از بسیاری از این شکستگی‌ها جلوگیری می‌کند و به طرح متن اجازه می‌دهد تا ارتفاع عمودی را با استفاده از ویژگی fallbackLineSpacing کشیده شود.

در اندروید 15، فونت فشرده همچنان در سیستم باقی می‌ماند، بنابراین برنامه شما می‌تواند elegantTextHeight را روی false تنظیم کند تا رفتار قبلی را داشته باشد، اما بعید است که در نسخه‌های آینده پشتیبانی شود. بنابراین، اگر برنامه شما از اسکریپت های زیر پشتیبانی می کند: عربی، لائوس، میانمار، تامیل، گجراتی، کانادا، مالایالام، اودیا، تلوگو یا تایلندی، برنامه خود را با تنظیم elegantTextHeight روی true تست کنید.

رفتار elegantTextHeight برای برنامه‌هایی که Android 14 (سطح API 34) و پایین‌تر را هدف قرار می‌دهند.
رفتار elegantTextHeight برای برنامه هایی که اندروید 15 را هدف قرار می دهند.

تغییر عرض TextView برای شکل‌های پیچیده حروف

在以前的 Android 版本中,某些具有复杂形状的手写字体或语言可能会在上一个或下一个字符的区域绘制字母。在某些情况下,此类字母会在开头或结尾处被剪裁。从 Android 15 开始,TextView 会分配宽度,以便为此类字母绘制足够的空间,并允许应用请求向左额外添加内边距以防止剪裁。

由于此更改会影响 TextView 确定宽度的方式,因此如果应用以 Android 15(API 级别 35)或更高版本为目标平台,TextView 会默认分配更多宽度。您可以通过对 TextView 调用 setUseBoundsForWidth API 来启用或停用此行为。

由于添加左内边距可能会导致现有布局未对齐,因此默认情况下不会添加内边距,即使以 Android 15 或更高版本为目标平台的应用也是如此。不过,您可以通过调用 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

در نسخه‌های قبلی اندروید، طرح‌بندی متن، ارتفاع متن را به اندازه ارتفاع خط فونتی که با منطقه فعلی مطابقت دارد، افزایش می‌داد. به عنوان مثال، اگر محتوا به زبان ژاپنی بود، چون ارتفاع خط فونت ژاپنی کمی بزرگتر از فونت لاتین است، ارتفاع متن کمی بزرگتر می شد. با این حال، علی‌رغم این تفاوت‌ها در ارتفاع خط، عنصر EditText بدون توجه به منطقه مورد استفاده، همانطور که در تصویر زیر نشان داده شده است، اندازه یکسانی داشت:

سه کادر نشان دهنده عناصر EditText که می تواند حاوی متنی از انگلیسی (en)، ژاپنی (ja) و برمه ای (my) باشد. ارتفاع EditText یکسان است، حتی اگر این زبان ها دارای ارتفاع خطوط متفاوت از یکدیگر باشند.

برای برنامه‌هایی که Android 15 (سطح API 35) را هدف قرار می‌دهند، اکنون یک حداقل ارتفاع خط برای EditText محفوظ است تا با فونت مرجع برای Locale مشخص‌شده مطابقت داشته باشد، همانطور که در تصویر زیر نشان داده شده است:

سه کادر نشان دهنده عناصر EditText که می تواند حاوی متنی از انگلیسی (en)، ژاپنی (ja) و برمه ای (my) باشد. ارتفاع EditText اکنون شامل فضایی برای قرار دادن ارتفاع خط پیش‌فرض برای فونت‌های این زبان‌ها می‌شود.

در صورت نیاز، برنامه شما می‌تواند رفتار قبلی را با تعیین ویژگی useLocalePreferredLineHeightForMinimum به false بازیابی کند، و برنامه شما می‌تواند حداقل معیارهای عمودی سفارشی را با استفاده از setMinimumFontMetrics API در Kotlin و Java تنظیم کند.

دوربین و رسانه

اندروید ۱۵ تغییرات زیر را در رفتار دوربین و رسانه برای برنامه‌هایی که اندروید ۱۵ یا بالاتر را هدف قرار می‌دهند، ایجاد می‌کند.

محدودیت‌های درخواست فوکوس صوتی

以 Android 15(API 级别 35)为目标平台的应用必须是顶部应用或正在运行前台服务,才能请求音频焦点。如果应用在未满足上述任一要求的情况下尝试请求焦点,调用将返回 AUDIOFOCUS_REQUEST_FAILED

如需详细了解音频焦点,请参阅管理音频焦点

محدودیت‌های غیر SDK به‌روزرسانی شدند

اندروید ۱۵ شامل فهرست‌های به‌روز شده‌ای از رابط‌های کاربری محدود شده غیر SDK بر اساس همکاری با توسعه‌دهندگان اندروید و آخرین آزمایش‌های داخلی است. در صورت امکان، قبل از محدود کردن رابط‌های کاربری غیر SDK، مطمئن می‌شویم که جایگزین‌های عمومی در دسترس هستند.

اگر برنامه شما اندروید ۱۵ را هدف قرار نمی‌دهد، ممکن است برخی از این تغییرات بلافاصله شما را تحت تأثیر قرار ندهند. با این حال، اگرچه بسته به سطح API هدف برنامه ، ممکن است برنامه شما به برخی از رابط‌های غیر SDK دسترسی داشته باشد، استفاده از هر روش یا فیلد غیر SDK همیشه خطر بالای خرابی برنامه شما را به همراه دارد.

اگر مطمئن نیستید که برنامه شما از رابط‌های غیر SDK استفاده می‌کند، می‌توانید برنامه خود را آزمایش کنید تا متوجه شوید. اگر برنامه شما به رابط‌های غیر SDK متکی است، باید برنامه‌ریزی برای مهاجرت به جایگزین‌های SDK را آغاز کنید. با این وجود، ما درک می‌کنیم که برخی از برنامه‌ها موارد استفاده معتبری برای استفاده از رابط‌های غیر SDK دارند. اگر نمی‌توانید جایگزینی برای استفاده از رابط غیر SDK برای یک ویژگی در برنامه خود پیدا کنید، باید یک API عمومی جدید درخواست کنید .

如需详细了解此 Android 版本中的变更,请参阅 Android 15 中有关限制非 SDK 接口的更新。如需全面了解有关非 SDK 接口的详细信息,请参阅对非 SDK 接口的限制