Изменения в поведении Android 8.0

Помимо новых функций и возможностей, Android 8.0 (уровень API 26) включает в себя множество изменений в поведении системы и API. В этом документе освещаются некоторые ключевые изменения, которые вам следует понимать и учитывать в своих приложениях.

Большинство этих изменений затрагивают все приложения, независимо от того, на какую версию Android они нацелены. Однако некоторые изменения касаются только приложений, ориентированных на Android 8.0. Чтобы обеспечить максимальную ясность, эта страница разделена на два раздела: «Изменения для всех приложений» и «Изменения для приложений, ориентированных на Android 8.0» .

Изменения для всех приложений

Эти изменения поведения относятся к Все приложения когда они работают на платформе Android 8.0 (уровень API 26), независимо от целевого уровня API. Всем разработчикам следует просмотреть эти изменения и модифицировать свои приложения для их надлежащей поддержки, если это применимо к приложению.

Ограничения фонового выполнения

В качестве одного из изменений, внесенных в Android 8.0 (уровень API 26) для увеличения времени автономной работы, когда ваше приложение переходит в кэшированное состояние без активных компонентов , система снимает все блокировки пробуждения, которые удерживает приложение.

Кроме того, для повышения производительности устройства система ограничивает определенные действия приложений, которые не работают на переднем плане. Конкретно:

  • Приложения, работающие в фоновом режиме, теперь имеют ограничения на свободный доступ к фоновым службам.
  • Приложения не могут использовать свои манифесты для регистрации на большинство неявных трансляций (то есть трансляций, которые не предназначены конкретно для приложения).

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

Android 8.0 (уровень API 26) также включает следующие изменения в отдельные методы:

  • Метод startService() теперь генерирует IllegalStateException если приложение, предназначенное для Android 8.0, пытается использовать этот метод в ситуации, когда ему не разрешено создавать фоновые службы.
  • Новый метод Context.startForegroundService() запускает службу переднего плана. Система позволяет приложениям вызывать Context.startForegroundService() даже когда приложение находится в фоновом режиме. Однако приложение должно вызвать метод startForeground() этой службы в течение пяти секунд после создания службы.

Дополнительные сведения см. в разделе «Ограничения фонового выполнения» .

Ограничения местоположения в фоновом режиме Android

Чтобы сохранить заряд батареи, удобство использования и работоспособность системы, фоновые приложения реже получают обновления местоположения при использовании на устройстве под управлением Android 8.0. Это изменение поведения затрагивает все приложения, которые получают обновления местоположения, включая сервисы Google Play.

Эти изменения затрагивают следующие API:

  • Поставщик объединенного местоположения (FLP)
  • Геофенсинг
  • ГНСС-измерения
  • Менеджер местоположения
  • Менеджер Wi-Fi

Чтобы убедиться, что ваше приложение работает должным образом, выполните следующие действия:

  • Просмотрите логику своего приложения и убедитесь, что вы используете новейшие API-интерфейсы определения местоположения.
  • Проверьте, что ваше приложение демонстрирует поведение, которое вы ожидаете для каждого варианта использования.
  • Рассмотрите возможность использования Fused Location Provider (FLP) или геозон для обработки случаев использования, которые зависят от текущего местоположения пользователя.

Дополнительные сведения об этих изменениях см. в разделе «Ограничения фонового местоположения» .

Ярлыки приложений

Android 8.0 (уровень API 26) включает следующие изменения в ярлыках приложений:

  • Трансляция com.android.launcher.action.INSTALL_SHORTCUT больше не оказывает никакого влияния на ваше приложение, поскольку теперь это частная неявная трансляция. Вместо этого вам следует создать ярлык приложения, используя метод requestPinShortcut() из класса ShortcutManager .
  • Цель ACTION_CREATE_SHORTCUT теперь может создавать ярлыки приложений, которыми вы управляете с помощью класса ShortcutManager . Это намерение также может создать устаревшие ярлыки запуска, которые не взаимодействуют с ShortcutManager . Раньше это намерение могло создавать только устаревшие ярлыки запуска.
  • Ярлыки, созданные с помощью requestPinShortcut() и ярлыки, созданные в действии, которое обрабатывает намерение ACTION_CREATE_SHORTCUT , теперь являются полноценными ярлыками приложений. В результате приложения теперь могут обновлять их с помощью методов ShortcutManager .
  • Устаревшие ярлыки сохраняют свою функциональность из предыдущих версий Android, но вам придется вручную преобразовать их в ярлыки приложений в своем приложении.

