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

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

حتماً فهرستی از تغییرات رفتاری را نیز مرور کنید که بر همه برنامه‌های در حال اجرا در Android 15 بدون توجه به targetSdkVersion برنامه شما تأثیر می‌گذارد.

عملکرد اصلی

اندروید 15 قابلیت های اصلی مختلف سیستم اندروید را اصلاح یا گسترش می دهد.

تغییرات در خدمات پیش زمینه

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

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

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:

  1. Have your service implement the new Service.onTimeout(int, int) method. When your app receives the callback, make sure to call stopSelf() within a few seconds. (If you don't stop the app right away, the system generates a failure.)
  2. Make sure your app's dataSync services 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).
  3. Only start dataSync foreground 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.
  4. Instead of using a dataSync foreground 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:

  1. Have your service implement the new Service.onTimeout(int, int) method. When your app receives the callback, make sure to call stopSelf() within a few seconds. (If you don't stop the app right away, the system generates a failure.)
  2. Make sure your app's mediaProcessing services 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).
  3. Only start mediaProcessing foreground 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.
  4. Instead of using a mediaProcessing foreground 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 که خدمات پیش زمینه را راه اندازی می کنند

محدودیت های جدیدی برای گیرنده های پخش 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) را در دستگاه تغییر دهند (چه با تغییر تنظیمات کاربر یا خاموش کردن حالت DND). در عوض، برنامه‌ها باید یک AutomaticZenRule ارائه دهند، که سیستم آن را در یک خط‌مشی جهانی با طرح موجود بیشترین محدودیت‌کننده-سیاست-برنده ترکیب می‌کند. تماس‌های APIهای موجود که قبلاً بر وضعیت جهانی تأثیر می‌گذاشتند ( setInterruptionFilter ، setNotificationPolicy ) منجر به ایجاد یا به‌روزرسانی یک AutomaticZenRule ضمنی می‌شود که بسته به چرخه تماس آن فراخوان‌های API، روشن و خاموش می‌شود.

توجه داشته باشید که این تغییر تنها در صورتی بر رفتار قابل مشاهده تأثیر می‌گذارد که برنامه setInterruptionFilter(INTERRUPTION_FILTER_ALL) را فراخوانی کند و انتظار دارد که این تماس AutomaticZenRule را که قبلاً توسط صاحبان آن فعال شده است غیرفعال کند.

OpenJDK API تغییر می کند

اندروید 15 به کار تازه سازی کتابخانه های اصلی اندروید برای هماهنگی با ویژگی های آخرین نسخه OpenJDK LTS ادامه می دهد.

برخی از این تغییرات می‌تواند بر سازگاری برنامه‌ها برای برنامه‌هایی که Android 15 را هدف قرار می‌دهند (سطح API 35) تأثیر بگذارد:

  • تغییرات در APIهای قالب‌بندی رشته‌ای : اعتبارسنجی شاخص آرگومان، پرچم‌ها، عرض و دقت اکنون هنگام استفاده از APIهای 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 API، کدهای زبان عبری، ییدیش و اندونزیایی دیگر به شکل‌های منسوخ خود تبدیل نمی‌شوند (عبری: iw ، ییدیش: ji ، و اندونزیایی: in ). هنگام تعیین کد زبان برای یکی از این مناطق، به جای آن از کدهای ISO 639-1 استفاده کنید (عبری: he ، ییدیش: yi ، و اندونزیایی: id ).

  • تغییرات در دنباله‌های تصادفی int : به دنبال تغییرات ایجاد شده در https://bugs.openjdk.org/browse/JDK-8301574 ، متدهای Random.ints() زیر اکنون دنباله‌ای متفاوت از اعداد را نسبت به متدهای Random.nextInt() انجام دهید:

    به طور کلی، این تغییر نباید منجر به رفتار شکستن برنامه شود، اما کد شما نباید انتظار داشته باشد که دنباله تولید شده از متدهای Random.ints() مطابق با Random.nextInt() باشد.

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

  • برخورد با توابع پسوند MutableList.removeFirst() و MutableList.removeLast() در kotlin-stdlib

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

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

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

    گزینه NewApi lint موجود در پلاگین Android Gradle می تواند این موارد استفاده جدید API را دریافت کند.

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

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

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

  • برخورد با روش های دیگر در جاوا

    روش های جدیدی به انواع موجود اضافه شده است، به عنوان مثال، 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();
    }
    

