Всем приложениям, опубликованным в Google Play, до 31 августа 2023 года надо поддержать Android 13 в своих приложениях, т.е. поднять targetSdk до значения 33. В этом году сроки для обновления новых и уже опубликованных приложений объединили в один дедлайн. Я потратил несколько дней, чтобы разобрать все самые важные изменения и полезные фичи Android 13, чтобы упростить вам процесс миграции.
Если вам интересно следить за самыми последними новостями Android разработки и получать подборку интересных статей по этой тематике, тогда вам стоит подписаться на Телеграм-канал Android Broadcast и мой YouTube канал "Android Broadcast"
Улучшенная поддержка планшетов и больших экранов
Google еще c выходом Android 12L показала важность адаптации приложений под планшеты, складные устройства и большие экраны. В Android 13 были добавлены все наработки по улучшению UI/UX для планшетов и больших экранов из Android 12L, а также добавлены новые. Теперь системный UI лучше выглядит на больших экранах; улучшили работу с многозадачностью, добавив Task Bar, чем-то похожи на панель с приложениям в macOS и Windows; появился полноценный разделенный экран и др. улучшения.
Чтобы все это работало хорошо, начиная с Android 12L, поддержка режима многооконности для всех приложений была включена по умолчанию. Если ваше приложение этого не поддерживает, то придется это явно указать в AndroidManifest. От разработчиков требуется проверить, как ваше приложения будет работать в режиме “Split Screen”. Как это сделать, вы найдете в официальной документации.
Task Bar позволяет пользователям быстро запускать и переключаться между приложениями, перетаскивать их для входа в режим разделения экрана и проводить свайп вверх, чтобы вернуться на главный экран.
![Использование Task Bar Использование Task Bar](https://habrastorage.org/getpro/habr/upload_files/4ee/d0b/f6f/4eed0bf6f962cd18785b5052d4cab908.gif)
Информация о Task Bar для приложения сообщается через Inset. При использовании навигации жестами Task Bar может показываться или скрываться динамически. Если ваше приложение отрисовывает UI на основе Inset-ов окна, учтите, что тогда размер отступов может меняться пока приложение показывается на экране. Чтобы все корректно работало и дальше, вам надо будет подписаться на обновления отступов в окне и реагировать на это в UI вашего приложения.
ViewCompat.setOnApplyWindowInsetsListener(view) { view, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures())
// Применяем изменение Inset к UI вашего окна
}
Режим Совместимости
Приложения, которые не адаптированы для работы на больших экранах, будут запускаться в режиме совместимости. В эту категорию попадают приложения, которые поддерживают только портретную ориентацию или явно отказались от поддержки больших экранов в AndroidManifest.
![Пример работы режима совместимости Пример работы режима совместимости](https://habrastorage.org/getpro/habr/upload_files/9d3/e28/674/9d3e28674614f762861cfb65a014fe98.png)
В режиме Совместимости производители устройства будут задавать какое-то стандартное соотношение сторон, делать закругления окна приложения и задавать прозрачность status bar. Разработчикам надо проверить корректность работы и вида приложения в режиме Совместимости.
Улучшена поддержка стилусов
Стилус - популярный способ работы на больших экранах, но пользователь может случайно касаться экрана рукой при его использовании. До Android 13 движения пальцами заканчивались отправкой MotionEvent с ACTION_CANCEL, но начиная с новой версии ОС поведение меняется. Если экрана касались только рукой, тогда завершающий MotionEvent будет содержать ACTION_CANCEL
и FLAG_CANCELED
, но если есть другие указатели на экране - будет задано ACTION_POINTER_UP
и FLAG_CANCELED
.
// До Android 13
MotionEvent(action = ACTION_CANCEL, flags = FLAG_CANCELED)
// Android 13+. Убрали все указатели с экрана
MotionEvent(action = ACTION_CANCEL, flags = FLAG_CANCELED)
// Android 13+. Убрали палец с экрана но стилус остался
MotionEvent(action = ACTION_POINTER_UP, flags = FLAG_CANCELED)
Помимо прочего адаптировали Google приложения для больших экранов и складных устройств, а также не забыли и про ChromeOS. Сортировка контента в магазине теперь будет идти с учетом выполнения гайда по качеству приложения для больших экранов.
Помимо этого, выпустили много новых API в Jetpack, например, появилась библиотека Jetpack WindowManager, которая позволяет встраивать Activity в UI вашего приложения (называется Activity Embedding). Нечто подобное было давно в Android до прихода Fragment, а вот сейчас вернули снова, но уже в новом варианте
![Пример работы приложения с Activity Embedding Пример работы приложения с Activity Embedding](https://habrastorage.org/getpro/habr/upload_files/2df/e63/a23/2dfe63a239cee83605264bc93a8267be.png)
Google явно прилагает много усилий для лучшей работы Android ОС на планшетах и больших экранах, особенно что не за горами выход фирменного планшета компании - Pixel Tablet.
![Pixel Tablet Pixel Tablet](https://habrastorage.org/getpro/habr/upload_files/e22/5e6/4f0/e225e64f02210bd756cf9e0befadb09b.png)
Разрешение для показа уведомлений
В Android 13 и новее для показа уведомлений придется запросить новое разрешение POST_NOTIFICATIONS. Это поведение идентично тому, как уже давно было на iOS. Рассказывать, как запрашивать разрешения, я вам не буду, функционал с нами уже с 2015 года, но вот есть несколько рекомендаций, когда стоит показывать запрос на показ уведомлений, например, когда пользователь выполняет действие, для которого важен показ уведомлений.
Изменение будет работать для всех приложений, независимо от targetSdk, но есть несколько отличий:
Для приложений с targetSdk = 33 и выше, разработчик сам отвечает за проверку разрешения и его запрос
Для приложений с targetSdk ниже 33, которые были установлены на устройстве при обновление на Android 13, разрешение на показ уведомлений выдадут автоматически, но оно будет сброшено при удалении приложения. Важно, чтобы у вашего приложения уже должен быть создан хотя бы один канал уведомлений и пользователь не отключил все уведомления в вашем приложении.
Все новые устанавливаемые приложения с targetSdk ниже 33 будут показывать диалог с запросом на показ уведомлений при первом запуске любой Activity приложения и создании первого канала уведомлений. Обычно это делают в Application.onCreate()
Нововведение касается показа всех уведомлений, включая Foreground Service, но есть исключения. Уведомления, связанные с медиа сессией, будут показываться вне зависимости от состояния разрешения, а также приложения, которые самостоятельно управляют звонками, смогут показывать уведомления, которые используют Notification.CallStyle.
Стандартный Photo Picker
В Android 13 добавили стандартный компонент, который предоставляет возможность обзора и поиска фотографий пользователя как на устройстве, так и в облаке, например, Google Photos. Новый компонент позволит предоставлять пользователю доступ к своим фото, а приложения не будут иметь доступ ко всем файлам пользователя, а только к фото и видео, которые он сам решит предоставить.
Важной особенностью Photo Picker является то, что он будет доступен на Android 11, благодаря модульной системе компонентов. Важно, устройство должно получить эти новинки через систему обновлений Google Pllay Services.
![Пример работы Photo Picker Пример работы Photo Picker](https://habrastorage.org/getpro/habr/upload_files/5df/e9e/0d1/5dfe9e0d1d9b50ab85e5361188548b86.png)
Jetpack Activity 1.6.1 уже содержит Activity Result API контракты PickVisualMedia и будет выбирать наилучший вариант, доступный на устройстве. В случае если Photo Picker недоступен на устройстве, то будет вызван Intent с ACTION_OPEN_DOCUMENT.
// Регистрируем Activity Result для получения фото
// Откроется Photo Picker (если доступен) или Document Provider
val pickMedia = registerForActivityResult(PickVisualMedia()) { uri ->
// Обрабатываем результат
}
// Запуск для выбора фото и видео
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageAndVideo))
// Запуск для выбора только фото
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly))
// Запуск для выбора только видео
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.VideoOnly))
// Выбираем меди только указанного MIME типа
pickMedia.launch(
PickVisualMediaRequest(PickVisualMedia.SingleMimeType("image/gif"))
)
Чтобы проверить доступность Photo Picker, можно вызвать метод isPhotoPickerAvailable() либо воспользоваться Android SDK Extensions.
// Проверка доступности Photo Picker
fun isPhotoPickerAvailable(): Boolean {
when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> true
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R ->
SdkExtensions.getExtensionVersion(Build.VERSION_CODES.R) >= 2
else -> false
}
Выбор языков для приложений
![Выбор языка для приложения в Android 13 Выбор языка для приложения в Android 13](https://habrastorage.org/getpro/habr/upload_files/9f4/548/1b1/9f45481b15f450751a688a83e9c6204c.png)
В Android 13 появилась возможность выбрать язык приложения отдельного от установленного в системе. В системных настройках у приложения вы сможете найти пункт “Язык приложения”. Это еще одна из возможностей, заимствованная из iOS
Эта опция появится только для приложений, которые поддержали эту фичу. Для этого в AndroidManifest вашего приложения вы должны добавить атрибут android:localeConfig
, который будет ссылаться на XML ресурс с перечислением поддерживаемых вашим приложением локалей
<!-- res/xml/locale_config.xml -->
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
<locale android:name="en" />
<locale android:name="en-GB" />
<locale android:name="fr" />
<locale android:name="ja" />
<locale android:name="zh-Hans-MO" />
<locale android:name="zh-Hant-MO" />
</locale-config>
<!-- AndroidManifest.xml -->
<manifest>
...
<application
...
android:localeConfig="@xml/locales_config">
</application>
</manifest>
Также будет полезно добавить и поддерживаемые локали в Gradle, чтобы ненужные ресурсы не попадали в финальную сборку. Подробнее про этот прием я рассказывал в видео про уменьшение размера APK
android {
...
defaultConfig {
resourceConfigurations += ["en", "en-rGB", "fr", "ja", "b+zh+Hans+MO", "b+zh+Hant+MO"]
}
}
Было бы конечно удобнее все сделать из коробки и чтобы разработчикам не надо было включать возможность. Ведь определить поддерживаемые языки можно по локалям, для которых есть строки в ресурсах приложения. Это не так. Многие приложения не заботятся о том, чтобы удалить ресурсы строк из неподдерживаемых локалей, а также библиотеки могут туда что-то положить. Поэтому без информации от разработчика, какие локали поддерживаются приложением, корректной работы фичи не получается.
Чтобы корректно получать текущую локаль, добавили новый системный сервис - LocaleManager, который позволяет получить текущие системные локали, локали для вашего или другого приложения, а также поменять локали приложения из кода.
// LocaleManager доступен на Android 13+ (API Level 33+)
val localeManager: LocaleManager = context.getSystemService()
// Список локалей для текущего приложения
val appLocales: LocaleList = localeManager.getApplicationLocales()
// Спиоск локалей выбранных в системе
val systemLocales: LocaleList = localeManager.getSystemLocales()
Возможно, вы уже реализовали собственный выбор языка в приложении, но рекомендуется миграция на стандартный UI. Для Android 12 и ниже вам придется реализовать UI самостоятельно, но зато в AppCompat 1.6.0 в классе AppCompatDelegate появились методы для получения и задание значения локалей, которые работают с аналогом системного API, либо могут запоминать выбранные значения на Android 12 и ниже. Для этого вам надо в манифесте добавить специальный сервис
// Код работает на всех версиях Andoid, поддеживаемы Jetpack
// Получаем актуальные локали приложения
val appLocales: LocaleListCompat = AppCompatDelegate.getApplicationLocales()
// Задаем новые локали
val newLocales = LocaleListCompat.create("ru", "en")
AppCompatDelegate.setApplicationLocales(newLocales)
<application>
...
<service
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
android:enabled="false"
android:exported="false">
<meta-data
android:name="autoStoreLocales"
android:value="true" />
</service>
...
</application>
Также важно учитывать настройки языка приложения при работе с API, которым необходимо передавать локаль: Accept-Language Header при открытии Web контента или при распознавании речи с помощью Speech Recognizer API.
Predictive Back Gesture
![](https://habrastorage.org/getpro/habr/upload_files/d74/f56/4f2/d74f564f2510cde8f513ac95ed071f80.gif)
В Android 13 представили новую систему навигации назад под названием Predictive Back Gesture, которая будет показывать превью экрана, на который будет сделан переход при жесте назад. Пользователь сможет решить, нужно ли ему перейти или остаться на текущем экране.
В Android 13 добавится лишь API и поддержка, а переход на новую систему навигации будет осуществлен в Android 14. Протестировать систему можно и на Android 13 через настройки разработчика, а в манифесте вашего приложения вы можете выставить, что поддерживаете Predictive Back Gesture
<application
...
android:enableOnBackInvokedCallback="true"
... >
</application>
Теперь разработчикам вместо переопределения Activity.onBackPressed() и обработке события нажатия KeyEvent.KEYCODE_BACK на Android 13 и выше надо будет использовать новое платформенное API - OnBackInvokedCallback. Если вы уже успели мигрировать на OnBackPressedCallback из Jetpack, то в AppCompat 1.6.0 уже под капотом сделали миграцию на новое платформенное API и вам ничего менять не придется
class MyActivity : AppCompatActivity() {
@Override
fun onCreate() {
if (BuildCompat.isAtLeastT()) {
onBackInvokedDispatcher.registerOnBackInvokedCallback(
OnBackInvokedDispatcher.PRIORITY_DEFAULT // или PRIORITY_OVERLAY
) {
// Обрабатываем нажатие назад
}
}
}
}
// AndroidManifest.xml
<application
...
android:enableOnBackInvokedCallback="true"
... >
...
</application>
Foreground Service Task Manager
![Foreground Task Manager в Android 13 Foreground Task Manager в Android 13](https://habrastorage.org/getpro/habr/upload_files/154/64f/fe1/15464ffe166ffd242157c0f2f8cca7f4.png)
Теперь из системной панели уведомлений пользователь сможет остановить любой запущенный Foreground Service, независимо от targetSdk приложения. Это меню назвали Task Manager и он показывает список всех приложений с запущенными Foreground Service, рядом с каждым приложением в списке есть кнопка “Остановить”
Остановка приложения таким образом нечто среднее между удалением его из меню “Недавнее” и принудительной остановкой из раздела информации о приложении, а именно:
приложение удаляется из памяти
очищается back stack activity
останавливается воспроизведение медиа
уведомление, связанное с Foreground Service, будет убрано
приложение остается в истории
Запланированный Job будут выполняться
Все запланированные вызовы через AlarmManager сработают
FGS Task Manager | Удаление из Recent | Force Stop | |
---|---|---|---|
Незамедлительное удаление приложения из памяти | ✅ | ❌ | ✅ |
Остановка воспроизведения медиа | ✅ | ❌ | ✅ |
Остановка Foreground Service | ✅ | ❌ | ✅ |
Удаление Activity Back Stack | ✅ | ✅ | ✅ |
Удаление приложения из истории | ❌ | ✅ | ✅ |
Запланированные Job отменены | ❌ | ❌ | ✅ |
Alarm отменяются | ❌ | ❌ | ✅ |
Некоторые приложения не будут отображаться в Task Manager, а для других не будет показываться кнопка “Остановить”, например, для приложения звонилки или приложения, связанного с EMM.
Также благодаря этому изменению уведомления, связанные с Foreground Service, можно убрать из панели уведомлений. Если вы этого не хотите, то при создании объекта Notification, пометьте его как ongoing.
Notification.Builder(context)
// Задаем уведомление как текущее, которое не может быть удалено
.setOngoing(true)
// ...
.build();
Прокачали использование батарейки
Система App Standby Bucket появилась еще в Android 9 и развивается. В Android 13 сделали строже правила, когда приложения попадет в Restricted App Standy Bucket, независимо от targetSdk:
Пользователь не взаимодействовал с приложением 8 дней и больше (на Android 12 - это было 45 дней). Считаются только дни когда устройство не выключено
Приложение выполняет слишком много байндингов к Services или слишком часто отправляется broadcast-ы в течение 24 часов
Приложение потребляет слишком много батарейки в течение 24 часов
Что значит попасть в restricted bucket:
Выполнение задач в JobScheduler и WorkManager будет возможность один раз в день в течение 10 минут, во время которых будут также выполняться задачи других приложений
Уменьшается возможное количество запускаемых expedited jobs
Приложение сможет выполнять только один alarm в течение дня, независимо, задан в точное время или нет
Если пользователь начнет взаимодействовать с приложением, тогда система переместит приложение в другую корзинку.
Часть приложений попадают в исключение и не попадут под ограничения, когда из функции или смысл работы подразумевают это. Полный список исключений вы можете найти по ссылке
Уведомление о слишком активном использовании батареи
Если приложение будет потреблять слишком много энергии в пределах 24-часового окна, то система покажет уведомление “приложение слишком сильно расходует энергию”. Android 13 рассчитывает расход батарейки в фоне на основе работы Foreground и Background Service (если вы все еще сможете такие использовать), JobScheduler/WorkManager и BroadcastReceiver-ы.
За время использования Android 13 я не нашел приложения, которые приведут к показу такого уведомления. Видно его реально увидеть только для совсем зловредных приложений.
Превью контента в буфере обмена
![Пример системного уведомления при изменение контента в буфере обмена Пример системного уведомления при изменение контента в буфере обмена](https://habrastorage.org/getpro/habr/upload_files/a2d/f61/017/a2df61017f4f0d5b10fc98de5ad3c682.gif)
Теперь при копировании чего-либо в буфер обмена будет автоматически показываться превью содержимого и предлагаться действия с ним.
Если вы что-то из кода добавляете в буфер обмена, вы должны учитывать, что все содержимое будет показано на экране. Если вы этого не хотите, тогда помечайте содержимое как чувствительный с помощью специального флага EXTRA_IS_SENSITIVE
// Android 13+ (API Level 33+)
clipData.apply {
description.extras = PersistableBundle().apply {
putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true)
}
}
Новое разрешение для Wi-Fi устройств поблизости
Если вам приходилось работать с устройствами в Wi-Fi сети (nearby), то разработчикам надо было запросить разрешение ACCESS_FINE_LOCATION на доступ к геолокации. В Android 13 появилось отдельное разрешение NEARBY_WIFI_DEVICES, которое позволит работать с устройствами в Wi-Fi сети.
<manifest ...>
<!-- Старое разрешение. Используем до Android 13 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- Новое разрешение. Используем на Android 13+ -->
<uses-permission
android:name="android.permission.NEARBY_WIFI_DEVICES"
android:usesPermissionFlags="neverForLocation"
/>
</manifest>
Новое разрешение попадает в группу NEARBY_WIFI_DEVICES, в которую также попадают и разрешения на доступ к Bluetooth и Ultra-wideband. Это значит, что при запросе или отзыве любого из них, будет выдаваться доступ или отзываться для всех разрешений в группе.
Для части Wi-Fi API все также придется запрашивать доступ к местоположению. Полный список всех API, которым будет достаточно нового разрешение, вы можете найти по ссылке
Новые иконки приложений
![](https://habrastorage.org/getpro/habr/upload_files/9da/856/27f/9da85627f7e91f1e1206632bc2ddaeca.png)
В Android 13 продолжают развитие Material You, добавляя тематические иконки приложений. Такие иконки смогут перекрашиваться в цвета из системной темы.
В дополнении к уже всем существующим иконкам (обычная, круглая и адаптивная) приложениям надо будет добавить монохромную картинку, хорошо, что это сделали простым добавлением тэга monochrome
в адаптивной иконке
![](https://habrastorage.org/getpro/habr/upload_files/928/94d/a72/92894da728b3de3e0b1f2dbb84b33a58.png)
Новая иконка будет показываться в случае, если пользователь явно включит их в поддерживаемом лаунчере. Не все разработчики озаботились тем, чтобы добавить такую иконку и не факт, что сделают быстро, поэтому скорее всего вы будете видеть странный микс из темизированных иконок и нет.
Очень странная фича, так как разработчики точно не будут спешить с ее реализацией в приложениях, если конечно Google Play не станет давить на разработчиков. А они только форсируют targetSdk и функции касательно безопасности
OpenJDK 11
В Android 13 стали переносить возможности из OpenJDK 11 LTS, как API из JDK, так и фичи языка. Они также будут перенесены через Google Play Services на Android 12, благодаря системе модульных компонентов.
Что именно теперь станет доступно:
Ключевое слова
var
для объявления локальных переменных и параметров лямбдНовое API в классе String
Обновление Collection Stream API
Обновление Java Util Concurrent
и множество других API
C одной стороны - это хорошо, но для прикладных разработчиков толку не так много. Кто еще пишет приложения на Java? Уже все разработчики давно перешли на Kotlin. Тем, кто разрабатывает форки Android или сам Android, точно станет лучше.
android {
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
}
Новое разрешение для использование AlarmManager
В Android 12 представили специальное разрешение для установки точных будильников через AlarmManager - SCHEDULE_EXACT_ALARM, которое выдается автоматом приложениям и может быть отозвано через системные настройки. В Android 13 появляется новое разрешение на замену USE_EXACT_ALARM. Отозвать такое разрешение пользователь уже не сможет, но чтобы опубликовать с ним приложение в Google Play, вам придется пройти специальное ревью и доказать, что ваше приложение не сможет работать без него. Например, будильник, таймер или календарь. Политика вступает в действие с 31 июля 2023.
<manifest ...>
<!-- Используем на Android 13 и новее. Выдаётся автоматом -->
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
<!-- Используем если не подходит новое разрешение -->
<!-- Разрешение может быть отозвано пользователем -->
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
</manifest>
На Android 13 и новее старое разрешение SCHEDULE_EXACT_ALARM больше не будет выдаваться автоматом. Вы всё также можете использовать его для тех случаев, когда опубликоваться с USE_EXACT_ALARM у вас не получиться, но вам надо будет явно просить пользователя выдавать его через системные настройки, а также не забывайте, что его могут отозвать в любой момент.
JobScheduler
Начиная с Android 13, в JobScheduler можно будет указывать приоритет для запускаемой задачи. Эта информация будет использоваться для выбора наиболее важных задач для выполнения в пределах всех задач приложения, а не между приложениями.
Есть возможность выбрать один из 5 приоритетов
PRIORITY_MIN
Для задач, результат которых пользователь не ожидает или вовсе не знает про них, например, загрузка аналитики. Может быть отложено, чтобы обеспечить достаточную квоту для задач более высокого приоритета.PRIORITY_LOW
Для задач, представляющие минимальную пользу для пользователя, например, предварительная загрузка данных, которые пользователь явно не запрашивал. Такую работы все еще можно отложить, чтобы гарантировать достаточную квоту для задач с приоритетом выше.PRIORITY_DEFAULT
Приоритет по умолчанию для всех задач. Максимальное время выполнение - 10 минут и стандартные правила по управлению задачей, как было раньше.PRIORITY_HIGH
: Для задач, которые должны выполняться, чтобы пользователь не подумал, что что-то идет не так. Такие задачи имеют максимальное время выполнения - 4 минуты при условии, что все ограничения выполнены и система находится в нагрузке. которая позволяет её выполнить.PRIORITY_MAX
: Для задач, которые должны выполняться в первую очередь, например, обработка текстового сообщения для отображения уведомления. Только Expedited Jobs могут использовать такой приоритет.
На момент выхода этой статьи стабильным является WorkManager 2.8.0 и возможность явного задания приоритетов туда не перенесли.
В Android 9.0 появилась возможность пометить Job как ”prefetch”, т.е. предзагрузка данных, которая в идеале должна как можно ближе и до следующего запуска приложения. Раньше никак не учитывалось лучшее время запуска для такой Job, а лишь ее расход данных. Начиная с Android 13, система будет пытаться прогнозировать следующий запуск приложения и оценить время на выполнение задач, чтобы запускать задачу в наиболее подходящее для этого время.
JobInfo.Builder(...)
.setPrefetch(boolean)
// Настраиваем Job
.build()
Программируемые шейдеры
![](https://habrastorage.org/getpro/habr/upload_files/f76/cc1/511/f76cc151146a550de328846e5cf80964.gif)
В Android 13 появилась возможность использовать программируемые шейдеры для создания сложных эффектов. Появился новый класс - RuntimeShader. Например, на их основе в Android работает ripple эффект при нажатии кнопок, блюр, а также другие эффекты в UI. Для описания шейдера используется Android Graphics Shading Language (AGSL), который очень похож на GLSL, но способен работать андройдовским движком рендеринда и может фильтровать контент внутри View.
void mainImage(out vec4 Color, in vec2 Coord)
{
vec2 Pos = (Coord-.5*iResolution.xy)/iResolution.y;
float Size = 0.25;
float Dist = length(max(abs(Pos)-Size,0.));
float Glow = 1./(Dist*25.+.5);
Color = vec4(Glow*vec3(.4,1,.1),1);
}
Вы можете попробовать создать собственные шейдеры в песочнице на сайте shadertoy.com и потом перенести их в Android приложения.
Любители iOS копирования теперь могут порадоваться, ведь сделать размытие, как в яблочной ОС, теперь можно будет очень дешево по ресурсам для системы.
Пожалуйста, не копируйте дизайн iOS 🙏
Обновление ART
Как и каждый выход новой версии ОС, виртуальную машину ART улучшают, но вот, что именно сделали, говорят мало. В Android 13 в ART поработали над ускорением вызова нативного (C/C++) кода и он стал выполняться до 2.5 раз быстрее (информация Google) по сравнению с тем, что было до обновления ОС на одном и том же устройстве.
Обработка ссылок на объекты во время работы приложения было переработано и стало быстрее, и стало неблокирующим в большей части случаев. Помимо этого, появилось новое публичное API Reference.refersTo(), которое позволяет удалить из памяти недостижимые объекты раньше, чем это сделает сборщик мусора. Интерпретатор стал быстрее, благодаря оптимизации поиска классы и методы. В дополнении к этому ART часть проверок байткода теперь выполняются при установке приложения, а не во время старта или при выполнении кода.
Самым большим изменением в ART стал новый механизм сборки мусора, основанный на userfaultd фиче Linux ядра. Это позволило сделать существующий механизм GC эффективнее и быстрее. Благодаря тому, что ART стал Mainline модулем в Android 12, обладатели предыдущей версии Android также получат улучшенную виртуальную машину.
Также было улучшено управление памятью. Для этого Google разработала новая LRU стратегия управления страницами в памяти c множеством поколений
Некоторые операции стали до 40% меньше использовать процессор, реже стали вычищаться объекты при нехватке памяти, а старт приложений в половине запусков стал быстрее на 18%. Новая стратегия управлению памяти будет влита в основную ветку разработки Linux ядра. Если вы хотите больше узнать про то, как происходит управление виртуальной памятью в Linux ядре и как работает LRU стратегия со множеством поколений, то можете почитать статью.
Отдельные разрешения на доступ к медиа
Появились отдельные разрешения на доступ к видео, аудио и одно разрешение на доступ к фото и картинкам, которые призваны уменьшить количество приложений, которые READ_EXTERNAL_STORAGE.
// Доступ к картинкам
READ_MEDIA_IMAGES
// Доступ к видео
READ_MEDIA_VIDEO
// Доступ к аудио
READ_MEDIA_AUDIO
![Пример запроса разрешения на доступ только к музыке и аудио на устройстве Пример запроса разрешения на доступ только к музыке и аудио на устройстве](https://habrastorage.org/getpro/habr/upload_files/126/82a/272/12682a2725e1ef076dd5ce4bc34a6454.png)
Если ранее вы уже получили разрешение READ_EXTERNAL_STORAGE, то при обновлении системы до Android 13 все новые отдельные разрешения на доступ к медиа будут выданы приложению.
Пока этого еще не было объявлено, но я думаю в какой-то момент в политиках ревью Googlе Play появится пункт, который заставит использовать разработчиков Photo Picker и усложнит приложениям публикацию в магазине приложений с разрешениями на полный доступ к файловой системе.
Изменения в получении разрешений
Для доступа к сенсорам состояния тела (сердцебиение, температура, воздух в крови и др.) приложениям из фона в дополнение к разрешению BODY_SENSORS, надо будет получить новое разрешение BODY_SENSORS_BACKGROUND
Приложения, которые используют рекламный ID из Google Play Services теперь должны запрашивать разрешение AD_ID, которое выдается приложению без запроса у пользователя. Если разрешение не будет запрошено приложением с targetSdk 33 и выше, тогда рекламный id будет возвращать строку из нулей. Вполне возможно для корректной работы рекламные SDK будут объявлять это разрешение и оно попадет в конечный манифест приложения, так что вам не придется его добавлять самостоятельно. Если хотите узнать, как это работает и управлять процессом мержа манифестов, то я рассказывал об этом в этом видео
Появился специальный доступ, чтоб разрешить приложениям включать экран устройства. Появилось новое разрешение READ_BASIC_PHONE_STATE, которое является урезанной версий READ_PHONE_STATE и подходит для тех случаев, когда вам надо получить тип текущей сети у пользователя. Это разрешение выдается приложению при установке.
![](https://habrastorage.org/getpro/habr/upload_files/00b/883/1c4/00b8831c48770d3781f49c5b5ed3f606.png)
Строгое совпадение Intent
Зачастую intent-filter
в манифесте объявляется с action
и category
, но раньше было достаточно отправить intent, совпадающий по action. Теперь на Android 13 для всех приложений с targetSdk 33 и выше broadcast-ы будут доставляться приложению, только если у них совпадает action и category из <intent-filter>.
<activity android:name="MainActivity" android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>
// Работает до Android 13 или приложений с targetSdk < 33
val sendIntent = Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_TEXT, textMessage)
type = MimeType.TEXT_PLAIN
}
startActivity(sendIntent)
// Работает на всех версиях Android
val sendIntent = Intent().apply {
action = Intent.ACTION_SEND
categroy = Intent.CATEGORY_DEFAULT
putExtra(Intent.EXTRA_TEXT, textMessage)
type = MimeType.TEXT_PLAIN
}
startActivity(sendIntent)
Работает на Android 13 для всех приложений
Есть исключения из правила:
Intent, отправленный из этого же приложения
Intent, отправляемый в компонент без intent фильтров
Intent, отправленный из системного приложения
Intent, отправленный от root
Ограничение скорости сети
![Установка ограничения скорости передачи данных по сети Установка ограничения скорости передачи данных по сети](https://habrastorage.org/getpro/habr/upload_files/ae4/ad4/389/ae4ad4389158f1032aff1a634a9c1bf1.png)
В настройках разработчика появилась важная возможность для тестирования приложений - ограничение скорости любой сети, которые могут предоставлять выход в интернет. Эта фича позволит вам лучше проверить работу вашего приложения в условиях сетей с низкой скоростью без каких-либо танцев с бубном с проксями
Ограничения доступа к Accessibility Services
![Пример получения доступа в Accessibility Services для приложения, установленного не из магазина приложений Пример получения доступа в Accessibility Services для приложения, установленного не из магазина приложений](https://habrastorage.org/getpro/habr/upload_files/9c8/143/ee2/9c8143ee2ec4c46a2b922e9cfa3c55e9.png)
Использование Accessibility Services даёт разработчикам неограниченные возможности по отслеживанию того, что происходит на экране и в системе. Этим могли пользоваться злоумышленники. В Android 13, чтобы ограничить эту уязвимость, запретили использовать Accessibility Services для всех приложений, которые установлены не из магазинов приложений. Установка засчитывается как из Google Play, так и из альтернативных магазинов.
Для корректной установки приложения магазины используют Package Manager Session API. Браузеры, файловые менеджеры и другие приложения, как правило, используют обычное API для установки. Так и определяется, что приложение установлено из магазина. Использовать оба API для установки могут все, поэтому злоумышленники найдут способ обойти ограничение, но им однозначно становится сложнее.
Изменение сделано с целью того, что Google хочет, чтобы приложения, которые получают такой доступ, проходили проверку. При попытке включения доступа для загруженного из вне приложения пользователь увидит предупреждение о недоступности настройки для приложения. Но у пользователя все равно есть возможность разрешить доступ явно, просто это стало сложнее.
Прочие изменения
В Android 13 произошло множество изменений, не все из которых заслуживают полноценного разбора, но точно стоит озвучить. Поехали!
Добавлена поддержка Bluetooth Low Energy Audio, для прослушивания музыки с меньшим потреблением энергии на поддерживаемых устройствах
Добавлена поддержка MIDI 2.0 с возможностью подключения устройств по USB. Это изменение оценят те, кто занимается музыкой
Добавлена поддержка статического пространственного звука и динамического с отслеживанием движения головы. В AudioManager API появились соответствующие методы для работы с таким типом звука. Jetpack Media3 и ExoPlayer уже имеют поддержку пространственного аудио
Audio Routing API - AudioManager теперь позволит определить, на каком из подключенных устройств можно воспроизвести заданное аудио
Появилась API, которое позволит быстро добавить элементы в быстрые настройки. Называется Quick Settings Placement API. Если ваше приложение содержит собственные тайлы для настроек - это хороший способ предложить пользователю начать их использовать.
Разработчики смогут отзывать разрешения, которые больше не используются. После отзыва процесс приложения будет убит. Система сама выберет лучшее время для этого. Если знаете, как это реально применить, то пишите в комментариях к этой статье. Кроме как похвастаться пользователю, что вы отказались от ранее выданных разрешений, я не вижу
Поддержана новая схема подписи APK Signature Scheme v3.1, которая исправила несколько проблем в v3. Она несовместима с предыдущей версий и будет работать только на Android 13 и выше
Bluetooth стек в Android стал Mainline модулем, а это значит, что он сможет обновляться независимо от Android системы и новые фичи из будущих версий ОС, связанные с этой беспроводной технологией, мы увидим и в Android 13. Также mainline модулем стал ultra-wideband стек
Neural Network API должен был стать Mainline модулем еще в Android 12, но это реализовали только в Android 13.
Улучшили Динамическую Систему Обновления. Она стала быстрее и теперь пользователь сможет увидеть, какой раздел именно сейчас обновляется.
Добавлена поддержка exFAT, файловой системы, которая используется современным Flash накопителям и не имеет ограничений FAT32
Добавили новое “cross device calling” API, которое позволяет отправить звонок на удаленный сервер или переадресовать его на другие устройства, например, Android планшет
Появилась возможность создавать виртуальные аудио устройства для захвата аудио или подкидывания микрофона
При попытке считать логи пользователю будет показываться диалог, в котором он должен будет подтвердить доступ приложения к ним
Квоты на доставку высокоприоритетных пушей через Firebase Cloud Messaging отвязали от системы App Standby Buckets
Тема приложения теперь будет автоматически применяться к Web контенту, если не будет явного задания прочего. Методы setForceDark() из WebSettings стал deprecated. Изменение применяется только для приложений с targetSdk 33
Если приложение будет помещено в "restricted" App Standby Bucket, то система не будет доставлять броадкасты
BOOT_COMPLETED
иLOCKED_BOOT_COMPLETED
. Изменение применяется только для приложений с targetSdk 33Скорость работы переноса слова была увеличена в 2 раза, улучшили поддержку китайского и японского языка, также теперь для нелатинских языков размер линии будет адаптирован для каждого языка. Помимо этого, обновили библиотеки Unicode до самых свежих версий
Автоматическая очистка буфера обмена. По умолчанию стоит значение в 60 минут
Кнопки для управления медиа сессией теперь задаются не через уведомление в MediaStyle, а берутся из PlaybackState. Это по умолчанию будет работать для всех приложений, независимо от targetSdk
В быстрых настройках появились отдельные выключатели на доступ всех приложений к камере и микрофону
Реализована базовая поддержка Wi-Fi 7
Gabeldorsche Bluetooth stack теперь стал работать по умолчанию
Появился новый композитный сенсор TYPE_HEADING, который показывает направление относительно истинного севера на основе акселерометра и сенсора геомагнитного поля
Улучшения камеры: стабилизация превью, поддержка записи в 60FPS, уменьшена дрожь видоискателя, добавлено API по управлению яркостью вспышки
У Activity появился новый метод setRecentsScreenshotEnabled(), который запрещает создавать скриншот для превью в меню “последних” запущенных приложений. Система может использовать фон окна, чтобы создать превью. Это опция дополняет FLAG_SECURE в класс Window.
Все BroadcastReceiver, зарегистрированные из кода во время работы приложения, должны явно указывать, доступны они из вне или нет. Для этого при их регистрации надо добавить флаг RECEIVER_EXPORTED или RECEIVER_NOT_EXPORTED.
Для подготовки этой статьи я использовал официальную документацию, а также разбор Android 13 от Mishaal Rahman. В его блоге вы сможете найти более скурпулезный обзор всех изменений в этой версии ОС и много полезных материалов по Android под капотом.
Делитесь своим мнением о новых фичах в Android 13 и опытом миграции на актуальную версию Android в комментариях к статье