Дополнительные сведения об изменениях ярлыков приложений см. в руководстве по закреплению ярлыков и виджетов .

Локали и интернационализация

В Android 7.0 (уровень API 24) появилась концепция возможности указывать локаль категории по умолчанию, но некоторые API продолжали использовать общий метод Locale.getDefault() без аргументов, хотя вместо этого они должны были использовать локаль категории DISPLAY по умолчанию. В Android 8.0 (уровень API 26) следующие методы теперь используют Locale.getDefault(Category.DISPLAY) вместо Locale.getDefault() :

Locale.getDisplayScript(Locale) также возвращается к Locale.getDefault() , когда значение displayScript , указанное для аргумента Locale , недоступно.

Дополнительные изменения, связанные с локалью и интернационализацией, заключаются в следующем:

  • Вызов Currency.getDisplayName(null) вызывает исключение NullPointerException , соответствующее документированному поведению.
  • Изменился анализ названия часового пояса. Раньше устройства Android использовали значение системных часов, выбранное во время загрузки, для кэширования имен часовых поясов, используемых для анализа даты и времени. В результате синтаксический анализ может быть ухудшен, если системные часы были неправильными во время загрузки или в других, более редких случаях.

    Теперь в обычных случаях логика анализа использует ICU и текущее значение системных часов при анализе имен часовых поясов. Это изменение обеспечивает более правильные результаты, которые могут отличаться от более ранних версий Android, если ваше приложение использует такие классы, как SimpleDateFormat .

  • Android 8.0 (уровень API 26) обновляет версию ICU до версии 58.

Окна оповещений

Если приложение использует разрешение SYSTEM_ALERT_WINDOW и использует один из следующих типов окон, чтобы попытаться отобразить окна предупреждений поверх других приложений и системных окон:

...тогда эти окна всегда появляются под окнами, использующими тип окна TYPE_APPLICATION_OVERLAY . Если приложение предназначено для Android 8.0 (уровень API 26), оно использует тип окна TYPE_APPLICATION_OVERLAY для отображения окон предупреждений.

Дополнительную информацию см. в разделе «Общие типы окон для окон предупреждений» в разделе «Изменения поведения приложений для Android 8.0» .

Ввод и навигация

С появлением приложений Android на ChromeOS и других крупных форм-факторах, таких как планшеты, мы наблюдаем возрождение использования клавиатуры в приложениях Android. В Android 8.0 (уровень API 26) мы переосмыслили использование клавиатуры в качестве устройства ввода навигации, в результате чего появилась более надежная и предсказуемая модель навигации с помощью стрелок и табуляции.

В частности, мы внесли следующие изменения в поведение фокуса элемента:

  • Если вы не определили какие-либо цвета состояния фокуса для объекта View (его рисуемого переднего плана или фона), платформа теперь устанавливает цвет выделения фокуса по умолчанию для View . Эта подсветка фокуса представляет собой волнистый рисунок, основанный на теме занятия.

    Если вы не хотите, чтобы объект View использовал это выделение по умолчанию при получении фокуса, установите для атрибута android:defaultFocusHighlightEnabled значение false в XML-файле макета, содержащем View , или передайте false в setDefaultFocusHighlightEnabled() в логике пользовательского интерфейса вашего приложения.

  • Чтобы проверить, как ввод с клавиатуры влияет на фокус элемента пользовательского интерфейса, вы можете включить параметр разработчика «Рисование» > «Показать границы макета» . В Android 8.0 этот параметр отображает значок «X» над элементом, который в данный момент находится в фокусе.

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

Чтобы узнать больше о том, как улучшить поддержку навигации с помощью клавиатуры в вашем приложении, прочтите руководство «Поддержка навигации с помощью клавиатуры» .

Автозаполнение веб-форм

Теперь, когда Android Autofill Framework обеспечивает встроенную поддержку функций автозаполнения, следующие методы, связанные с объектами WebView изменились для приложений, установленных на устройствах под управлением Android 8.0 (уровень API 26):

WebSettings
  • Метод getSaveFormData() теперь возвращает false . Раньше этот метод вместо этого возвращал true .
  • Вызов setSaveFormData() больше не имеет никакого эффекта.