امنیت

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

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

اندروید 15 از کاربران در برابر برنامه‌های مخرب محافظت می‌کند و با افزودن تغییراتی که مانع از نمایش برنامه‌های مخرب در پس‌زمینه، افزایش امتیازات و سوء استفاده از تعامل با کاربر می‌شود، کنترل بیشتری بر دستگاه‌هایشان می‌دهد. راه اندازی فعالیت های پس زمینه از Android 10 (سطح API 29) محدود شده است.

تغییرات دیگر

علاوه بر محدودیت برای تطبیق UID، این تغییرات دیگر نیز شامل می شود:

  • سازندگان PendingIntent تغییر دهید تا به طور پیش‌فرض راه‌اندازی‌های فعالیت پس‌زمینه را مسدود کنند . این به جلوگیری از ایجاد تصادفی یک PendingIntent توسط برنامه‌ها کمک می‌کند که ممکن است توسط عوامل مخرب مورد سوء استفاده قرار گیرد.
  • یک برنامه را در پیش زمینه نیاورید مگر اینکه فرستنده PendingIntent اجازه دهد . هدف این تغییر جلوگیری از سوء استفاده برنامه های مخرب از توانایی شروع فعالیت در پس زمینه است. به‌طور پیش‌فرض، برنامه‌ها اجازه ندارند پشته کار را به پیش‌زمینه بیاورند، مگر اینکه سازنده امتیازات راه‌اندازی فعالیت پس‌زمینه را اجازه دهد یا فرستنده دارای امتیازات راه‌اندازی فعالیت در پس‌زمینه باشد.
  • کنترل کنید که فعالیت برتر یک پشته وظیفه چگونه می تواند کار خود را به پایان برساند . اگر فعالیت برتر یک کار را تمام کند، Android به هر کاری که آخرین بار فعال بوده است برمی گردد. علاوه بر این، اگر یک فعالیت غیر برتر وظیفه خود را به پایان برساند، Android به صفحه اصلی باز خواهد گشت. پایان این فعالیت غیر برتر را مسدود نخواهد کرد.
  • از راه‌اندازی فعالیت‌های خودسرانه از برنامه‌های دیگر در وظیفه خود جلوگیری کنید . این تغییر با ایجاد فعالیت هایی که به نظر می رسد از سایر برنامه ها باشد، از فیشینگ کاربران توسط برنامه های مخرب جلوگیری می کند.
  • از در نظر گرفتن پنجره‌های غیرقابل مشاهده برای راه‌اندازی فعالیت پس‌زمینه جلوگیری کنید . این به جلوگیری از سوء استفاده برنامه های مخرب از راه اندازی فعالیت های پس زمینه برای نمایش محتوای ناخواسته یا مخرب به کاربران کمک می کند.
،

اندروید 15 از کاربران در برابر برنامه‌های مخرب محافظت می‌کند و با افزودن تغییراتی که مانع از نمایش برنامه‌های مخرب در پس‌زمینه، افزایش امتیازات و سوء استفاده از تعامل با کاربر می‌شود، کنترل بیشتری بر دستگاه‌هایشان می‌دهد. راه اندازی فعالیت های پس زمینه از Android 10 (سطح API 29) محدود شده است.

تغییرات دیگر

