Android 17 представляет множество новых функций и API для разработчиков. В следующих разделах приведено краткое описание этих функций, которое поможет вам начать работу с соответствующими API.
Подробный список новых, измененных и удаленных API см. в отчете об изменениях API . Подробную информацию о новых API см. в справочнике Android API — новые API выделены для большей наглядности.
Также следует проанализировать области, где изменения платформы могут повлиять на ваши приложения. Для получения дополнительной информации см. следующие страницы:
- Изменения в поведении, влияющие на приложения при использовании Android 17.
- Изменения в поведении, затрагивающие все приложения независимо от
targetSdkVersion.
Основная функциональность
В Android 17 добавлены следующие новые функции, относящиеся к основным возможностям Android.
Новые триггеры ProfilingManager
В Android 17 в ProfilingManager добавлено несколько новых системных триггеров, которые помогут вам собрать подробные данные для отладки проблем с производительностью.
Новые триггеры:
-
TRIGGER_TYPE_COLD_START: Триггер срабатывает во время холодного запуска приложения. В ответе он предоставляет как пример стека вызовов, так и трассировку системы. -
TRIGGER_TYPE_OOM: Триггер срабатывает, когда приложение генерирует ошибкуOutOfMemoryErrorи в ответ предоставляет дамп кучи Java. -
TRIGGER_TYPE_KILL_EXCESSIVE_CPU_USAGE: Триггер срабатывает, когда приложение завершает работу из-за ненормального и чрезмерного использования ЦП, и в ответ предоставляет пример стека вызовов. -
TRIGGER_TYPE_ANOMALY: Обнаруживает аномалии производительности системы, такие как чрезмерное количество вызовов binder и чрезмерное использование памяти.
Чтобы понять, как настроить системный триггер, ознакомьтесь с документацией по профилированию на основе триггеров , а также с документацией по получению и анализу данных профилирования .
Триггер профилирования для выявления аномалий в приложении
В Android 17 появилась встроенная служба обнаружения аномалий на устройстве, которая отслеживает ресурсоемкое поведение и потенциальные проблемы совместимости. Интегрированная с ProfilingManager , эта служба позволяет вашему приложению получать артефакты профилирования, запускаемые определенными событиями, обнаруженными системой.
Используйте триггер TRIGGER_TYPE_ANOMALY для обнаружения проблем с производительностью системы, таких как чрезмерное количество вызовов binder и чрезмерное использование памяти. Когда приложение превышает установленные ОС ограничения памяти, триггер anomaly позволяет разработчикам получать дампы кучи, специфичные для приложения, что помогает выявлять и устранять проблемы с памятью. Кроме того, при чрезмерном использовании binder триггер anomaly предоставляет профиль выборки стека для транзакций binder.
Этот API-вызов происходит до применения каких-либо системных мер. Например, он может помочь разработчикам собрать отладочные данные до того, как приложение будет завершено системой за превышение лимитов памяти.
val profilingManager =
applicationContext.getSystemService(ProfilingManager::class.java)
val triggers = ArrayList<ProfilingTrigger>()
triggers.add(ProfilingTrigger.Builder(ProfilingTrigger.TRIGGER_TYPE_ANOMALY))
val mainExecutor: Executor = Executors.newSingleThreadExecutor()
val resultCallback = Consumer<ProfilingResult> { profilingResult ->
if (profilingResult.errorCode != ProfilingResult.ERROR_NONE) {
// upload profile result to server for further analysis
setupProfileUploadWorker(profilingResult.resultFilePath)
}
profilingManager.registerForAllProfilingResults(mainExecutor,
resultCallback)
profilingManager.addProfilingTriggers(triggers)
}
API JobDebugInfo
В Android 17 представлены новые API JobDebugInfo , которые помогут разработчикам отлаживать задания JobScheduler — выяснять, почему они не выполняются, как долго они выполнялись, и получать другую сводную информацию.
Первый метод расширенного API JobDebugInfo — getPendingJobReasonStats() , который возвращает карту причин, по которым задание находилось в состоянии ожидания выполнения , и их соответствующую суммарную продолжительность ожидания. Этот метод объединяет методы getPendingJobReasonsHistory() и getPendingJobReasons() , предоставляя информацию о причинах, по которым запланированное задание выполняется не так, как ожидалось, но упрощает получение информации, предоставляя в одном методе как продолжительность, так и причину выполнения задания.
Например, для указанного jobId метод может вернуть PENDING_JOB_REASON_CONSTRAINT_CHARGING и длительность 60000 мс, указывая на то, что задание находилось в состоянии ожидания в течение 60000 мс из-за несоблюдения ограничения на зарядку.
Уменьшите количество блокировок пробуждения благодаря поддержке слушателей для будильников, разрешающих работу в режиме ожидания.
В Android 17 представлен новый вариант метода AlarmManager.setExactAndAllowWhileIdle , который принимает OnAlarmListener вместо PendingIntent . Этот новый механизм на основе обратных вызовов идеально подходит для приложений, которые в настоящее время полагаются на непрерывную блокировку пробуждения для выполнения периодических задач, например, для мессенджеров, поддерживающих сокетные соединения.
Конфиденциальность
В Android 17 добавлены следующие новые функции для повышения конфиденциальности пользователей.
Поддержка платформы Encrypted Client Hello (ECH).
В Android 17 появилась поддержка технологии Encrypted Client Hello (ECH), которая значительно повышает конфиденциальность сетевых коммуникаций. ECH — это расширение TLS 1.3, которое шифрует Server Name Indication (SNI) во время первоначального установления TLS-соединения. Это шифрование помогает защитить конфиденциальность пользователей, затрудняя сетевым посредникам идентификацию конкретного домена, к которому подключается приложение.
Теперь платформа включает необходимые API для сетевых библиотек, позволяющие реализовать ECH. Это включает новые возможности в DnsResolver для запроса записей HTTPS DNS, содержащих конфигурации ECH, а также новые методы в SSLEngines и SSLSockets Conscrypt для включения ECH путем передачи этих конфигураций при подключении к домену. Разработчики могут настраивать параметры ECH, например, включать его по мере необходимости или предписывать его использование, с помощью нового элемента <domainEncryption> в файле конфигурации сетевой безопасности, применимого глобально или для каждого домена отдельно.
Ожидается, что популярные сетевые библиотеки, такие как HttpEngine, WebView и OkHttp, интегрируют эти API платформы в будущих обновлениях, что упростит внедрение ECH в приложения и повысит конфиденциальность пользователей.
Для получения более подробной информации см. документацию по протоколу Encrypted Client Hello .
средство выбора контактов для Android
Интерфейс выбора контактов Android Contact Picker — это стандартизированный, удобный для просмотра интерфейс, позволяющий пользователям делиться контактами с вашим приложением. Доступный на устройствах под управлением Android 17 (уровень API 37) или выше, этот интерфейс предлагает альтернативу широкому разрешению READ_CONTACTS , обеспечивающую конфиденциальность. Вместо запроса доступа ко всей адресной книге пользователя, ваше приложение указывает необходимые поля данных, такие как номера телефонов или адреса электронной почты, а пользователь выбирает конкретные контакты для обмена. Это предоставляет вашему приложению доступ на чтение только к выбранным данным, обеспечивая детальный контроль и предоставляя единообразный пользовательский опыт со встроенным поиском, переключением профилей и возможностью множественного выбора без необходимости разработки или поддержки пользовательского интерфейса.
Для получения более подробной информации см. документацию по средству выбора контактов .
Безопасность
В Android 17 добавлены следующие новые функции для повышения безопасности устройств и приложений.
Расширенный режим защиты Android (AAPM)
Android Advanced Protection Mode offers Android users a powerful new set of security features, marking a significant step in safeguarding users—particularly those at higher risk—from sophisticated attacks. Designed as an opt-in feature, AAPM is activated with a single configuration setting that users can turn on at any time to apply an opinionated set of security protections.
These core configurations include blocking app installation from unknown sources
(sideloading), restricting USB data signaling, and mandating Google Play Protect
scanning, which significantly reduces the device's attack surface area.
Developers can integrate with this feature using the
AdvancedProtectionManager API to detect the mode's status, enabling
applications to automatically adopt a hardened security posture or restrict
high-risk functionality when a user has opted in.
Подписание APK-файлов PQC
Android now supports a hybrid APK signature scheme to future-proof your app's signing identity against the potential threat of attacks that make use of quantum computing. This feature introduces a new APK Signature Scheme, which lets you pair a classical signing key (such as RSA or EC) with a new post-quantum cryptography (PQC) algorithm (ML-DSA).
This hybrid approach ensures your app remains secure against future quantum attacks while maintaining full backward compatibility with older Android versions and devices that rely on classical signature verification.
Impact on developers
- Apps using Play App Signing: If you use Play App Signing, you can wait for Google Play to give you the option to upgrade a hybrid signature using a PQC key generated by Google Play, ensuring your app is protected without requiring manual key management.
- Apps using self-managed keys: Developers who manage their own signing keys can utilize updated Android build tools (like apksigner) to rotate to a hybrid identity, combining a PQC key with a new classical key. (You must create a new classical key, you cannot reuse the older one.)
Подключение
В Android 17 добавлены следующие функции для улучшения взаимодействия устройств и приложений.
Ограниченные спутниковые сети
Implements optimizations to enable apps to function effectively over low-bandwidth satellite networks.
Пользовательский опыт и пользовательский интерфейс системы
В Android 17 внесены следующие изменения для улучшения пользовательского опыта.
Поток выделенного аудиопомощника
Android 17 introduces a dedicated Assistant volume stream for Assistant apps,
for playback with USAGE_ASSISTANT. This change decouples Assistant audio
from the standard media stream, providing users with isolated control over both
volumes. This enables scenarios such as muting media playback while maintaining
audibility for Assistant responses, and the other way around.
Assistant apps with access to the new MODE_ASSISTANT_CONVERSATION audio
mode can further improve the volume control consistency. Assistant apps can use
this mode to provide a hint to the system about an active Assistant session,
ensuring the Assistant stream can be controlled outside of the active
USAGE_ASSISTANT playback or with connected Bluetooth peripherals.
Передавать
Handoff — это новая функция и API, которые появятся в Android 17 и которые разработчики приложений смогут интегрировать для обеспечения непрерывности работы приложений на разных устройствах. Она позволяет пользователю запустить приложение на одном устройстве Android и перевести его на другое. Handoff работает в фоновом режиме на устройстве пользователя и отображает доступные приложения с других находящихся рядом устройств пользователя через различные точки входа, такие как панель запуска и панель задач, на принимающем устройстве.
Приложения могут настроить Handoff на запуск того же самого нативного приложения Android, если оно установлено и доступно на принимающем устройстве. В этом процессе взаимодействия между приложениями пользователь получает прямую ссылку на указанное действие. В качестве альтернативы, в качестве резервного варианта может быть предложен Handoff для взаимодействия между приложением и веб-приложением или он может быть реализован напрямую с помощью URL Handoff.
Поддержка Handoff реализована для каждой активности отдельно. Чтобы включить Handoff, вызовите метод setHandoffEnabled() для соответствующей активности. Для восстановления состояния на принимающем устройстве при передаче данных могут потребоваться дополнительные данные. Реализуйте функцию обратного вызова onHandoffActivityDataRequested() которая будет возвращать объект HandoffActivityData , содержащий подробную информацию о том, как Handoff должен обрабатывать и восстанавливать активность на принимающем устройстве.
Обновление в реальном времени - API семантического цвета
В Android 17 функция Live Update запускает API семантической раскраски для поддержки цветов с универсальным значением.
Следующие классы поддерживают семантическую раскраску:
-
Notification -
Notification.Metric -
Notification.ProgressStyle.Point -
Notification.ProgressStyle.Segment
Раскрашивание
- Зеленый : ассоциируется с безопасностью. Этот цвет следует использовать в тех случаях, когда он дает понять окружающим, что вы находитесь в безопасной ситуации.
- Оранжевый : Используется для обозначения предупреждающих знаков и физических опасностей. Этот цвет следует использовать в ситуациях, когда пользователям необходимо проявлять осторожность для обеспечения более надежной защиты.
- Красный цвет : Обычно указывает на опасность, необходимо остановиться. Его следует использовать в случаях, когда требуется срочное внимание людей.
- Синий : Нейтральный цвет для информационного контента, который должен выделяться на фоне остального контента.
В следующем примере показано, как применить семантические стили к тексту в уведомлении:
val ssb = SpannableStringBuilder()
.append("Colors: ")
.append("NONE", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_UNSPECIFIED), 0)
.append(", ")
.append("INFO", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_INFO), 0)
.append(", ")
.append("SAFE", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_SAFE), 0)
.append(", ")
.append("CAUTION", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_CAUTION), 0)
.append(", ")
.append("DANGER", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_DANGER), 0)
Notification.Builder(context, channelId)
.setSmallIcon(R.drawable.ic_icon)
.setContentTitle("Hello World!")
.setContentText(ssb)
.setOngoing(true)
.setRequestPromotedOngoing(true)
API UWB Downlink-TDoA для Android 17
Метод определения местоположения по разности времени прихода сигнала в нисходящем канале (DL-TDoA) позволяет устройству определять свое положение относительно нескольких опорных точек путем измерения относительного времени прихода сигналов.
Следующий фрагмент кода демонстрирует, как инициализировать менеджер определения дальности , проверить возможности устройства и запустить сессию DL-TDoA:
Котлин
class RangingApp {
fun initDlTdoa(context: Context) {
// Initialize the Ranging Manager
val rangingManager = context.getSystemService(RangingManager::class.java)
// Register for device capabilities
val capabilitiesCallback = object : RangingManager.RangingCapabilitiesCallback {
override fun onRangingCapabilities(capabilities: RangingCapabilities) {
// Make sure Dl-TDoA is supported before starting the session
if (capabilities.uwbCapabilities != null && capabilities.uwbCapabilities!!.isDlTdoaSupported) {
startDlTDoASession(context)
}
}
}
rangingManager.registerCapabilitiesCallback(Executors.newSingleThreadExecutor(), capabilitiesCallback)
}
fun startDlTDoASession(context: Context) {
// Initialize the Ranging Manager
val rangingManager = context.getSystemService(RangingManager::class.java)
// Create session and configure parameters
val executor = Executors.newSingleThreadExecutor()
val rangingSession = rangingManager.createRangingSession(executor, RangingSessionCallback())
val rangingRoundIndexes = byteArrayOf(0)
val config: ByteArray = byteArrayOf() // OOB config data
val params = DlTdoaRangingParams.createFromFiraConfigPacket(config, rangingRoundIndexes)
val rangingDevice = RangingDevice.Builder().build()
val rawTagDevice = RawRangingDevice.Builder()
.setRangingDevice(rangingDevice)
.setDlTdoaRangingParams(params)
.build()
val dtTagConfig = RawDtTagRangingConfig.Builder(rawTagDevice).build()
val preference = RangingPreference.Builder(DEVICE_ROLE_DT_TAG, dtTagConfig)
.setSessionConfig(SessionConfig.Builder().build())
.build()
// Start the ranging session
rangingSession.start(preference)
}
}
private class RangingSessionCallback : RangingSession.Callback {
override fun onDlTdoaResults(peer: RangingDevice, measurement: DlTdoaMeasurement) {
// Process measurement results here
}
}
Java
public class RangingApp {
public void initDlTdoa(Context context) {
// Initialize the Ranging Manager
RangingManager rangingManager = context.getSystemService(RangingManager.class);
// Register for device capabilities
RangingManager.CapabilitiesCallback capabilitiesCallback = new RangingManager.RangingCapabilitiesCallback() {
@Override
public void onRangingCapabilities(RangingCapabilities capabilities) {
// Make sure Dl-TDoA is supported before starting the session
if (capabilities.getUwbCapabilities() != null && capabilities.getUwbCapabilities().isDlTdoaSupported()) {
startDlTDoASession(context);
}
}
};
rangingManager.registerCapabilitiesCallback(Executors.newSingleThreadExecutor(), capabilitiesCallback);
}
public void startDlTDoASession(Context context) {
RangingManager rangingManager = context.getSystemService(RangingManager.class);
// Create session and configure parameters
Executor executor = Executors.newSingleThreadExecutor();
RangingSession rangingSession = rangingManager.createRangingSession(executor, new RangingSessionCallback());
byte[] rangingRoundIndexes = new byte[] {0};
byte[] config = new byte[0]; // OOB config data
DlTdoaRangingParams params = DlTdoaRangingParams.createFromFiraConfigPacket(config, rangingRoundIndexes);
RangingDevice rangingDevice = new RangingDevice.Builder().build();
RawRangingDevice rawTagDevice = new RawRangingDevice.Builder()
.setRangingDevice(rangingDevice)
.setDlTdoaRangingParams(params)
.build();
RawDtTagRangingConfig dtTagConfig = new RawDtTagRangingConfig.Builder(rawTagDevice).build();
RangingPreference preference = new RangingPreference.Builder(DEVICE_ROLE_DT_TAG, dtTagConfig)
.setSessionConfig(new SessionConfig.Builder().build())
.build();
// Start the ranging session
rangingSession.start(preference);
}
private static class RangingSessionCallback implements RangingSession.Callback {
@Override
public void onDlTdoaResults(RangingDevice peer, DlTdoaMeasurement measurement) {
// Process measurement results here
}
}
}
Внеполосные (OOB) конфигурации
Приведённый ниже фрагмент кода представляет собой пример данных конфигурации DL-TDoA OOB для Wi-Fi и BLE:
Java
// Wifi Configuration
byte[] wifiConfig = {
(byte) 0xDD, (byte) 0x2D, (byte) 0x5A, (byte) 0x18, (byte) 0xFF, // Header
(byte) 0x5F, (byte) 0x19, // FiRa Sub-Element
(byte) 0x02, (byte) 0x00, // Profile ID
(byte) 0x06, (byte) 0x02, (byte) 0x20, (byte) 0x08, // MAC Address
(byte) 0x14, (byte) 0x01, (byte) 0x0C, // Preamble Index
(byte) 0x27, (byte) 0x02, (byte) 0x08, (byte) 0x07, // Vendor ID
(byte) 0x28, (byte) 0x06, (byte) 0xCA, (byte) 0xC8, (byte) 0xA6, (byte) 0xF7, (byte) 0x6F, (byte) 0x08, // Static STS IV
(byte) 0x08, (byte) 0x02, (byte) 0x60, (byte) 0x09, // Slot Duration
(byte) 0x1B, (byte) 0x01, (byte) 0x0A, // Slots per RR
(byte) 0x09, (byte) 0x04, (byte) 0xE8, (byte) 0x03, (byte) 0x00, (byte) 0x00, // Duration
(byte) 0x9F, (byte) 0x04, (byte) 0x67, (byte) 0x45, (byte) 0x23, (byte) 0x01 // Session ID
};
// BLE Configuration
byte[] bleConfig = {
(byte) 0x2D, (byte) 0x16, (byte) 0xF4, (byte) 0xFF, // Header
(byte) 0x5F, (byte) 0x19, // FiRa Sub-Element
(byte) 0x02, (byte) 0x00, // Profile ID
(byte) 0x06, (byte) 0x02, (byte) 0x20, (byte) 0x08, // MAC Address
(byte) 0x14, (byte) 0x01, (byte) 0x0C, // Preamble Index
(byte) 0x27, (byte) 0x02, (byte) 0x08, (byte) 0x07, // Vendor ID
(byte) 0x28, (byte) 0x06, (byte) 0xCA, (byte) 0xC8, (byte) 0xA6, (byte) 0xF7, (byte) 0x6F, (byte) 0x08, // Static STS IV
(byte) 0x08, (byte) 0x02, (byte) 0x60, (byte) 0x09, // Slot Duration
(byte) 0x1B, (byte) 0x01, (byte) 0x0A, // Slots per RR
(byte) 0x09, (byte) 0x04, (byte) 0xE8, (byte) 0x03, (byte) 0x00, (byte) 0x00, // Duration
(byte) 0x9F, (byte) 0x04, (byte) 0x67, (byte) 0x45, (byte) 0x23, (byte) 0x01 // Session ID
};
Если вы не можете использовать конфигурацию OOB из-за её отсутствия, или если вам нужно изменить значения по умолчанию, которых нет в конфигурации OOB, вы можете создать параметры с помощью DlTdoaRangingParams.Builder , как показано в следующем фрагменте кода. Вы можете использовать эти параметры вместо DlTdoaRangingParams.createFromFiraConfigPacket() :
Котлин
val dlTdoaParams = DlTdoaRangingParams.Builder(1)
.setComplexChannel(UwbComplexChannel.Builder()
.setChannel(9).setPreambleIndex(10).build())
.setDeviceAddress(deviceAddress)
.setSessionKeyInfo(byteArrayOf(0x01, 0x02, 0x03, 0x04))
.setRangingIntervalMillis(240)
.setSlotDuration(UwbRangingParams.DURATION_2_MS)
.setSlotsPerRangingRound(20)
.setRangingRoundIndexes(byteArrayOf(0x01, 0x05))
.build()
Java
DlTdoaRangingParams dlTdoaParams = new DlTdoaRangingParams.Builder(1)
.setComplexChannel(new UwbComplexChannel.Builder()
.setChannel(9).setPreambleIndex(10).build())
.setDeviceAddress(deviceAddress)
.setSessionKeyInfo(new byte[]{0x01, 0x02, 0x03, 0x04})
.setRangingIntervalMillis(240)
.setSlotDuration(UwbRangingParams.DURATION_2_MS)
.setSlotsPerRangingRound(20)
.setRangingRoundIndexes(new byte[]{0x01, 0x05})
.build();