Перевод первой половины статьи об изменениях в Android 8.0. Как обычно, я рекомендую вам читать оригинал: https://developer.android.com/about/versions/oreo/android-8.0-changes.html Свои комментарии я пометил курсивом.
Android 8.0 (API level 26), кроме новых возможностей и разных плюшек, некоторые привычные поведения системы и API. В этой статье описываются некоторые ключевые изменения, которые вам необходимо понимать и учитывать при разработке приложений.
И хотя большинство этих изменений затрагивают все приложения и не важно, какая версия Android указана как target, есть и такие, которые повлияют лишь на те приложения, которые объявили в манифесте о готовности к Android 8.0. Для упрощения чтения, статья была разделена на две: приложения с любым target API level и приложения с target на Android 8.0.
Приложения с любым target API level
Изменения поведений, описанные в этой статье, применимы ко всем приложениям, работающим на Android 8.0 и не важно, какой API level был задан в target. Все разработчики (и тестировщики!) должны ознакомиться с этими изменениями и модифицировать приложения для их нормальной поддержки, если это потребуется.
Ограничения фоновых операций
Одним из изменений, представленным в Android 8.0 (API level 26), является улучшение жизни батарейки. Теперь, когда приложение входит в кешированное состояние (см. cached state) и не имеет активных компонентов (см. components), система отпускает все вейклоки, которые удерживало это приложение.
Кроме того, для увеличения производительности устройства, система накладывает на приложения некоторые ограничения, если эти приложения в данный момент находятся не на переднем плане. К примеру:
- Приложения, работающие в фоне, теперь имеют ограничения на свободный доступ к фоновым сервисам.
- Приложения не могут использовать манифест для регистрации большинства неявных бродкастов (то есть бродкастов, которые не нацелены на какое-то вполне конкретное приложение).
По умолчанию эти ограничения применимы только к приложениям с таргетом на O. Однако пользователь может включить эти ограничения для любого приложения из экрана Настройки, даже если производитель не заявлял поддержку Android 8.
Также Android 8 включает следующие изменения конкретных методов:
- Теперь метод startService() бросает IllegalStateException, если приложение с таргетом на Android 8 пытается использовать этот метод в ситуации, когда ему уже не позволяется создавать фоновые сервисы.
- Новый метод Context.startForegroundService() запускает, собственно, фореграунд сервис. Система позволяет приложениям вызывать Context.startForegroundService() даже когда приложение находится в бэкграунде. Тем не менее, приложение обязано вызывать метод startForeground() у сервиса в пределах пяти секунд после того, как сервис создан.
Для дополнительной информации смотри Background Execution Limits. Если я переведу эту статью, а планы на это есть, пните меня, чтобы я обновил здесь ссылку.
Ограничения получения местоположения из фона
Дабы оберегать батарею, нервы пользователя и здоровье системы, на устройствах, работающих под Android 8.0, фоновые приложения реже получают обновления местоположения. Это изменение затрагивает все приложения, получающие геолокацию, включая Google Play сервисы.
Эти изменения затрагивают следующие API:
- Fused Location Provider (FLP)
- Geofencing
- GNSS Measurements
- Location Manager
- Wi-Fi Manager
Чтобы проверить, что ваши приложения работают так, как ожидается, выполните следующее:
- Просмотрите логику приложений и убедитесь, что вы используете самые последние location API.
- Проведите тесты, которые покажут, является ли поведение ожидаемым в каждом из кейсов.
- Рассмотрите возможность использования Fused Location Provider (FLP) или geofencing в сценариях, когда поведение зависит от местоположения пользователя.
Для дополнительной информации смотри Background Location Limits. Если я всё же переведу и эту статью, пните, чтобы я ссылку добавил и на перевод тоже.
Ярлыки приложений
Android 8.0 (API level 26) включает следующие изменения для ярлыков приложений:
- Ваше приложение не получит com.android.launcher.action.INSTALL_SHORTCUT, потому что теперь это приватный неявный бродкаст. Вместо этого вы должны создать ярлык приложения, используя метод requestPinShortcut() класса ShortcutManager.
- Теперь интент ACTION_CREATE_SHORTCUT может создавать ярлыки приложений, которыми вы можете управлять, используя класс ShortcutManager. Этот интент также создаёт легаси ланчер шорткат, который не взаимодействует с ShortcutManager. Ранее этот интент мог создать только легаси ланчер шортакт.
- Ярлыки, созданные с использованием requestPinShortcut() и ярлыки, созданные в активити с использованием интента ACTION_CREATE_SHORTCUT теперь являются полноценными ярылками приложений. Как результат, приложения могут обновлять их, используя методы в ShortcutManager.
- Легаси ярлыки сохраняют возможности из предыдущих версий Android, но вы обязаны сконвертировать их в ярлыки приложений для вашего приложения вручную.
Чтобы узнать больше об изменениях ярлыков приложений, смотри Pinning Shortcuts and Widgets preview feature guide.
Локали и интернационализация
В Android 7.0 (API level 24) была представлена концепция, которая была способна определять категорию локали по умолчанию, но некоторые API продолжали использовать универсальный метод Locale.getDefault() без аргументов, тогда как должны были использовать дефолтную категорию DISPLAY в Locale. Теперь, в Android 8, следующие методы используют Locale.getDefault(Category.DISPLAY) вместо Locale.getDefault():
Также Locale.getDisplayScript(Locale) возвращает Locale.getDefault(), когда значение displayScript, определённое в аргументе Locale, недоступно.
Другие изменения, связанные с локалью и интернационализацией:
- Вызов Currency.getDisplayName(null) бросает NullPointerException. Так что теперь всё работает именно так, как всегда было описано в документации.
- Изменился парсинг имени тайм зоны. Раньше устройства под Android использовали значение системных часов, полученное во время загрузки, откуда кешировалась тайм зона, используемая для парсинга даты/времени. Это могло иметь негативные последствия, если системные часы были неправильным в момент загрузки.
Теперь в подобных ситуациях парсер использует ICU (предполагаю, что речь об этом: http://site.icu-project.org/) и текущее значение системных часов для разбора имён тайм зон. Это изменение даёт более правильный результат, который может отличаться от тех, что были в предыдущих версиях Android, если в ваших приложениях использовались классы типа SimpleDateFormat.
- В Android 8.0 версия ICU обновлена до 58.
Алерты
Если приложение использует пермишен SYSTEM_ALERT_WINDOW и для показа алерта поверх других приложений и системных окон использует любой из этих типов окон:
… то эти окна всегда появляются под окнами, которые имеют тип TYPE_APPLICATION_OVERLAY. Если приложение имеет таргет Android 8 (API level 26), приложение должно использовать тип TYPE_APPLICATION_OVERLAY для отображения алерта.
Для дополнительной информации смотрите секцию Common window types for alert windows раздела Apps targeting Android 8. (TODO: ПОПРАВИТЬ ССЫЛКУ, ЧТОБЫ ОНА ВЕЛА НА БЛОГ, КОГДА СДЕЛАЮ ПЕРЕВОД)
Ввод и перемещение по элементам
С приходом приложений Android в Chrome OS и на другие большие форм факторы, такие как планшеты, мы увидели возрождение клавиатурной навигации по этим Android приложениям. В Android 8.0 (API level 26) мы повторно рассмотрели использование клавиатуры как устройства навигации. В результате получилась более надёжная и предсказуемая модель навигации, основанная на стрелках и табах.
В частности, мы сделали следующие изменения в поведении элементов в фокусе:
Если вы не хотите, чтобы View использовал подсветку фокуса по умолчанию, установите атрибут android:defaultFocusHighlightEnabled в false в файле layout XML, содержащем этот View, либо передайте false в setDefaultFocusHighlightEnabled() в UI логике приложения.
- Для понимания, как клавиатурный ввод влияет на элементы в фокусе, включите Drawing > Show layout bounds в developer option. В Android 8.0 эта опция отображает иконку "X" поверх элемента в фокусе.
Кроме того, все тулбары в Android 8 автоматически объединяются в keyboard navigation clusters (группы навигации с клавиатуры?), что облегчает пользователям переключения от одного тулбара к другому, а также переходы в пределах каждого тулбара.
Автозаполнение форм
Теперь Android Autofill Framework предоставляет встроенную поддержку автозаполнения. Для приложений, запущенных под Android 8 изменены следующие методы объекта WebView:
- Теперь метод hasFormData() возвращает false. Раньше этот метод возвращал true, если форма содержала данные.
Accessibility
Android 8.0 (API level 26) имеет следующие изменения сервиса специальных возможностей:
- Теперь accessibility framework конвертирует все дабл-тапы в ACTION_CLICK. Это изменение позволило TalkBack’у вести себя так же, как другие сервисы специальных возможностей.
- Если в вашем приложении объекты View используют самописное определение нажатий, вам нужно проверить, что они продолжают работать с TalkBack. Вам нужно лишь зарегистрировать обработчик клика в объектах View. Если TalkBack по-прежнему не распознаёт выполняемые действия на ваших вьюхах, переопределите performAccessibilityAction().
- Теперь сервисы специальных возможностей знают обо всех экземплярах ClickableSpan внутри объектов TextView вашего приложения.
Чтобы узнать больше, как сделать приложение более удобным для людей с ограниченными возможностями, посмотрите Accessibility.
Сети и HTTP(S) подключения
Android 8 включает следующие изменения, связанные с сетями и HTTP(S) подключениями:
- Запрос OPTIONS без тела имеет хедер Content-Length: 0. Ранее Content-Length хедера не было.
- HttpURLConnection нормализует URLы, содержащие пустые путьи, добавлением слеша после хоста или authority имени со слешом. Например, http://example.com будет нормализован в http://example.com/.
- Кастомный прокси селектор, установленный через ProxySelector.setDefault() предназначен только для адреса (схема, хост и порт) запрашиваемого URL. Как результат, выбор прокси может основываться только на этих значениях. URL, переданный кастомному прокси селектору, не включает полный путь, параметры запроса или фрагменты.
- URI не могут содержать пустые метки.
Раньше платформа имела обходной вариант для разрешения пустых меток в именах хостов, что есть неправильное использование URI. Этот обходной вариант существовал для совместимости со старыми версиями libcore. Разработчики, некорректно использующие API, видели сообщение ADB: "URI example..com has empty labels in the hostname. This is malformed and will not be accepted in future Android releases." В Android 8.0 обходной путь удалён; система возвращает null для кривых URI.
- Реализованный в Android 8 HttpsURLConnection не переключает на предыдущие уязвимые протоколы TLS/SSL.
- Обработка туннельных HTTP(S) соединений изменилась следующим образом:
- При туннелировании HTTPS подключений система корректно помещает номер порта (:443) в строку хоста и отправляет эту информацию на промежуточный сервер. Ранее номер порта появлялся только в CONNECT.
- Система больше не отправляет хедеры user-agent и proxy-authorization из туннелированного запроса на прокси сервер.
При установке туннеля система больше не отправляет к прокси в Http(s)URLConnection хедер proxy-authorization. Вместо этого система генерирует хедер proxy-authorization и отправляет его этой проксе, если та присылает HTTP 407 в ответ на первоначальный запрос.
Похожим образом, при настройке туннельного подключения, система более не копирует хедер user-agent из туннельного запроса на запрос прокси. Вместо этого, на этот запрос прокси, библиотека генерирует хедер user-agent.
- Метод send(java.net.DatagramPacket) бросает SocketException, если предыдущее выполнение метода connect() провалилось.
- DatagramSocket.connect() устанавливает pendingSocketException в случае внутренней ошибки. До Android 8 последующий вызов recv() бросал SocketException даже когда вызов send() был успешным. Для единообразия, теперь оба вызова бросают SocketException.
- InetAddress.isReachable() пытается использовать ICMP перед переключением на протокол TCP Echo.
- Некоторые хосты блокирующие порт 7 (TCP Echo), к примеру google.com, теперь могут стать доступными, если протокол ICMP Echo они всё же принимают.
- Для действительно недоступных хостов это означает, что из-за двойного запроса на получение результата вызова будет затрачено больше времени.
Bluetooth
В Android 8 (API level 26) сделаны следующие изменения длины получаемых от метода ScanRecord.getBytes() данных:
- Метод getBytes() не делает никаких предположений количестве получаемых байтов. Потому приложения не должны зависеть от минимума или максимума количества возвращаемых байтов. Вместо этого они должны считать длину возвращаемого массива.
- Устройства с Bluetooth 5 могут возвращать данные длиной, превышающей предыдущий максимум в ~60 байт.
- Если же удалённое устройство не отвечает на запросы сканирования, может быть возвращено меньше 60 байт.
Плавные подключения
В Android 8 сделаны улучшения в настройках Wi-Fi, дабы проще было выбрать ту Wi-Fi сеть, с которой пользователю наиболее удобно работать. Суть изменений:
- Улучшения стабильности и надёжности.
- Более интуитивно понятный UI.
- Единое меню Wi-Fi Preferences.
- Для совместимых устройств: автоматическая активация Wi-Fi при нахождении поблизости с высококачественной сохранённой сетью.
Безопасность
Android 8 включает следующие изменения по части безопасности:
- SSLv3 больше не поддерживается.
- При установке HTTPS подключения к серверу с кривой имплементацией согласования версий протоколов TLS, HttpsURLConnection больше не будет использовать ворэкраунд с обратной совместимостью и не будет переключаться на предыдущие уязвимые версии TLS.
- В Android 8 для всех приложений применяется Secure Computing (SECCOMP) фильтр. Список разрешённых системных вызовов ограничен через bionic. И хотя для обратной совместимости некоторые из вызовов разрешены, мы строго рекомендуем их не использовать.
- Объекты WebView ваших приложений теперь работают в многопроцессорном режиме. Web контент находится в отдельном процессе, изолированном от процесса вашего приложения, что улучшает безопасность.
- Вы больше не можете предполагать, что APK ваших приложений находятся в директориях, названия которых заканчиваются на -1 или -2. Приложения должны использовать sourceDir для получения директории.
- Для информации об улучшениях безопасности, связанных с нативными библиотеками, смотрите Native Libraries.
Дополнительно к этому, в Android 8.0 (API level 26) представлены следующие изменения, связанные с установкой неизвестных приложений из неизвестных источников:
- Значение устаревшей настройки INSTALL_NON_MARKET_APPS теперь всегда 1. Для понимания, может ли какое-то приложение устанавливать другие приложения, смотрите, что вам возвращает canRequestPackageInstalls() для него.
- Если вы попытаетесь изменить значение INSTALL_NON_MARKET_APPS, используя setSecureSetting(), будет выброшено UnsupportedOperationException. Чтобы запретить пользователям установки непонятных приложений из неизвестных источников, вы должны установить ограничение DISALLOW_INSTALL_UNKNOWN_SOURCES.
- Управляемые профили, созданные на устройствах под Android 8.0 (API level 26), автоматически получают ограничение DISALLOW_INSTALL_UNKNOWN_SOURCES. Для существующих управляемых профилей, для устройств, обновившихся на Android 8.0, ограничение DISALLOW_INSTALL_UNKNOWN_SOURCES также включено по умолчанию, кроме случаев, когда владелец профиля явно отключил его перед обновлением, выставив настройку INSTALL_NON_MARKET_APPS в 1.
Дополнительную информацию об установке неизвестных приложений, смотрите Unknown App Install Permissions.
Для дополнительных указаний, как сделать ваше приложение более безопасным, смотрите Security for Android Developers.
Приватность
В Android 8 сделали следующие изменения, связанные с приватностью:
- Теперь система иначе обрабатывает идентификаторы:
- Для приложений, установленных до получения OTA до Android 8 (API level 26), значение ANDROID_ID после получения OTA остаётся без изменений до тех пор, пока они не будут удалены и установлены заново. Для сохранения значениий межу переустановками после получения OTA, разработчики могут связать старые и новые значения через Key/Value Backup.
- Для приложений, устанавливаемых на устройство, работающим под Android 8, значение ANDROID_ID зависит и от ключа подписи приложения, и от пользователя. Значение ANDROID_ID уникально для каждой связки “ключ подписи приложения, пользователь, устройство”. Как результат, приложения с разной подписью не получат один и тот же Android ID даже под одним и тем же пользователем.
- Значение ANDROID_ID не изменяется при перестановках приложений, если не изменялась подпись (ну и если приложения не было установлено до получения OTA с Android 8 и удалено после получения).
- Значение ANDROID_ID не изменяется при обновлении системы. Предполагаю, что речь об обновлениях безопасности, т.к. что будет в Android P пока вряд ли знает и сам Google.
Для простой монетизации приложений используйте Advertising ID. Advertising ID — это уникальный ID, предоставляемый Google Play services для рекламы. Пользователь может его сбрасывать.
- Запрос системного параметра net.hostname возвращает null.
Логгирование не перехваченных исключений
Если приложение ставит Thread.UncaughtExceptionHandler, которое не вызывается через дефолтный Thread.UncaughtExceptionHandler, система не убивает приложение при возникновении не перехваченного исключения. Начиная с Android 8, в этой ситуации система запишет stacktrace (в предыдущих версиях платформы система бы не его не записала).
Мы рекомендуем, чтобы кастомные реализации Thread.UncaughtExceptionHandler всегда вызывались через дефолтный обработчик. Приложения, которые следуют этой рекомендации, никак не затронуты изменением в Android 8.
Изменение статистик использования в Contacts provider
В предыдущих версиях Android, компонент Contacts Provider позволял разработчикам получать разные данные для каждого контакта. В этих данных была информация по каждому email адресу и каждому телефонному номеру контакта и даже сколько раз была установлена связь с этим контактом. Приложения, получившие READ_CONTACTS могли читать эти данные.
Начиная с Android 8, приложения по-прежнему могут читать эти данные, если получают пермишен READ_CONTACTS. Однако при запросе данных об использовании, система вернёт не точные, а приблизительные значения. Так что это изменение на затрагивает auto-complete API.
Изменение поведения затрагивает следующие запросы:
Обработка коллекций
Теперь AbstractCollection.removeAll() и AbstractCollection.retainAll() всегда бросают NullPointerException. Ранее, если коллекция была пустой, NullPointerException’а не было. Это изменение сделало поведение таким, как оно описано в документации.
Android enterprise
Android 8 изменяет поведение некоторых API и фич для корпоративных решений, включая политики контроля устройства (device policy controllers, DPC). Изменения включают:
- Новые поведения, помогающие приложениям поддерживать рабочие профили на полностью управляемых устройствах.
- Изменения обработки обновлений системы, проверки приложений и аутентификации для лучшей интеграции с устройством и системой.
- Улучшения при работе с уведомлениями, экраном списка задач, VPN.
Чтобы узнать все изменения Android 8, касающиеся корпоративных решений и понять, как они затрагивают ваши приложения, прочтите Android in the Enterprise.
Продолжение читайте в статье «Изменения в поведениях Android 8.0. Часть 2: Приложения с target API level 26»
Продолжение читайте в статье «Изменения в поведениях Android 8.0. Часть 2: Приложения с target API level 26»
Комментариев нет:
Отправить комментарий