علاوه بر محدودیت برای تطبیق UID، این تغییرات دیگر نیز شامل می شود:

  • سازندگان PendingIntent تغییر دهید تا به طور پیش‌فرض راه‌اندازی‌های فعالیت پس‌زمینه را مسدود کنند . این به جلوگیری از ایجاد تصادفی یک PendingIntent توسط برنامه‌ها کمک می‌کند که ممکن است توسط عوامل مخرب مورد سوء استفاده قرار گیرد.
  • یک برنامه را در پیش زمینه نیاورید مگر اینکه فرستنده PendingIntent اجازه دهد . هدف این تغییر جلوگیری از سوء استفاده برنامه های مخرب از توانایی شروع فعالیت در پس زمینه است. به‌طور پیش‌فرض، برنامه‌ها اجازه ندارند پشته کار را به پیش‌زمینه بیاورند، مگر اینکه سازنده امتیازات راه‌اندازی فعالیت پس‌زمینه را اجازه دهد یا فرستنده دارای امتیازات راه‌اندازی فعالیت در پس‌زمینه باشد.
  • کنترل کنید که فعالیت برتر یک پشته وظیفه چگونه می تواند کار خود را به پایان برساند . اگر فعالیت برتر یک کار را تمام کند، Android به هر کاری که آخرین بار فعال بوده است برمی گردد. علاوه بر این، اگر یک فعالیت غیر برتر وظیفه خود را به پایان برساند، Android به صفحه اصلی باز خواهد گشت. پایان این فعالیت غیر برتر را مسدود نخواهد کرد.
  • از راه‌اندازی فعالیت‌های خودسرانه از برنامه‌های دیگر در وظیفه خود جلوگیری کنید . این تغییر با ایجاد فعالیت هایی که به نظر می رسد از سایر برنامه ها باشد، از فیشینگ کاربران توسط برنامه های مخرب جلوگیری می کند.
  • از در نظر گرفتن پنجره‌های غیرقابل مشاهده برای راه‌اندازی فعالیت پس‌زمینه جلوگیری کنید . این به جلوگیری از سوء استفاده برنامه های مخرب از راه اندازی فعالیت های پس زمینه برای نمایش محتوای ناخواسته یا مخرب به کاربران کمک می کند.

مقاصد امن تر

اندروید 15 اقدامات امنیتی اختیاری جدیدی را برای ایمن تر و قوی تر کردن مقاصد معرفی می کند. این تغییرات با هدف جلوگیری از آسیب پذیری های احتمالی و سوء استفاده از اهدافی است که می تواند توسط برنامه های مخرب مورد سوء استفاده قرار گیرد. دو پیشرفت اصلی برای امنیت intent در اندروید 15 وجود دارد:

  • Match target-intent-filters: مقاصدی که اجزای خاصی را هدف قرار می دهند باید دقیقاً با مشخصات فیلتر هدف هدف مطابقت داشته باشند. اگر قصدی برای راه‌اندازی فعالیت برنامه دیگری ارسال می‌کنید، مؤلفه هدف هدف باید با فیلترهای هدف اعلام‌شده فعالیت دریافت‌کننده هماهنگ شود.
  • Intent ها باید دارای عملکرد باشند: Intent های بدون عمل دیگر با فیلترهای intent مطابقت ندارند. این بدان معناست که مقاصد مورد استفاده برای شروع فعالیت ها یا خدمات باید دارای یک کنش به وضوح تعریف شده باشند.

برای بررسی اینکه برنامه شما چگونه به این تغییرات پاسخ می دهد، از StrictMode در برنامه خود استفاده کنید. برای مشاهده گزارش‌های دقیق درباره نقض استفاده Intent ، روش زیر را اضافه کنید:

کاتلین


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

جاوا


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

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

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

ورودی پنجره تغییر می کند

در اندروید 15 دو تغییر مربوط به ورودی‌های پنجره وجود دارد: لبه به لبه به‌طور پیش‌فرض اعمال می‌شود و همچنین تغییراتی در پیکربندی وجود دارد، مانند پیکربندی پیش‌فرض نوارهای سیستم.

اجرای لبه به لبه

اگر برنامه اندروید 15 (سطح API 35) را هدف قرار دهد، برنامه‌ها به‌طور پیش‌فرض در دستگاه‌های دارای Android 15 لبه به لبه هستند.

