Всем приложениям, опубликованным в 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

Информация о Task Bar для приложения сообщается через Inset. При использовании навигации жестами Task Bar может показываться или скрываться динамически. Если ваше приложение отрисовывает UI на основе Inset-ов окна, учтите, что тогда размер отступов может меняться пока приложение показывается на экране. Чтобы все корректно работало и дальше, вам надо будет подписаться на обновления отступов в окне и реагировать на это в UI вашего приложения.

ViewCompat.setOnApplyWindowInsetsListener(view) { view, windowInsets ->
    val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures())
    // Применяем изменение Inset к UI вашего окна
}

Режим Совместимости

Приложения, которые не адаптированы для работы на больших экранах, будут запускаться в режиме совместимости. В эту категорию попадают приложения, которые поддерживают только портретную ориентацию или явно отказались от поддержки больших экранов в AndroidManifest.

Пример работы режима совместимости
Пример работы режима совместимости

В режиме Совместимости производители устройства будут задавать какое-то стандартное соотношение сторон, делать закругления окна приложения и задавать прозрачность 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

Google явно прилагает много усилий для лучшей работы Android ОС на планшетах и больших экранах, особенно что не за горами выход фирменного планшета компании - Pixel Tablet.

Pixel Tablet
Pixel Tablet

Разрешение для показа уведомлений

В 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

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

В 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

В 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

Теперь из системной панели уведомлений пользователь сможет остановить любой запущенный 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 я не нашел приложения, которые приведут к показу такого уведомления. Видно его реально увидеть только для совсем зловредных приложений.

Превью контента в буфере обмена

Пример системного уведомления при изменение контента в буфере обмена
Пример системного уведомления при изменение контента в буфере обмена

Теперь при копировании чего-либо в буфер обмена будет автоматически показываться превью содержимого и предлагаться действия с ним.

Если вы что-то из кода добавляете в буфер обмена, вы должны учитывать, что все содержимое будет показано на экране. Если вы этого не хотите, тогда помечайте содержимое как чувствительный с помощью специального флага 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, которым будет достаточно нового разрешение, вы можете найти по ссылке

Новые иконки приложений

В Android 13 продолжают развитие Material You, добавляя тематические иконки приложений. Такие иконки смогут перекрашиваться в цвета из системной темы.

В дополнении к уже всем существующим иконкам (обычная, круглая и адаптивная) приложениям надо будет добавить монохромную картинку, хорошо, что это сделали простым добавлением тэга monochrome в адаптивной иконке

Новая иконка будет показываться в случае, если пользователь явно включит их в поддерживаемом лаунчере. Не все разработчики озаботились тем, чтобы добавить такую иконку и не факт, что сделают быстро, поэтому скорее всего вы будете видеть странный микс из темизированных иконок и нет.

Очень странная фича, так как разработчики точно не будут спешить с ее реализацией в приложениях, если конечно 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()

Программируемые шейдеры

В 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
Пример запроса разрешения на доступ только к музыке и аудио на устройстве
Пример запроса разрешения на доступ только к музыке и аудио на устройстве

Если ранее вы уже получили разрешение 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 и подходит для тех случаев, когда вам надо получить тип текущей сети у пользователя. Это разрешение выдается приложению при установке.

Строгое совпадение 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

Ограничение скорости сети

Установка ограничения скорости передачи данных по сети
Установка ограничения скорости передачи данных по сети

В настройках разработчика появилась важная возможность для тестирования приложений - ограничение скорости любой сети, которые могут предоставлять выход в интернет. Эта фича позволит вам лучше проверить работу вашего приложения в условиях сетей с низкой скоростью без каких-либо танцев с бубном с проксями

Ограничения доступа к Accessibility Services

Пример получения доступа в Accessibility Services для приложения, установленного не из магазина приложений
Пример получения доступа в Accessibility Services для приложения, установленного не из магазина приложений

Использование Accessibility Services даёт разработчикам неограниченные возможности по отслеживанию того, что происходит на экране и в системе. Этим могли пользоваться злоумышленники. В Android 13, чтобы ограничить эту уязвимость, запретили использовать Accessibility Services для всех приложений, которые установлены не из магазинов приложений. Установка засчитывается как из Google Play, так и из альтернативных магазинов.

Для корректной установки приложения магазины используют Package Manager Session API. Браузеры, файловые менеджеры и другие приложения, как правило, используют обычное API для установки. Так и определяется, что приложение установлено из магазина. Использовать оба API для установки могут все, поэтому злоумышленники найдут способ обойти ограничение, но им однозначно становится сложнее.

Изменение сделано с целью того, что Google хочет, чтобы приложения, которые получают такой доступ, проходили проверку. При попытке включения доступа для загруженного из вне приложения пользователь увидит предупреждение о недоступности настройки для приложения. Но у пользователя все равно есть возможность разрешить доступ явно, просто это стало сложнее.

Прочие изменения

В Android 13 произошло множество изменений, не все из которых заслуживают полноценного разбора, но точно стоит озвучить. Поехали!

  • Появилась 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 до самых свежих версий

  • Добавлена поддержка COLRv1 - новый векторный формат шрифтов

  • Автоматическая очистка буфера обмена. По умолчанию стоит значение в 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 в комментариях к статье

