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

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

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

عملکرد اصلی

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

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

ما در حال انجام تغییرات زیر در سرویس های پیش زمینه با اندروید 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

نوع سرویس پیش زمینه پردازش رسانه جدید

اندروید 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 برنامه شما در هر دوره ۲۴ ساعته در مجموع بیش از ۶ ساعت اجرا نمی‌شوند (مگر اینکه کاربر با برنامه تعامل داشته باشد و تایمر را بازنشانی کند).
  3. خدمات پیش زمینه mediaProcessing را فقط در نتیجه تعامل مستقیم کاربر شروع کنید. از آنجایی که هنگام شروع سرویس، برنامه شما در پیش زمینه است، سرویس شما شش ساعت کامل پس از رفتن برنامه به پس‌زمینه است.
  4. به جای استفاده از سرویس پیش زمینه mediaProcessing ، از یک API جایگزین مانند WorkManager استفاده کنید.

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

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

تغییرات OpenJDK API

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

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

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

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

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

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

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

  • تداخل با توابع افزونه MutableList.removeFirst() و MutableList.removeLast() در kotlin-stdlib

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

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

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

    گزینه موجود NewApi lint در «افزایه Android Gradle» می‌تواند این موارد استفاده جدید از میانای برنامه‌سازی کاربردی را شناسایی کند.

    ./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 جایگزین کرد. اگر از Android Studio Ladybug | 2024.1.3 یا بالاتر استفاده می‌کنید، این نسخه همچنین گزینه رفع سریع برای این خطاها ارائه می‌دهد.

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

  • تداخل با روش‌های دیگر در Java

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

امنیت

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

نسخه‌های محدودشده «امنیت لایه انتقال»

‫Android 15 استفاده از نسخه‌های ۱.۰ و ۱.۱ «امنیت لایه انتقال» (TLS) را محدود می‌کند. این نسخه‌ها قبلاً در Android منسوخ شده بودند، اما اکنون برای برنامه‌هایی که Android 15 را هدف قرار می‌دهند غیرمجاز هستند.

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

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

تغییرات دیگر

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

مقصودهای ایمن‌تر

‫Android 15‏ StrictMode را برای قصدها معرفی می‌کند.

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

کاتلین

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

جاوا

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

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

Android 15 شامل برخی تغییرات است که هدف آن‌ها ایجاد تجربه کاربری منسجم‌تر و شهودی‌تر است.

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

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

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

اگر برنامه Android 15 (سطح میانای برنامه‌سازی کاربردی ۳۵) را هدف قرار دهد، برنامه‌ها به‌طور پیش‌فرض در دستگاه‌های دارای Android 15 به‌صورت لبه‌به‌لبه نمایش داده می‌شوند.

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