برنامه ای که اندروید 14 را هدف قرار می دهد و در دستگاه اندروید 15 لبه به لبه نیست.


برنامه ای که اندروید 15 (سطح API 35) را هدف قرار می دهد و در دستگاه اندروید 15 لبه به لبه است. این برنامه بیشتر از کامپوننت های Material 3 Compose استفاده می کند که به طور خودکار inset ها را اعمال می کنند. این صفحه نمایش تحت تأثیر اجرای لبه به لبه اندروید 15 قرار نمی گیرد.

این یک تغییر اساسی است که ممکن است بر رابط کاربری برنامه شما تأثیر منفی بگذارد. تغییرات بر حوزه های UI زیر تأثیر می گذارد:

  • نوار پیمایش دسته اشاره
    • به طور پیش فرض شفاف است.
    • افست پایین غیرفعال است، بنابراین محتوا در پشت نوار پیمایش سیستم کشیده می‌شود، مگر اینکه ورودی‌ها اعمال شوند.
    • setNavigationBarColor و R.attr#navigationBarColor منسوخ شده‌اند و بر ناوبری اشاره‌ای تأثیری ندارند.
    • setNavigationBarContrastEnforced و R.attr#navigationBarContrastEnforced همچنان هیچ تاثیری بر ناوبری اشاره ای ندارند.
  • ناوبری 3 دکمه ای
    • Opacity به طور پیش‌فرض روی 80% تنظیم شده است و رنگ احتمالاً با پس‌زمینه پنجره مطابقت دارد.
    • افست پایین غیرفعال است، بنابراین محتوا در پشت نوار پیمایش سیستم کشیده می‌شود مگر اینکه درج‌های داخلی اعمال شوند.
    • setNavigationBarColor و R.attr#navigationBarColor به طور پیش‌فرض با پس‌زمینه پنجره مطابقت دارند. پس زمینه پنجره باید یک رنگ قابل ترسیم باشد تا این پیش فرض اعمال شود. این API منسوخ شده است اما همچنان بر ناوبری 3 دکمه ای تأثیر می گذارد.
    • setNavigationBarContrastEnforced و R.attr#navigationBarContrastEnforced به طور پیش‌فرض درست است، که 80% پس‌زمینه مات را در مسیریابی 3 دکمه اضافه می‌کند.
  • نوار وضعیت
    • به طور پیش فرض شفاف است.
    • افست بالا غیرفعال است، بنابراین محتوا در پشت نوار وضعیت ترسیم می شود، مگر اینکه درج ها اعمال شوند.
    • setStatusBarColor و R.attr#statusBarColor منسوخ شده اند و روی اندروید 15 تاثیری ندارند.
    • setStatusBarContrastEnforced و R.attr#statusBarContrastEnforced منسوخ شده‌اند اما همچنان روی اندروید 15 اثر دارند.
  • برش نمایشگر
    • layoutInDisplayCutoutMode پنجره‌های غیر شناور باید LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS باشد. SHORT_EDGES ، NEVER و DEFAULT به‌عنوان ALWAYS تفسیر می‌شوند تا کاربران نوار سیاه ناشی از بریدگی نمایشگر را نبینند و لبه به لبه ظاهر شوند.

مثال زیر یک برنامه را قبل و بعد از هدف قرار دادن Android 15 (سطح API 35) و قبل و بعد از اعمال insets نشان می دهد.

برنامه ای که اندروید 14 را هدف قرار می دهد و در دستگاه اندروید 15 لبه به لبه نیست.
برنامه ای که اندروید 15 (سطح API 35) را هدف قرار می دهد و در دستگاه اندروید 15 لبه به لبه است. با این حال، بسیاری از عناصر در حال حاضر توسط نوار وضعیت، نوار ناوبری 3 دکمه یا بریدگی نمایشگر به دلیل اجرای لبه به لبه اندروید 15 پنهان شده اند. رابط کاربری پنهان شامل نوار برنامه بالای Material 2، دکمه‌های عمل شناور و موارد فهرست است.
برنامه‌ای که Android 15 (سطح API 35) را هدف قرار می‌دهد، لبه به لبه در دستگاه Android 15 است و ورودی‌ها را اعمال می‌کند تا رابط کاربری پنهان نشود.
چه باید بررسی کرد که آیا برنامه شما از قبل لبه به لبه است

