Android 6.0: Doze Mode, App Standby, Runtime Permissions. Всё, что необходимо знать каждому разработчику


    В этой статье мы рассмотрим три самых важных изменения в новом 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 делятся на два типа:
    1. Нормальные разрешения, вроде доступа к сети и bluetooth.
    2. Опасные разрешения. В этот список входят разрешения на: календарь, камеру, контакты, местоположение, микрофон, телефон, сенсоры, смс и внешнее хранилище


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

    Итак, последовательность наших шагов:
    • Описать только 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!
    Метки:
    Поделиться публикацией
    Похожие публикации
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 17
    • +4
      А что будет со старыми приложениям, у которых опасные permissions прописаны в манифесте?
      • +7
        Если у них targetSdk 22 или ниже, то все будет хорошо, пермишены они получат автоматом.
        Но пользователь может зайти в настройки, и запретить приложению доступ к любому из сервисов, например, к камере. Его система предупредит:«Не надо так, приложение не оптимизировано, может упасть!».
        Но он все равно может запретитить. В этом случае SecurityException не вывалится, а будут следующие сценарии, для локейшн и камеры, к примеру, будут возвращены null, для контактов — пустой список или пустой контакт.
        • 0
          Тогда какой стимул будет для «плохих» приложений обновлять sdk на > 22?
          • +2
            Как бы более низкая выдача в поиске.
            • +1
              Как бы это не самое страшное для «плохих» приложений
            • 0
              фишки нового api не задействовать, саппорты новые не запустить, плей сервисы — много всего
              • +1
                А что с саппортами не так? И разве android будет принудительно «портить» фичи при старом targetSdk?
              • 0
                Нет смысла оставаться на старом SDK. Всё равно ОС не даст разрешения или пользователь их отрубит, а отреагировать на старом SDK не получится корректно.
                • +3
                  Имхо шансы на отключение пермишшенов в настройках во много раз ниже, чем на запрет прямо при запросе приложения.
          • +3
            А еще важное замечание: нормальные разрешения пользователь не может отозвать, если они уже были даны при установке приложения
            • 0
              Ну это логично, ведь они в манифесте. И если приложение запустилось, предполагается, что разрешения все уже даны и ничего проверять не нужно.
              Опять же, отозвать можно — через удаление приложения.
            • 0
              Doze Mode может серьёзно поломать моё приложение, предвижу жалобы от пользователей. Моя софтина коннектится к цифровой камере и управляет ею по проводу или Wi-Fi. Вот как, например, снимать time lapse, который может длиться много часов, если через час девайс заснёт, невзирая на мой wake lock?
              • +2
                При старте просить добавить свое приложение в Whitelist (… Приложениям из Whitelist не страшны ни Doze Mode ни App Standby).
              • 0
                А если у нас приложение будильник, то мы должны обязательно вызвать для Alarm setAndAllowWhileIdle() или setExactAndAllowWhileIdle().
                Хоть автор и заблуждается насчёт будильника, эти методы действительно разбудят телефон (AlarmManager API23+).

                А для будильника нужно продолжать использовать setAlarmClock().
              • +1
                Вот еще хорошая заметка о новом механизме Permissions: code.tutsplus.com/articles/understanding-permissions-in-android-m--cms-24443 (eng). Вот прямо сегодня добавлял в одно из своих приложений, все просто и понятно.
                • 0
                  Описать только PROTECTION_NORMAL запросы в manifest


                  Небольшое уточнение, в manifest нужно описывать все permissions, а не только из normal категории. Отличие в том, что для normal, разрешения система выдаст автоматически, а для остальных нужно будет воспользоваться новой схемой запроса разрешений в коде. Очевидно, что в manifest запросы пригодятся системе и для обратной совместимости.

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