В этой статье мы рассмотрим три самых важных изменения в новом Android, которые не могут быть проигнорированы ни одним разработчиком, который поставил у себя в проекте targetSdk = 23 и выше.
Doze Mode — режим «отключки», в который переходят все устройства на Marshmallow после некоторого времени обездвижения без зарядки.
App Standby — автоматическое лишение приложений доступа к ресурсам устройства, всех которые давно не открывал пользователь.
Runtime Permissions — новая модель запроса разрешений. Теперь мы, как разработчики, каждый раз обращаясь, например, к микрофону устройства, должны проверять, есть ли у нашего приложения разрешение на доступ к нему.
В Google в новом релизе Android сделали очень важный шаг в сторону оптимизации работы батареи. Все мы знаем, как пользователи любят повонять в комментариях высказываниями: «Дурацкие Google Play Services» жрут 25% батареи моего ******* S III, гопники, верните мне мой драгоценный айфон, нет сил, терпеть издевательства от Гугл". Только вот эти пользователи не ставили себе никогда Battery Historian и не в курсе, что жрут батарею бесплатные игры от сомнительных авторов и такие же сделанные на коленке живые обои, например. Но пользователь этого не знает, и как бороться с кучей левых приложений, беспощадно съедающих батарею, он не в курсе.
Ну теперь пользователям об этом заботиться и не придется. С приходом двух новых режимов Doze Mode и App Standby операционная система перекрывает кислород всем чрезмерно жрущим заряд приложениям. Как? Читаем далее:
Doze Mode
Когда устройство на Android Marshmallow лежит без движения и без зарядки, спустя час оно переходит в Doze Mode. Режим отключки, когда почти все приложения перестают жрать батарею.
Это происходит не сразу, а по шагам:
ACTIVE — Устройство используется или на зарядке
INACTIVE — Устройство недавно вышло из активного режима (пользователь выключил экран, выдернул зарядку и т.п.)
...30 минут
IDLE_PENDING — Устройство готовится перейти в режим ожидания
...30 минут
IDLE — Устройство в режиме бездействия
IDLE_MAINTENANCE — Открыто короткое окно, чтобы приложения выполнили свою работу
Мы можем продебажить наши приложения, переключаясь последовательно между этими шагами с помощью:
$ adb shell dumpsys deviceidle step
В момент, когда устройство переходит в состояние IDLE:
- Доступ приложению к сети отключен, пока приложение не получит high-priority GCM-push.
- Система игнорирует Wake lock’и. Приложения могут сколько угодно пытаться запросить пробуждение процессора — они их не получат.
- Alarm’ы запланированные в AlarmManager не будут вызываться, кроме тех, которые будут обновлены с помощью setAndAllowWhileIdle().
- Система не производит поиска сетей Wi-Fi.
- NetworkPolicyManagerService: пропускает только приложения из белого списка.
- JobSchedulerService: все текущие задачи отменяются. Новые откладываются до пробуждения.
- SyncManager: все текущие отменяются, новые откладываются до пробуждения.
- PowerManagerService: только задачи приложений из белого списка вызовутся.
Соответственно, если наше приложение чат, то мы можем отправить с сервера push с полем priority = high.
А если у нас приложение будильник, то мы должны обязательно вызвать для Alarm setAndAllowWhileIdle() или setExactAndAllowWhileIdle().
Во многих других случаях мы вообще не должны об этом переживать, после того, как пользователь возьмет устройство в руки, все заснувшие alarm'ы и SyncAdapter'ы проснутся и сделают свою работу. (Да-да я знаю, что после выхода из doze mode все начинает синкаться и даже Nexus 9 минуты две тормозит)
App Standby
Но не только при попадании устройство в Doze Mode наши приложения будут лишены возможности разряжать батарею. Второй режим под название App Standby отправляет в такую же изоляцию приложения, которые не подходят под условия:
- Пользователь явно запустил приложение.
- Приложение имеет процесс, работающий в данный момент на переднем плане (Activity или foreground service, или используется другой activity или foreground service’ом).
- Приложение создало уведомление, которое висит в списке уведомлений.
- Пользователь принудительно добавил приложение в список исключений оптимизации в настройках системы
Исключения
Возможно сейчас разработчики коммерческих voip нервно начали продумывать, как запретить обновляться своим пользователям на пугающий своей жесткостью Android Marshmallow. Но не волнуйтесь, есть специальный Whitelist, в который пользователь руками может добавить исключения. Приложениям из Whitelist не страшны ни Doze Mode ни App Standby.
Чтобы проверить, попало ли наше приложение в Whitelist вызываем метод isIgnoringBatteryOptimizations().
Пользователь может сам руками добавить/удалить из списка в настройках Settings > Battery > Battery Optimization
Но мы можем его сами попросить с помощью интента ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS или запросив пермишен REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, который покажет диалог на автоматическое добавление в вайтлист с разрешения пользователя.
Подробнее:
developer.android.com/intl/ru/training/monitoring-device-state/doze-standby.html#support_for_other_use_cases
newcircle.com/s/post/1739/2015/06/12/diving-into-android-m-doze
Runtime Permissions
Мы подобрались к самому известному изменению в Android Marshmallow. Более того это изменение требует от нас наибольшего вовлечения в перелопачивание кода приложения. Кратко говоря: халява кончилась.
Да-да, каждый раз, когда наше приложение обращается, например, с запросом на местоположение пользователя, мы должны проверить, есть ли у приложения разрешение от пользователя на это действие. Если есть — обращаемся к нужным нам системным ресурсам, если нет — запрашиваем. Так же пользователь может навсегда приложению запретить доступ, тогда единственный наш шанс — это попросить его самого зайти в настройки и снять запрет, показав ему объясняющее сообщение, зачем нам нужен доступ.
Стоит отметить, что Permissions в Android делятся на два типа:
- Нормальные разрешения, вроде доступа к сети и bluetooth.
- Опасные разрешения. В этот список входят разрешения на: календарь, камеру, контакты, местоположение, микрофон, телефон, сенсоры, смс и внешнее хранилище
Вот как раз все опасные разрешения мы и должны постоянно проверять, ибо пользователь может в любой момент их запретить. Да и при первом старте доступа у приложения к ним нет.
Итак, последовательность наших шагов:
- Описать только PROTECTION_NORMAL запросы в manifest
- Пользователь их все подтвердит при установке
- Когда приложению нужен доступ к одному или нескольким разрешениям из группы опасных, проверить, нет ли разрешения
- Если разрешения нет — запросить
- Если разрешения не будет — объяснить, на что это повлияет
- Если разрешение получено — продолжить работу
Чтобы проверить доступность разрешения дергаем ContextCompat.checkSelfPermission (Context context, String permission).
Чтобы запросить разрешения, показав системный диалог, вызываем ActivityCompat.requestPermissions();
Результат этого запроса придет в асинхронный колбэк в активити onRequestPermissionsResult(), в нем мы узнаем решение пользователя по каждому из запрошенных разрешений.
Запрашивать лишь те разрешения, которые действительно нужны. До сих пор в Google Play находятся разработчики, которые запрашивают все подряд
Если есть возможность, вместо запроса воспользоваться внешним Intent. Например, для фото или видео часто нет смысла встраивать камеру в приложение, гораздо проще воспользоваться внешним приложением
Запрашивать разрешение, только перед тем, когда оно понадобится. Запрашивать при старте приложения все разрешения нелогично (из тех, которые нам нужны), их смысл как раз в том, что мы запрашиваем их в контексте их использования.Например, пользователю становится понятно зачем его банковскому клиенту доступ к контактам — чтобы выбрать одного при шаринге по ФИО
Пояснять пользователю, для чего запрашивается разрешение. Если пользователь все же запретил приложению доступ, а без него оно не может, оно должно максимально понятно объяснить, что без этого разрешения оно работать дальше не будет
Подробнее: developer.android.com/intl/ru/training/permissions/requesting.html
Подкаст о пермишенах: androidbackstage.blogspot.ru/2015/08/episode-33-permission-mission.html
Семпл от Google: developer.android.com/intl/ru/samples/RuntimePermissions/index.html
Мой семпл на github: github.com/nekdenis/Permissions_sample
Сегодня мы поговорили о самых заметных изменениях в Android Marshmallow. Так же обязательно прочтите полностью вторую статью про остальные изменения и нововведения в Marshmallow. Спасибо за внимание и скорейшую оптимизацию ваших приложений под новый Android!