WebViewDatabase
  • Вызов clearFormData() больше не имеет никакого эффекта.
  • Метод hasFormData() теперь возвращает false . Раньше этот метод возвращал true если форма содержала данные.

Доступность

Android 8.0 (уровень API 26) включает следующие изменения специальных возможностей:

  • Платформа специальных возможностей теперь преобразует все жесты двойного касания в действия ACTION_CLICK . Это изменение позволяет TalkBack вести себя как другие службы специальных возможностей.

    Если объекты View вашего приложения используют специальную обработку сенсорного ввода, вам следует убедиться, что они по-прежнему работают с TalkBack. Возможно, вам просто нужно зарегистрировать обработчик кликов, который используют ваши объекты View . Если TalkBack по-прежнему не распознает жесты, выполняемые с этими объектами View , переопределите performAccessibilityAction() .

  • Службы специальных возможностей теперь знают обо всех экземплярах ClickableSpan в объектах TextView вашего приложения.

Чтобы узнать больше о том, как сделать ваше приложение более доступным, см. раздел «Доступность» .

Сеть и подключение HTTP(S)

Android 8.0 (уровень API 26) включает следующие изменения в поведении сети и подключения HTTP(S):

  • Запросы OPTIONS без тела имеют заголовок Content-Length: 0 . Раньше у них не было заголовка Content-Length .
  • HttpURLConnection нормализует URL-адреса, содержащие пустые пути, добавляя косую черту после имени хоста или центра сертификации. Например, он преобразует http://example.com в http://example.com/ .
  • Пользовательский селектор прокси, установленный с помощью ProxySelector.setDefault(), нацелен только на адрес (схему, хост и порт) запрошенного URL-адреса. В результате выбор прокси может основываться только на этих значениях. URL-адрес, передаваемый в пользовательский селектор прокси-сервера, не включает в себя путь запрошенного URL-адреса, параметры запроса или фрагменты.
  • URI не могут содержать пустые метки.

    Ранее платформа поддерживала обходной путь, позволяющий принимать пустые метки в именах хостов, что является незаконным использованием URI. Это обходное решение предназначено для совместимости со старыми выпусками libcore. Разработчики, неправильно использующие API, увидят сообщение ADB: «URI example..com имеет пустые метки в имени хоста. Это неправильно и не будет принято в будущих выпусках Android». В Android 8.0 этот обходной путь исключен; система возвращает ноль для неверных URI.

  • Реализация HttpsURLConnection в Android 8.0 не выполняет небезопасный возврат версии протокола TLS/SSL.
  • Обработка туннельных соединений HTTP(S) изменилась следующим образом:
    • При туннелировании HTTPS-соединения поверх соединения система правильно размещает номер порта (:443) в строке Хост при отправке этой информации на промежуточный сервер. Раньше номер порта встречался только в строке CONNECT.
    • Система больше не отправляет заголовки пользовательского агента и прокси-авторизации из туннелированного запроса на прокси-сервер.

      Система больше не отправляет заголовок прокси-авторизации в туннелированном Http(s)URLConnection на прокси при настройке туннеля. Вместо этого система генерирует заголовок авторизации прокси-сервера и отправляет его прокси-серверу, когда этот прокси-сервер отправляет HTTP 407 в ответ на первоначальный запрос.

      Аналогично, система больше не копирует заголовок пользовательского агента из туннелируемого запроса в запрос прокси, который устанавливает туннель. Вместо этого библиотека генерирует заголовок пользовательского агента для этого запроса.

  • Метод send(java.net.DatagramPacket) генерирует исключение SocketException, если ранее выполненный метод Connect() завершился неудачно.
    • DatagramSocket.connect() устанавливает исключение pendingSocketException, если произошла внутренняя ошибка. До Android 8.0 последующий вызов Recv() вызывал исключение SocketException, хотя вызов send() был бы успешным. Для обеспечения единообразия оба вызова теперь вызывают исключение SocketException.
  • InetAddress.isReachable() пытается использовать ICMP, прежде чем вернуться к протоколу TCP Echo.
    • Некоторые хосты, блокирующие порт 7 (TCP Echo), например google.com, теперь могут стать доступными, если они принимают протокол ICMP Echo.
    • Для действительно недоступных хостов это изменение означает, что до возврата вызова затрачивается вдвое больше времени.

Bluetooth

