مانند نسخههای قبلی، Android 15 شامل تغییرات رفتاری است که ممکن است بر برنامه شما تأثیر بگذارد. تغییرات رفتاری زیر منحصراً برای برنامههایی اعمال میشود که Android 15 یا بالاتر را هدف قرار میدهند. اگر برنامه شما Android 15 یا بالاتر را هدف قرار میدهد، باید برنامه خود را اصلاح کنید تا از این رفتارها بهدرستی پشتیبانی کند، درصورت قابل اجرا بودن.
حتماً فهرست تغییرات رفتاری را که بر همه برنامههای
اجراشده در Android 15 تأثیر میگذارد، صرفنظر از targetSdkVersion برنامهتان، مرور کنید.
عملکرد اصلی
Android 15 قابلیتهای اصلی مختلف سیستم Android را اصلاح یا گسترش میدهد.
تغییرات در سرویسهای پیشزمینهای
ما در حال انجام تغییرات زیر در سرویس های پیش زمینه با اندروید 15 هستیم.
- رفتار درنگ سرویس پیش زمینه همگام سازی داده ها
- نوع سرویس پیش زمینه پردازش رسانه جدید
- محدودیت در گیرنده های پخش
BOOT_COMPLETEDکه خدمات پیش زمینه را راه اندازی می کنند - محدودیتهایی برای شروع سرویسهای پیشزمینه در زمانی که برنامه دارای مجوز
SYSTEM_ALERT_WINDOWاست
رفتار درنگ سرویس پیش زمینه همگام سازی داده ها
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]"
برای جلوگیری از مشکلات ناشی از این تغییر رفتار، می توانید یک یا چند مورد از موارد زیر را انجام دهید:
- از سرویس خود بخواهید روش جدید
Service.onTimeout(int, int)را پیاده سازی کند. وقتی برنامه شما پاسخ تماس را دریافت کرد، مطمئن شوید که در عرض چند ثانیهstopSelf()تماس بگیرید. (اگر برنامه را فورا متوقف نکنید، سیستم خراب می شود.) - مطمئن شوید که سرویسهای
dataSyncبرنامه شما در هر دوره 24 ساعته در مجموع بیش از 6 ساعت اجرا نمیشوند (مگر اینکه کاربر با برنامه تعامل داشته باشد و تایمر را بازنشانی کند). - خدمات پیش زمینه
dataSyncفقط در نتیجه تعامل مستقیم کاربر شروع کنید. از آنجایی که برنامه شما هنگام شروع سرویس در پیش زمینه است، سرویس شما شش ساعت کامل پس از رفتن برنامه به پسزمینه است. - به جای استفاده از سرویس پیش زمینه
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]"
برای جلوگیری از استثناء، می توانید یکی از موارد زیر را انجام دهید:
- از سرویس خود بخواهید روش جدید
Service.onTimeout(int, int)را پیاده سازی کند. هنگامی که برنامه شما پاسخ تماس را دریافت کرد، مطمئن شوید که در عرض چند ثانیهstopSelf()تماس بگیرید. (اگر برنامه را فوراً متوقف نکنید، سیستم یک خرابی ایجاد می کند.) - مطمئن شوید که سرویسهای
mediaProcessingبرنامه شما در هر دوره ۲۴ ساعته در مجموع بیش از ۶ ساعت اجرا نمیشوند (مگر اینکه کاربر با برنامه تعامل داشته باشد و تایمر را بازنشانی کند). - خدمات پیش زمینه
mediaProcessingرا فقط در نتیجه تعامل مستقیم کاربر شروع کنید. از آنجایی که هنگام شروع سرویس، برنامه شما در پیش زمینه است، سرویس شما شش ساعت کامل پس از رفتن برنامه به پسزمینه است. - به جای استفاده از سرویس پیش زمینه
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 مجاز به راه اندازی انواع خدمات پیش زمینه زیر نیستند :
-
dataSync -
camera -
mediaPlayback -
phoneCall -
mediaProjection -
microphone(این محدودیت از اندروید 14 برایmicrophoneاعمال شده است)
اگر یک گیرنده 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()زیر سختگیرانهتر است:String.format(String, Object[])String.format(Locale, String, Object[])Formatter.format(String, Object[])Formatter.format(Locale, String, Object[])
برای مثال، وقتی از نمایه متغیر مستقل 0 استفاده میشود (
%0در رشته قالب)، استثنای زیر ایجاد میشود:IllegalFormatArgumentIndexException: Illegal format argument index = 0در این مورد، مشکل را میتوان بااستفاده از نمایه شناسه ۱ (
%1در رشته قالب) برطرف کرد.تغییرات در نوع مؤلفه
Arrays.asList(...).toArray(): هنگام استفاده ازArrays.asList(...).toArray()، نوع مؤلفه آرایه حاصل اکنونObjectاست—نه نوع عناصر آرایه زیرین. بنابراین کد زیرClassCastExceptionرا برمیگرداند:String[] elements = (String[]) Arrays.asList("one", "two").toArray();در این مورد، برای حفظ
Stringبهعنوان نوع مؤلفه در آرایه حاصل، میتوانید بهجای آن ازCollection.toArray(Object[])استفاده کنید:String[] elements = Arrays.asList("two", "one").toArray(new String[0]);تغییرات در مدیریت کد زبان: هنگام استفاده از
LocaleAPI، کدهای زبان عبری، ییدیش، و اندونزیایی دیگر به شکلهای منسوخشده خود تبدیل نمیشوند (عبری:iw، ییدیش:ji، و اندونزیایی:in). هنگام مشخص کردن کد زبان برای یکی از این زبانها، بهجای آن از کدهای ISO 639-1 استفاده کنید (عبری:he، ییدیش:yi، و اندونزیایی:id).تغییرات در توالیهای عدد صحیح تصادفی: بهدنبال تغییرات ایجادشده در 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;گزینه موجود
NewApilint در «افزایه Android Gradle» میتواند این موارد استفاده جدید از میانای برنامهسازی کاربردی را شناسایی کند../gradlew lintMainActivity.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.javaMyList.java:135: error: removeLast() in MyList cannot implement removeLast() in List public void removeLast() { ^ return type void is not compatible with Object where E is a type-variable: E extends Object declared in interface Listنمونه خطا ۲:
javac MyList.javaMyList.java:7: error: types Deque<Object> and List<Object> are incompatible; public class MyList implements List<Object>, Deque<Object> { both define reversed(), but with unrelated return types 1 errorخطای نمونه ۳:
javac MyList.javaMyList.java:43: error: types List<E#1> and MyInterface<E#2> are incompatible; public static class MyList implements List<Object>, MyInterface<Object> { class MyList inherits unrelated defaults for getFirst() from types List and MyInterface where E#1,E#2 are type-variables: E#1 extends Object declared in interface List E#2 extends Object declared in interface MyInterface 1 errorبرای برطرف کردن این خطاهای ساخت، کلاسی که این میاناهای کاربری را پیادهسازی میکند باید روش را با نوع پاسخ سازگار لغو کند. برای مثال:
@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 بهصورت لبهبهلبه نمایش داده میشوند.
این تغییری ناسازگار است که ممکن است تأثیر منفی بر واسط کاربر برنامهتان داشته باشد. این تغییرات بر بخشهای زیر از میانای کاربر تأثیر میگذارد:
- نوار پیمایش دستگیره اشاره
- بهطور پیشفرض شفاف است.
- انحراف پایین غیرفعال است، بنابراین محتوا در پشت نوار پیمایش سیستم رسم میشود، مگراینکه تورفتگیها اعمال شده باشند.
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 متفاوت بهنظر برسد.
اگر برنامهتان ازقبل لبهبهلبه است، چه چیزی را باید بررسی کنید
اگر برنامهتان ازقبل لببهلب است و تورفتگیها را اعمال میکند، بهجز در سناریوهای زیر، عمدتاً تحتتأثیر قرار نمیگیرید. بااینحال، حتی اگر فکر میکنید تحت تأثیر قرار نمیگیرید، توصیه میکنیم برنامهتان را آزمایش کنید.
- پنجره غیرشناور دارید، مثلاً
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 یا نما را پشت نوار سیستم قرار دهد.
منابع تکمیلی برای لبهبهلبه
برای ملاحظات بیشتر درباره اعمال تورفتگیها، راهنماهای نماهای لببهلب و ترکیببندی لببهلب را ببینید.
میاناهای برنامهسازی کاربردی منسوخشده
میاناهای برنامهسازی کاربردی زیر منسوخ شدهاند اما غیرفعال نشدهاند:
R.attr#enforceStatusBarContrastR.attr#navigationBarColor(برای پیمایش ۳دکمهای، با ۸۰٪ آلفا)Window#isStatusBarContrastEnforcedWindow#setNavigationBarColor(برای پیمایش ۳دکمهای، با آلفای ۸۰٪)Window#setStatusBarContrastEnforced
میاناهای برنامهسازی کاربردی زیر منسوخ و غیرفعال شدهاند:
R.attr#navigationBarColor(برای پیمایش اشارهای)R.attr#navigationBarDividerColorR.attr#statusBarColorWindow#setDecorFitsSystemWindowsWindow#getNavigationBarColorWindow#getNavigationBarDividerColorWindow#getStatusBarColorWindow#setNavigationBarColor(برای پیمایش اشارهای)Window#setNavigationBarDividerColorWindow#setStatusBarColor
پیکربندی پایدار
اگر برنامه شما 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 ، بالشتک اضافی برای جلوگیری از بریدن اضافه کنید.
مثالهای زیر نشان میدهند که چگونه این تغییرات میتوانند طرحبندی متن را برای برخی از فونتها و زبانها بهبود بخشند.

<TextView android:fontFamily="cursive" android:text="java" />

<TextView android:fontFamily="cursive" android:text="java" android:useBoundsForWidth="true" android:shiftDrawingOffsetForStartOverhang="true" />

<TextView android:text="คอมพิวเตอร์" />

<TextView android:text="คอมพิวเตอร์" android:useBoundsForWidth="true" android:shiftDrawingOffsetForStartOverhang="true" />
ارتفاع خط پیشفرض حساس به زبان برای EditText
در نسخههای قبلی اندروید، طرحبندی متن، ارتفاع متن را به اندازه ارتفاع خط فونتی که با منطقه فعلی مطابقت دارد، افزایش میداد. به عنوان مثال، اگر محتوا به زبان ژاپنی بود، چون ارتفاع خط فونت ژاپنی کمی بزرگتر از فونت لاتین است، ارتفاع متن کمی بزرگتر می شد. با این حال، علیرغم این تفاوتها در ارتفاع خط، عنصر 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 مراجعه کنید.