Комментарии (16)


  1. quaer
    13.05.2023 12:25

    resourceConfigurations += ["en", "en-rGB", "fr", "ja", "b+zh+Hans+MO", "b+zh+Hant+MO"]

    Из-за += выглядит так, что эта строчка добавляет локали к локалям по умолчанию. Это точно верно? Цель же такой строчки - убрать лишние локали при сборке из всего, включая библиотеки.

    Кто еще пишет приложения на Java?

    На Java быстрее компиляция, нет мусора в релизном коде.


    1. kirich1409 Автор
      13.05.2023 12:25

      1. Да. верно. Добавление верно, но это мой собственный стиль. Чтобы не сломать код который мог быть выполнен раньше

      2. Язык - это инструмент. Если Java вам подходит - пишите на ней.


      1. quaer
        13.05.2023 12:25

        Кстати, какая разница между resConfigs и resourceConfigurations ?


        1. kirich1409 Автор
          13.05.2023 12:25

          Помойму одну из них пометили как deprecated, но весь код проверял и он был актуальный


  1. Pastoral
    13.05.2023 12:25
    -1

    Регулярно приводил, привожу, и буду приводить кнопку Назад как один из примеров фундаментальной архитектурной ошибки в Андроид вызванной интернет мышлением компании Гугол. Несмотря на всю очевидность, многие не понимали и не понимают. Красота решения в Андроид 13, надеюсь, поможет - впредь будут меньше не понимать.


    1. kirich1409 Автор
      13.05.2023 12:25
      +1

      Нужно понимать что тогда это было проще пользователям. Также Android был заложен ещё давно и как альтернатива Blackberry. В начале был ещё шарик для скролла. ОС меняются от возможностей железа и запросов пользователей. Они не могут предвидеть все, а делают здесь и сейчас


      1. Pastoral
        13.05.2023 12:25

        Они - не могут, точно. Эппл - может.

        Если правильно помню, Андроид создавался для гаджетов типа фотокамер, т.е. устройств вообще без понятия стороннего приложения. То, что вовремя почуяли неминуемый провал и переобулись в прыжке, одно время популяризировалось как пример деловой хватки. ИМХО совершенно заслужено, перед концом грех не поискать богатеньких Буратин.

        Отсюда и были прошивки с целым гигабайтом памяти куда можно ставить приложения и ещё 15 гигами как образ SD карты. Всё это на одном кристалле естественно, а когда добавлялась собственно SD карта - начинались чудеса.

        Это я к тому, что Гугол покупал сознательно с желанием продолжить абы как, совершенно сознательно, такое оно, интернет-мышление. Кнопка Назад в браузере уже в то время достала всех кто пытался сделать что-то как нетривиальное так и одностраничное.


    1. Mingun
      13.05.2023 12:25
      +5

      А что не так с кнопкой «Назад»?


    1. ganzmavag
      13.05.2023 12:25
      +3

      А почему фундаментальная ошибка? Можете подробнее рассказать?


      1. Rusrst
        13.05.2023 12:25

        Вероятно это к тому что со стеком навигации (к примеру если у нас очень разветвленной приложение имеющее навигацию в bottomsheet) могут быть сложности. В ios вроде кнопки этой нет и там нет таких проблем делать всю навигацию под требования и разбираться что как и где должно работать.

        С onbackpressedcallback тоже не все прям радостно, все привыкли что при нажатии кнопки назад можно что-то сделать, а теперь если флаг для callback взведен (т.е. вы хотите что-то сделать по нажатию) анимации красивой из примера не получится...


  1. santjagocorkez
    13.05.2023 12:25

    А скажите, знатоки андроида, почему любой (абсолютно любой, без исключений, даже FOSS Browser) браузер, стоит ему наткнуться на рендер виджета ютуба, моргает из xPrivacy уведомлением о предотвращенной попытке получения доступа к камере?


    1. kirich1409 Автор
      13.05.2023 12:25

      Комментарий не в тему статьи


      1. santjagocorkez
        13.05.2023 12:25

        Зато статья неплохо притягивает разбирающихся в этой кухне. Впрочем, я могу это переформулировать в виде вопроса вида "скажите, в 13 версии так и не исправили ..?"


  1. Akr0n
    13.05.2023 12:25

    В Андроид 13 без рута вообще никак не получить доступ в папку установленного приложения? Например, Android_data/net.osmand/. В Андроид 12 руками закидывал карты, было очень удобно...


    1. quaer
      13.05.2023 12:25
      +2

      Они пару лет назад запретили приложениям общаться со всей файловой системой. Приложения могут иметь доступ только к своему собственному каталогу. Надо слать запрос в гугл и получать от них одобрение, если приложение хочет иметь функционал файлового менеджера. Из-за этого много приложений, которые сохраняли/получали файлы/бэкапили свои файлы вынуждены были убрать такую функциональность или, если это было связано с базовыми функциями приложений, вообще перестали нормально работать.


      1. Akr0n
        13.05.2023 12:25

        Спасибо за наводку, выяснилось, что встроенный файловый менеджер всё-таки может получить туда доступ. Никогда им не пользовался, теперь, видимо, придется.