В этой статье мы рассмотрим три самых важных изменения в новом 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!

Комментарии (15)


  1. AllexIn
    03.11.2015 11:43
    +4

    А что будет со старыми приложениям, у которых опасные permissions прописаны в манифесте?


    1. nekdenis
      03.11.2015 11:49
      +7

      Если у них targetSdk 22 или ниже, то все будет хорошо, пермишены они получат автоматом.
      Но пользователь может зайти в настройки, и запретить приложению доступ к любому из сервисов, например, к камере. Его система предупредит:«Не надо так, приложение не оптимизировано, может упасть!».
      Но он все равно может запретитить. В этом случае SecurityException не вывалится, а будут следующие сценарии, для локейшн и камеры, к примеру, будут возвращены null, для контактов — пустой список или пустой контакт.


      1. oWeRQ
        03.11.2015 15:40

        Тогда какой стимул будет для «плохих» приложений обновлять sdk на > 22?


        1. petrovichtim
          03.11.2015 15:52
          +2

          Как бы более низкая выдача в поиске.


          1. samodum
            04.11.2015 05:36
            +1

            Как бы это не самое страшное для «плохих» приложений


        1. nekdenis
          03.11.2015 17:28

          фишки нового api не задействовать, саппорты новые не запустить, плей сервисы — много всего


          1. thevery
            03.11.2015 22:41
            +1

            А что с саппортами не так? И разве android будет принудительно «портить» фичи при старом targetSdk?


        1. AllexIn
          03.11.2015 21:33

          Нет смысла оставаться на старом SDK. Всё равно ОС не даст разрешения или пользователь их отрубит, а отреагировать на старом SDK не получится корректно.


          1. thevery
            03.11.2015 22:44
            +3

            Имхо шансы на отключение пермишшенов в настройках во много раз ниже, чем на запрет прямо при запросе приложения.


  1. dumistoklus
    03.11.2015 14:12
    +3

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


    1. AllexIn
      04.11.2015 10:08

      Ну это логично, ведь они в манифесте. И если приложение запустилось, предполагается, что разрешения все уже даны и ничего проверять не нужно.
      Опять же, отозвать можно — через удаление приложения.


  1. VioletGiraffe
    06.11.2015 09:45

    Doze Mode может серьёзно поломать моё приложение, предвижу жалобы от пользователей. Моя софтина коннектится к цифровой камере и управляет ею по проводу или Wi-Fi. Вот как, например, снимать time lapse, который может длиться много часов, если через час девайс заснёт, невзирая на мой wake lock?


    1. andrey7mel
      06.11.2015 12:14
      +2

      При старте просить добавить свое приложение в Whitelist (… Приложениям из Whitelist не страшны ни Doze Mode ни App Standby).


      1. VioletGiraffe
        06.11.2015 12:19

        Спасибо!


  1. coder1cv8
    06.11.2015 12:46
    +1

    Вот еще хорошая заметка о новом механизме Permissions: code.tutsplus.com/articles/understanding-permissions-in-android-m--cms-24443 (eng). Вот прямо сегодня добавлял в одно из своих приложений, все просто и понятно.