Android 8.0 (уровень API 26) вносит следующие изменения в длину данных, которые получает метод ScanRecord.getBytes() :

  • Метод getBytes() не делает никаких предположений относительно количества полученных байтов. Таким образом, приложения не должны полагаться на минимальное или максимальное количество возвращаемых байтов. Вместо этого им следует оценить длину результирующего массива.
  • Устройства, совместимые с Bluetooth 5, могут возвращать длину данных, превышающую предыдущий максимум в ~60 байт.
  • Если удаленное устройство не предоставляет ответ на сканирование, также может быть возвращено менее 60 байт.

Бесшовное подключение

Android 8.0 (уровень API 26) вносит ряд улучшений в настройки Wi-Fi, чтобы упростить выбор сети Wi-Fi, обеспечивающей наилучшее взаимодействие с пользователем. Конкретные изменения включают в себя:

  • Улучшения стабильности и надежности.
  • Более интуитивно читаемый пользовательский интерфейс.
  • Единое консолидированное меню настроек Wi-Fi.
  • На совместимых устройствах автоматическая активация Wi-Fi при наличии поблизости сохраненной сети высокого качества.

Безопасность

Android 8.0 включает следующие изменения, связанные с безопасностью:

  • Платформа больше не поддерживает SSLv3.
  • При установке HTTPS-подключения к серверу, который неправильно реализует согласование версии протокола TLS, HttpsURLConnection больше не пытается использовать обходной путь возврата к более ранним версиям протокола TLS и повторной попытки.
  • Android 8.0 (уровень API 26) применяет фильтр безопасных вычислений (SECCOMP) ко всем приложениям. Список разрешенных системных вызовов ограничен теми, которые доступны через бионику. Хотя для обратной совместимости предусмотрено несколько других системных вызовов, мы не рекомендуем их использовать.
  • Объекты WebView вашего приложения теперь работают в многопроцессном режиме. Веб-содержимое обрабатывается в отдельном, изолированном процессе от процесса содержащего его приложения для повышения безопасности.
  • Вы больше не можете предполагать, что APK-файлы находятся в каталогах, имена которых заканчиваются на -1 или -2. Приложения должны использовать sourceDir для получения каталога, а не напрямую полагаться на формат каталога.
  • Сведения об улучшениях безопасности, связанных с использованием собственных библиотек, см. в разделе Собственные библиотеки .

Кроме того, в Android 8.0 (уровень API 26) представлены следующие изменения, связанные с установкой неизвестных приложений из неизвестных источников:

  • Значение устаревшего параметра INSTALL_NON_MARKET_APPS теперь всегда равно 1. Чтобы определить, может ли неизвестный источник устанавливать приложения с помощью установщика пакета, вместо этого следует использовать возвращаемое значение canRequestPackageInstalls() .
  • Если вы попытаетесь изменить значение INSTALL_NON_MARKET_APPS с помощью setSecureSetting() , будет выдано UnsupportedOperationException . Чтобы запретить пользователям устанавливать неизвестные приложения из неизвестных источников, вместо этого следует применить пользовательское ограничение DISALLOW_INSTALL_UNKNOWN_SOURCES .
  • В управляемых профилях, созданных на устройствах под управлением Android 8.0 (уровень API 26), автоматически включается пользовательское ограничение DISALLOW_INSTALL_UNKNOWN_SOURCES . Для существующих управляемых профилей на устройствах, обновленных до Android 8.0, ограничение пользователя DISALLOW_INSTALL_UNKNOWN_SOURCES включается автоматически, если только владелец профиля явно не отключил это ограничение (до обновления), установив для INSTALL_NON_MARKET_APPS значение 1.

Дополнительные сведения об установке неизвестных приложений см. в руководстве «Разрешения на установку неизвестных приложений» .

Дополнительные рекомендации по повышению безопасности вашего приложения см. в разделе Безопасность для разработчиков Android .

Конфиденциальность