اگر برنامه شما از قبل لبه به لبه است و از inset ها استفاده می کند، به جز در سناریوهای زیر، اکثراً بی تأثیر هستید. با این حال، حتی اگر فکر می کنید تحت تأثیر قرار نگرفته اید، توصیه می کنیم برنامه خود را آزمایش کنید.

  • شما یک پنجره غیر شناور دارید، مانند Activity که به جای LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS از SHORT_EDGES ، NEVER یا DEFAULT استفاده می کند. اگر برنامه شما در هنگام راه‌اندازی از کار می‌افتد، ممکن است به خاطر صفحه نمایش شما باشد. می‌توانید وابستگی اصلی صفحه نمایش اسپلش را به 1.2.0-alpha01 یا بالاتر ارتقا دهید یا window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutInDisplayCutoutMode.always تنظیم کنید.
  • ممکن است صفحه نمایش هایی با ترافیک کمتر با رابط کاربری مسدود شده وجود داشته باشد. بررسی کنید این صفحه‌نمایش‌هایی که کمتر بازدید شده‌اند، رابط کاربری مسدود شده ندارند. صفحه نمایش های کم تردد عبارتند از:
    • صفحات ورود یا ورود به سیستم
    • صفحات تنظیمات
اگر برنامه شما از قبل لبه به لبه نیست، چه باید بررسی کنید

اگر برنامه شما در حال حاضر لبه به لبه نیست، به احتمال زیاد تحت تأثیر قرار خواهید گرفت. علاوه بر سناریوهای برنامه‌هایی که از قبل لبه به لبه هستند، باید موارد زیر را در نظر بگیرید:

  • اگر برنامه شما از Material 3 Components ( androidx.compose.material3 ) در نوشتن استفاده می‌کند، مانند TopAppBar ، BottomAppBar ، و NavigationBar ، این مؤلفه‌ها احتمالاً تحت تأثیر قرار نمی‌گیرند زیرا به‌طور خودکار ورودی‌ها را مدیریت می‌کنند.
  • اگر برنامه شما از Material 2 Components ( androidx.compose.material ) در Compose استفاده می‌کند، این مؤلفه‌ها به‌طور خودکار ورودی‌ها را مدیریت نمی‌کنند. با این حال، می توانید به inset ها دسترسی داشته باشید و آنها را به صورت دستی اعمال کنید. در androidx.compose.material 1.6.0 و جدیدتر، از پارامتر windowInsets برای اعمال دستی Insets برای BottomAppBar ، TopAppBar ، BottomNavigation و NavigationRail استفاده کنید. به همین ترتیب، از پارامتر contentWindowInsets برای Scaffold استفاده کنید.
  • اگر برنامه شما از نماها و مؤلفه‌های مواد ( com.google.android.material ) استفاده می‌کند، بیشتر مؤلفه‌های مواد مبتنی بر نما مانند BottomNavigationView ، BottomAppBar ، NavigationRailView یا NavigationView ، ورودی‌ها را مدیریت می‌کنند و نیازی به کار اضافی ندارند. با این حال، اگر از AppBarLayout استفاده می کنید، باید android:fitsSystemWindows="true" را اضافه کنید.
  • برای ترکیب‌های سفارشی، اینست‌ها را به‌صورت دستی به‌عنوان بالشتک اعمال کنید. اگر محتوای شما در داخل یک Scaffold است، می‌توانید با استفاده از مقادیر Scaffold padding از انست استفاده کنید. در غیر این صورت، با استفاده از یکی از WindowInsets ، padding را اعمال کنید.
  • اگر برنامه شما از نماها و BottomSheet ، SideSheet یا ظروف سفارشی استفاده می کند، با استفاده از ViewCompat.setOnApplyWindowInsetsListener padding را اعمال کنید. برای RecyclerView ، با استفاده از این شنونده، padding را اعمال کنید و clipToPadding="false" را نیز اضافه کنید.