برنامه‌ای که Android 15 (سطح میانای برنامه‌سازی کاربردی 35) را هدف قرار می‌دهد و در دستگاه Android 15 به‌صورت لبه‌به‌لبه است. این برنامه بیشتر از «مؤلفه‌های ترکیب‌بندی Material 3» استفاده می‌کند که به‌طور خودکار تورفتگی‌ها را اعمال می‌کند. این صفحه تحت‌تأثیر منفی اجرای لبه‌به‌لبه Android 15 قرار نمی‌گیرد.

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

  • نوار پیمایش دستگیره اشاره
    • به‌طور پیش‌فرض شفاف است.
    • انحراف پایین غیرفعال است، بنابراین محتوا در پشت نوار پیمایش سیستم رسم می‌شود، مگراینکه تورفتگی‌ها اعمال شده باشند.
    • setNavigationBarColor و R.attr#navigationBarColor منسوخ شده‌اند و بر پیمایش اشاره‌ای تأثیر نمی‌گذارند.
    • setNavigationBarContrastEnforced و R.attr#navigationBarContrastEnforced همچنان تأثیری بر پیمایش اشاره‌ای ندارند.
  • پیمایش ۳دکمه‌ای
    • کدری به‌طور پیش‌فرض روی ۸۰٪ تنظیم شده است و رنگ احتمالاً با پس‌زمینه پنجره مطابقت دارد.
    • انحراف پایین غیرفعال شده است تا محتوا در پشت نوار پیمایش سیستم رسم شود مگر اینکه تورفتگی‌ها اعمال شده باشد.
    • setNavigationBarColor و R.attr#navigationBarColor به‌طور پیش‌فرض به‌گونه‌ای تنظیم شده‌اند که با پس‌زمینه پنجره مطابقت داشته باشند. پس‌زمینه پنجره باید رنگی قابل‌ترسیم باشد تا این پیش‌فرض اعمال شود. این میانای برنامه‌سازی کاربردی منسوخ شده است اما همچنان بر پیمایش ۳ دکمه‌ای تأثیر می‌گذارد.
    • setNavigationBarContrastEnforced و R.attr#navigationBarContrastEnforced به‌طور پیش‌فرض درست است، که پس‌زمینه کدر ۸۰٪ را در پیمایش ۳دکمه‌ای اضافه می‌کند.
  • نوار وضعیت
    • به‌طور پیش‌فرض شفاف است.
    • انحراف بالا غیرفعال است، بنابراین محتوا در پشت نوار وضعیت ترسیم می‌شود، مگراینکه درج‌ها اعمال شوند.
    • 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 (سطح میانای برنامه‌سازی کاربردی ۳۵) و قبل و بعداز اعمال حاشیه‌ها نشان می‌دهد. این مثال جامع نیست، ممکن است در Android Auto متفاوت به‌نظر برسد.

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

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

  • پنجره غیرشناور دارید، مثلاً Activity که به‌جای LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS از SHORT_EDGES، NEVER، یا DEFAULT استفاده می‌کند. اگر برنامه‌تان هنگام راه‌اندازی ازکار می‌افتد، ممکن است به‌دلیل صفحه آغازین باشد. می‌توانید وابستگی core splashscreen را به 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، تورفتگی‌ها را مدیریت می‌کنند و به کار اضافی نیاز ندارند. اما اگر از AppBarLayout استفاده می‌کنید، باید android:fitsSystemWindows="true" را اضافه کنید.
  • برای ترکیب‌پذیرهای سفارشی، تورفتگی‌ها را به‌صورت دستی به‌عنوان فاصله‌گذاری اعمال کنید. اگر محتوایتان درون Scaffold قرار دارد، می‌توانید بااستفاده از مقادیر حاشیه داخلی Scaffold، از حاشیه‌های داخلی استفاده کنید. درغیراین‌صورت، بااستفاده از یکی از WindowInsets، حاشیه داخلی اعمال کنید.
  • اگر برنامه‌تان از نماها و BottomSheet، SideSheet یا محفظه‌های سفارشی استفاده می‌کند، بااستفاده از ViewCompat.setOnApplyWindowInsetsListener لایه داخلی اعمال کنید. برای RecyclerView، لایه‌گذاری را بااستفاده از این شنونده اعمال کنید و همچنین clipToPadding="false" را اضافه کنید.
اگر برنامه‌تان باید محافظت پس‌زمینه سفارشی ارائه دهد، چه چیزی را باید بررسی کنید

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

منابع تکمیلی برای لبه‌به‌لبه

برای ملاحظات بیشتر درباره اعمال تورفتگی‌ها، راهنماهای نماهای لب‌به‌لب و ترکیب‌بندی لب‌به‌لب را ببینید.

میاناهای برنامه‌سازی کاربردی منسوخ‌شده

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

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

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

اگر برنامه شما Android 15 (سطح میانای برنامه‌سازی کاربردی ۳۵) یا بالاتر را هدف قرار می‌دهد، 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 قرار گرفته است. این مورد از سطح میانای برنامه‌سازی کاربردی ۳۰ منسوخ شده است.
  • Display.getMetrics() از سطح میانای برنامه‌سازی کاربردی ۳۳ به همین صورت کار می‌کرده است.

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

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

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

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

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

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

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

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

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

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