Android 8.0 (уровень API 26) вносит в платформу следующие изменения, связанные с конфиденциальностью.

  • Платформа теперь обрабатывает идентификаторы по-другому.
    • Для приложений, которые были установлены до OTA на версию Android 8.0 (уровень API 26) (уровень API 26), значение ANDROID_ID остается неизменным, если они не были удалены, а затем переустановлены после OTA. Чтобы сохранить значения при удалении после OTA, разработчики могут связать старые и новые значения с помощью резервного копирования ключей и значений .
    • Для приложений, установленных на устройстве под управлением Android 8.0, значение ANDROID_ID теперь ограничено как для ключа подписи приложения, так и для каждого пользователя. Значение ANDROID_ID уникально для каждой комбинации ключа подписи приложения, пользователя и устройства. В результате приложения с разными ключами подписи, работающие на одном устройстве, больше не видят один и тот же идентификатор Android (даже для одного и того же пользователя).
    • Значение ANDROID_ID не меняется при удалении или переустановке пакета, если ключ подписи тот же (и приложение не было установлено до OTA на версию Android 8.0).
    • Значение ANDROID_ID не меняется, даже если обновление системы приводит к изменению ключа подписи пакета.
    • На устройствах, поставляемых с сервисами Google Play и рекламным идентификатором, вы должны использовать рекламный идентификатор. Рекламный идентификатор — это простая стандартная система монетизации приложений. Это уникальный идентификатор рекламы, который можно сбросить пользователем. Его предоставляют сервисы Google Play.

      Другие производители устройств должны продолжать предоставлять ANDROID_ID .

  • Запрос системного свойства net.hostname дает нулевой результат.

Регистрация неперехваченных исключений

Если приложение устанавливает Thread.UncaughtExceptionHandler , который не вызывает Thread.UncaughtExceptionHandler по умолчанию, система не завершает приложение при возникновении неперехваченного исключения. Начиная с Android 8.0 (уровень API 26), в этой ситуации система регистрирует трассировку стека исключений; в более ранних версиях платформы система не регистрировала трассировку стека исключений.

Мы рекомендуем, чтобы пользовательские реализации Thread.UncaughtExceptionHandler всегда вызывали обработчик по умолчанию; приложения, которые следуют этой рекомендации, не затронуты изменениями в Android 8.0.

изменение подписи findViewById()

Все экземпляры метода findViewById() теперь возвращают <T extends View> T вместо View . Это изменение имеет следующие последствия:

  • Это может привести к тому, что существующий код теперь будет иметь неоднозначный тип возвращаемого значения, например, если существуют как someMethod(View) , так и someMethod(TextView) , которые принимают результат вызова findViewById() .
  • При использовании исходного языка Java 8 для этого требуется явное приведение к View , когда тип возвращаемого значения не ограничен (например, assertNotNull(findViewById(...)).someViewMethod()) .
  • Для переопределения нефинальных методов findViewById() (например, Activity.findViewById() ) потребуется обновить тип возвращаемого значения.

Изменилась статистика использования провайдера контактов

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

Приложения по-прежнему могут читать эти данные, если они запрашивают разрешение READ_CONTACTS . В Android 8.0 (уровень API 26) и более поздних версиях запросы данных об использовании возвращают приблизительные, а не точные значения. Система Android сохраняет точные значения внутри себя, поэтому это изменение не влияет на API автозаполнения.

Это изменение поведения влияет на следующие параметры запроса:

Обработка коллекции

AbstractCollection.removeAll() и AbstractCollection.retainAll() теперь всегда вызывают исключение NullPointerException ; ранее NullPointerException не вызывалось, если коллекция была пустой. Это изменение приводит поведение в соответствие с документацией.

Android предприятие

Android 8.0 (уровень API 26) меняет поведение некоторых API и функций корпоративных приложений, включая контроллеры политик устройств (DPC). Изменения включают в себя:

  • Новые возможности, помогающие приложениям поддерживать рабочие профили на полностью управляемых устройствах.
  • Изменения в обработке обновлений системы, проверке приложений и аутентификации для повышения целостности устройства и системы.
  • Улучшения в пользовательском интерфейсе подготовки, уведомлений, экрана «Недавние» и постоянной VPN.

Чтобы увидеть все корпоративные изменения в Android 8.0 (уровень API 26) и узнать, как они могут повлиять на ваше приложение, прочтите статью Android в Enterprise .

Приложения, ориентированные на Android 8.0

Эти изменения поведения применяются исключительно к приложениям, ориентированным на Android 8.0 (уровень API 26) или более поздних версий. Приложения, которые компилируются для Android 8.0 или устанавливают для targetSdkVersion значение Android 8.0 или более поздней версии, должны изменить свои приложения для правильной поддержки такого поведения, если это применимо к приложению.

Окна оповещений

Приложения, использующие разрешение SYSTEM_ALERT_WINDOW больше не могут использовать следующие типы окон для отображения окон предупреждений поверх других приложений и системных окон:

Вместо этого приложения должны использовать новый тип окна под названием TYPE_APPLICATION_OVERLAY .