چه باید بررسی کرد که آیا برنامه شما باید محافظت پس‌زمینه سفارشی ارائه دهد

اگر برنامه شما باید محافظت پس‌زمینه سفارشی را برای ناوبری 3 دکمه یا نوار وضعیت ارائه دهد، برنامه شما باید با استفاده از WindowInsets.Type#tappableElement() یک قابلیت ترکیب یا نمایش را در پشت نوار سیستم قرار دهد تا ارتفاع نوار ناوبری 3 دکمه یا WindowInsets.Type#statusBars .

منابع لبه به لبه اضافی

برای ملاحظات بیشتر در مورد اعمال inset ها، راهنمای Edge to Edge Views و Edge to Edge Compose را ببینید.

API های منسوخ شده

API های زیر منسوخ شده اند اما غیرفعال نشده اند:

API های زیر منسوخ و غیرفعال شده اند:

پیکربندی پایدار

اگر برنامه شما 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 منسوخ شد.
  • Display.getMetrics() قبلاً از سطح API 33 به این شکل کار کرده است.

صفت elegantTextHeight به طور پیش فرض درست است

برای برنامه‌هایی که 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 برای اشکال حروف پیچیده تغییر می کند

در نسخه‌های قبلی اندروید، برخی از فونت‌های شکسته یا زبان‌هایی که شکل پیچیده‌ای دارند، ممکن است حروف را در ناحیه شخصیت قبلی یا بعدی بکشند. در برخی موارد، چنین حروفی در موقعیت آغاز یا پایان بریده می شدند. با شروع اندروید 15، یک TextView عرض را برای ترسیم فضای کافی برای چنین حروفی اختصاص می‌دهد و به برنامه‌ها اجازه می‌دهد تا برای جلوگیری از برش، بالشتک‌های اضافی را در سمت چپ درخواست کنند.

از آنجایی که این تغییر بر نحوه تعیین عرض یک TextView تأثیر می‌گذارد، اگر برنامه Android 15 (سطح API 35) یا بالاتر را هدف قرار دهد، TextView به طور پیش‌فرض عرض بیشتری را اختصاص می‌دهد. می توانید این رفتار را با فراخوانی API setUseBoundsForWidth در TextView فعال یا غیرفعال کنید.

از آنجایی که افزودن پد سمت چپ ممکن است باعث ایجاد ناهماهنگی در طرح‌بندی‌های موجود شود، این پد به‌طور پیش‌فرض حتی برای برنامه‌هایی که 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 تغییرات زیر را در رفتار دوربین و رسانه برای برنامه هایی که اندروید 15 یا بالاتر را هدف قرار می دهند، اعمال می کند.

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

برنامه‌هایی که Android 15 (سطح API 35) را هدف قرار می‌دهند باید برنامه برتر باشند یا یک سرویس پیش‌زمینه را اجرا کنند تا فوکوس صوتی را درخواست کنند . اگر برنامه‌ای بخواهد فوکوس را درخواست کند در حالی که یکی از این شرایط را برآورده نمی‌کند، تماس AUDIOFOCUS_REQUEST_FAILED را برمی‌گرداند.

می‌توانید در مدیریت فوکوس صوتی درباره فوکوس صوتی اطلاعات بیشتری کسب کنید.

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

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

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

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

برای اطلاعات بیشتر در مورد تغییرات این نسخه از اندروید، به‌روزرسانی‌های محدودیت‌های رابط غیر SDK در Android 15 را ببینید. برای کسب اطلاعات بیشتر در مورد رابط های غیر SDK به طور کلی، به محدودیت ها در رابط های غیر SDK مراجعه کنید.