При использовании типа окна TYPE_APPLICATION_OVERLAY для отображения окон предупреждений для вашего приложения имейте в виду следующие характеристики нового типа окна:

  • Окна предупреждений приложения всегда появляются под критически важными системными окнами, такими как строка состояния и IME.
  • Система может перемещать или изменять размеры окон, использующих тип окна TYPE_APPLICATION_OVERLAY для улучшения представления на экране.
  • Открыв панель уведомлений, пользователи могут получить доступ к настройкам, позволяющим запретить приложению отображать окна предупреждений, отображаемые с использованием типа окна TYPE_APPLICATION_OVERLAY .

Уведомления об изменении контента

Android 8.0 (уровень API 26) меняет поведение ContentResolver.notifyChange() и registerContentObserver(Uri, boolean, ContentObserver) для приложений, ориентированных на Android 8.0.

Эти API теперь требуют, чтобы действительный ContentProvider был определен для полномочий во всех Uris. Определение действительного ContentProvider с соответствующими разрешениями поможет защитить ваше приложение от изменений содержимого со стороны вредоносных приложений и предотвратить утечку потенциально личных данных вредоносным приложениям.

Посмотреть фокус

Объекты интерактивного View теперь также доступны по умолчанию. Если вы хотите, чтобы объект View был кликабельным, но не фокусируемым, установите для атрибута android:focusable значение false в XML-файле макета, содержащем View , или передайте false в setFocusable() в логике пользовательского интерфейса вашего приложения.

Сопоставление пользовательского агента при обнаружении браузера

Android 8.0 (уровень API 26) и выше включает строку идентификатора сборки OPR . Некоторые совпадения с шаблонами могут привести к тому, что логика обнаружения браузера ошибочно определит браузер, отличный от Opera, как Opera. Примером такого соответствия шаблону может быть:

if(p.match(/OPR/)){k="Opera";c=p.match(/OPR\/(\d+.\d+)/);n=new Ext.Version(c[1])}

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

Безопасность

Следующие изменения влияют на безопасность в Android 8.0 (уровень API 26):

  • Если конфигурация сетевой безопасности вашего приложения отказывается от поддержки открытого текстового трафика, объекты WebView вашего приложения не смогут получить доступ к веб-сайтам через HTTP. Вместо этого каждый объект WebView должен использовать HTTPS.
  • Системная настройка «Разрешить неизвестные источники» удалена; Вместо этого разрешение «Установка неизвестных приложений» управляет установкой неизвестных приложений из неизвестных источников. Дополнительные сведения об этом новом разрешении см. в руководстве «Разрешения на установку неизвестных приложений» .

Дополнительные рекомендации по повышению безопасности вашего приложения см. в разделе Безопасность для разработчиков Android .

Доступ к учетной записи и возможность обнаружения

В Android 8.0 (уровень API 26) приложения больше не могут получать доступ к учетным записям пользователей, если аутентификатор не владеет учетными записями или пользователь не предоставляет такой доступ. Разрешения GET_ACCOUNTS больше недостаточно. Чтобы получить доступ к учетной записи, приложения должны использовать AccountManager.newChooseAccountIntent() или метод, специфичный для аутентификатора. Получив доступ к учетным записям, приложение может вызвать AccountManager.getAccounts() для доступа к ним.

В Android 8.0 LOGIN_ACCOUNTS_CHANGED_ACTION устарел. Вместо этого приложения должны использовать addOnAccountsUpdatedListener() для получения обновлений об учетных записях во время выполнения.

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

Конфиденциальность

Следующие изменения влияют на конфиденциальность в Android 8.0 (уровень API 26).

  • Системные свойства net.dns1 , net.dns2 , net.dns3 и net.dns4 больше не доступны — изменение, улучшающее конфиденциальность на платформе.
  • Чтобы получить сетевую информацию, такую ​​как DNS-серверы, приложения с разрешением ACCESS_NETWORK_STATE могут зарегистрировать объект NetworkRequest или NetworkCallback . Эти классы доступны в Android 5.0 (уровень API 21) и более поздних версиях.
  • Build.SERIAL устарел. Приложениям, которым необходимо знать серийный номер оборудования, следует вместо этого использовать новый метод Build.getSerial() , для которого требуется разрешение READ_PHONE_STATE .
  • API LauncherApps больше не позволяет приложениям рабочего профиля получать информацию об основном профиле. Когда пользователь находится в рабочем профиле, API LauncherApps ведет себя так, как будто в других профилях в той же группе профилей не установлены приложения. Как и раньше, попытки доступа к несвязанным профилям вызывают исключения SecurityExceptions.

Разрешения

До Android 8.0 (уровень API 26), если приложение запрашивало разрешение во время выполнения и разрешение было предоставлено, система также неправильно предоставляла приложению остальные разрешения, которые принадлежали к той же группе разрешений и которые были зарегистрированы в манифест.

Для приложений, ориентированных на Android 8.0, это поведение было исправлено. Приложению предоставляются только те разрешения, которые оно явно запрашивает. Однако как только пользователь предоставляет разрешение приложению, все последующие запросы разрешений в этой группе разрешений автоматически предоставляются.

Например, предположим, что приложение содержит в своем манифесте как READ_EXTERNAL_STORAGE , так и WRITE_EXTERNAL_STORAGE . Приложение запрашивает READ_EXTERNAL_STORAGE , и пользователь предоставляет его. Если приложение предназначено для уровня API 25 или ниже, система также одновременно предоставляет WRITE_EXTERNAL_STORAGE , поскольку оно принадлежит к той же группе разрешений STORAGE и также зарегистрировано в манифесте. Если приложение предназначено для Android 8.0 (уровень API 26), система в это время предоставляет только READ_EXTERNAL_STORAGE ; однако, если приложение позже запросит WRITE_EXTERNAL_STORAGE , система немедленно предоставит эту привилегию, не запрашивая пользователя.

СМИ

  • Платформа может сама выполнять автоматическое приглушение звука . В этом случае, когда другое приложение запрашивает фокус с помощью AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK , приложение, имеющее фокус, уменьшает громкость, но обычно не получает обратный вызов onAudioFocusChange() и не теряет фокус звука. Доступны новые API-интерфейсы, позволяющие переопределить это поведение для приложений, которым необходимо приостанавливать работу, а не уклоняться от нее.
  • Когда пользователь отвечает на телефонный звонок, активные медиапотоки отключаются на время разговора.
  • Все API, связанные со звуком, должны использовать AudioAttributes , а не типы аудиопотоков, чтобы описать вариант использования воспроизведения звука. Продолжайте использовать типы аудиопотоков только для регулировки громкости. Другие варианты использования типов потока по-прежнему работают (например, streamType устаревшего конструктора AudioTrack ), но система регистрирует это как ошибку.
  • Если при использовании AudioTrack приложение запрашивает достаточно большой аудиобуфер, платформа попытается использовать вывод глубокого буфера, если он доступен.
  • В Android 8.0 (уровень API 26) обработка событий мультимедийных кнопок отличается:
    1. Обработка медиа-кнопок в активности пользовательского интерфейса не изменилась: действия на переднем плане по-прежнему имеют приоритет при обработке событий медиа-кнопок.
    2. Если действие переднего плана не обрабатывает событие кнопки мультимедиа, система направляет событие в приложение, которое последним воспроизводило звук локально. Активный статус, флаги и состояние воспроизведения мультимедийного сеанса не учитываются при определении того, какое приложение получает события мультимедийной кнопки.
    3. Если сеанс мультимедиа приложения был освобожден, система отправляет событие кнопки мультимедиа в MediaButtonReceiver приложения, если оно есть.
    4. Во всех остальных случаях система отбрасывает событие медиа-кнопки.

Родные библиотеки

В приложениях, предназначенных для Android 8.0 (уровень API 26), собственные библиотеки больше не загружаются, если они содержат какой-либо сегмент загрузки, который доступен как для записи, так и для выполнения. Некоторые приложения могут перестать работать из-за этого изменения, если у них есть собственные библиотеки с неправильными сегментами загрузки. Это мера по усилению безопасности.

Дополнительные сведения см. в разделе «Записываемые и исполняемые сегменты» .

Изменения компоновщика привязаны к уровню API, на который нацелено приложение. Если на целевом уровне API произошло изменение компоновщика, приложение не сможет загрузить библиотеку. Если вы нацеливаетесь на уровень API ниже уровня API, на котором происходит изменение компоновщика, logcat отображает предупреждение.

Обработка коллекции

В Android 8.0 (уровень API 26) Collections.sort() реализован поверх List.sort() . Обратное было верно в Android 7.x (уровни API 24 и 25): реализация List.sort() по умолчанию называлась Collections.sort() .

Это изменение позволяет Collections.sort() использовать преимущества оптимизированных реализаций List.sort() , но имеет следующие ограничения:

  • Реализации List.sort() не должны вызывать Collections.sort() , поскольку это приведет к переполнению стека из-за бесконечной рекурсии. Вместо этого, если вы хотите использовать поведение по умолчанию в своей реализации List , вам следует избегать переопределения sort() .

    Если родительский класс неправильно реализует sort() , обычно можно переопределить List.sort() реализацией, построенной на основе List.toArray() , Arrays.sort() и ListIterator.set() . Например:

    @Override
    public void sort(Comparator<? super E> c) {
      Object[] elements = toArray();
      Arrays.sort(elements, c);
      ListIterator<E> iterator = (ListIterator<Object>) listIterator();
      for (Object element : elements) {
        iterator.next();
        iterator.set((E) element);
      }
    }
    

    В большинстве случаев вы также можете переопределить List.sort() с помощью реализации, которая делегирует различные реализации по умолчанию в зависимости от уровня API. Например:

    @Override
    public void sort(Comparator<? super E> comparator) {
      if (Build.VERSION.SDK_INT <= 25) {
        Collections.sort(this);
      } else {
        super.sort(comparator);
      }
    }
    

    Если вы делаете последнее только потому, что хотите, чтобы метод sort() был доступен на всех уровнях API, рассмотрите возможность присвоения ему уникального имени, например sortCompat() , вместо переопределения sort() .

  • Collections.sort() теперь считается структурной модификацией в реализациях List, которые вызывают sort() . Например, в версиях платформы до Android 8.0 (уровень API 26) итерация по ArrayList и вызов sort() в середине итерации вызвали бы исключение ConcurrentModificationException , если сортировка выполнялась вызовом List.sort() . Collections.sort() не вызвал исключение.

    Это изменение делает поведение платформы более согласованным: любой подход теперь приводит к ConcurrentModificationException .

Поведение при загрузке классов

Android 8.0 (уровень API 26) проверяет, не нарушают ли загрузчики классов предположения среды выполнения при загрузке новых классов. Эти проверки выполняются независимо от того, ссылается ли класс на Java (из forName() ), байт-кода Dalvik или JNI. Платформа не перехватывает прямые вызовы из Java метода loadClass() и не проверяет результаты таких вызовов. Такое поведение не должно влиять на работу корректных загрузчиков классов.

Платформа проверяет, соответствует ли дескриптор класса, который возвращает загрузчик классов, ожидаемому дескриптору. Если возвращенный дескриптор не соответствует, платформа выдает ошибку NoClassDefFoundError и сохраняет в исключении подробное сообщение с указанием несоответствия.

Платформа также проверяет корректность дескрипторов запрошенных классов. Эта проверка перехватывает вызовы JNI, которые косвенно загружают классы, такие как GetFieldID() , передавая этим классам недопустимые дескрипторы. Например, поле с подписью java/lang/String не найдено, поскольку эта подпись недействительна; это должно быть Ljava/lang/String; .

Это отличается от вызова JNI FindClass() , где java/lang/String — допустимое полное имя.

Android 8.0 (уровень API 26) не поддерживает попытки нескольких загрузчиков классов определить классы с использованием одного и того же объекта DexFile. Попытка сделать это приводит к тому, что среда выполнения Android выдает ошибку InternalError с сообщением «Попытка зарегистрировать dex-файл <filename> с помощью нескольких загрузчиков классов».

DexFile API теперь устарел, и вам настоятельно рекомендуется использовать один из загрузчиков класса платформы, включая PathClassLoader или BaseDexClassLoader .

Примечание. Вы можете создать несколько загрузчиков класса, которые ссылаются на один и тот же контейнер файла APK или JAR из файловой системы. Обычно это не приводит к большому количеству накладных расходов памяти: если файлы DEX в контейнере хранятся вместо сжатия, платформа может выполнять операцию mmap на них, а не напрямую извлекать их. Однако, если платформа должна извлечь файл DEX из контейнера, ссылка на файл DEX в этом моде может потреблять много памяти.

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

Внимание: в версиях платформы ниже, чем Android 8.0 (уровень API 26), нарушение этих предположений может привести к определению одного и того же класса несколько раз, коррупции кучи из -за путаницы класса и других нежелательных эффектов.