Далеко не всегда устройства с операционной системой Android используются как персональный гаджет. Иногда они служат одной конкретной бизнес-цели, и необходимость в предустановленных свойствах девайса отпадает.
В этой статье рассказываем, как мы в Программные технологии используем несколько простых манипуляций с Android Management API, чтобы заблокировать ненужные функции без root-прав.
Каждый из нас хоть раз в жизни имел дело с корпоративными девайсами:
- в случае клиентских приложений они используются для покупки билетов, заказа еды в ресторанах, регистрации гостей и т.д;
- в случае корпоративных — это могут быть приложения для менеджеров по продажам, курьеров, логистов, системы управления складскими запасами и т.д.
При такой эксплуатации часто требуется ограничить устройство одним приложением. Иногда для этих целей используются специализированные компьютеры, но по сути любой планшет или смартфон можно превратить в то, что в документации по Android-разработке называют Dedicated device.
В нашей компании разрабатывается много enterprise-приложений, из-за чего мы часто сталкиваемся с необходимостью блокировки функций на dedicated devices. Например, в нашей практике было приложение для инженеров по безопасности на промышленных предприятиях. Эти специалисты ходят по заводу, следят за исправностью трубопроводов и должны куда-то заносить собранные данные:
Компания-заказчик закупила для этой цели несколько десятков смартфонов на Android и заказала нам приложение со следующими требованиями:
- на экране всегда должно присутствовать выбранное приложение без возможности запуска других приложений. Соответственно, должны быть заблокированы кнопки “Назад”, “Домой” и “Последние приложения”;
- выбранное приложение должно запускаться сразу же после перезагрузки;
- заблокировать возможность изменять какие-либо настройки на устройстве;
- заблокировать возможность взаимодействия со статус-баром, т.к. там возможно менять настройки;
- заблокировать возможность открывать пуш-уведомления;
- экран устройства не должен гаснуть.
Часть этого функционала можно реализовать довольно просто, однако на текущий момент устройство без root-прав не позволяет как-либо блокировать взаимодействие со статус-баром и пуш-уведомлениями. Также не удастся ничего сделать с кнопкой “Последние приложения”.
Тут на помощь приходит Android Management API и device policy controller (DPC), которые позволят выполнять настройку корпоративных устройств в кратчайшие сроки и по своему усмотрению блокировать любые функции.
Инструменты для управления устройством: Device policy controller и Android Management API
DPC — это приложение, которое может контролировать разрешения других приложений, а также блокировать различные функции устройства. Соответственно, используя кастомный DPC, мы можем в том числе скрывать статус-бар и блокировать системные кнопки на устройстве.
Написание собственного DPC довольно трудозатратно, т.к. включает в себя написание целого приложения, единственная функция которого — ограничивать возможности пользователя при работе с устройством. Кроме того, любые изменения в политике устройства придётся внедрять в коде, что повлечет за собой выпуск новой версии этого приложения.
Чтобы упростить жизнь разработчикам таких решений, Google в 2017 году выпустил свой DPC, который называется Android Device Policy и управляется с помощью Android Management API. Чтобы использовать Android Management API, нужно выполнить несколько шагов:
- Создать сервисный аккаунт. Этот шаг является опциональным и нужен для вызова методов API из кода (с бэкенда или из web-консоли, которую также нужно писать самим), поскольку такие вызовы требуют аутентификации через OAuth.
- Создать политику (policy). Это тот самый набор правил и ограничений, который будет применен к устройству. Когда мы изменяем что-либо в policy, все устройства, к которым она применена, автоматически обновляют своё состояние в соответствии с изменениями без каких-либо дополнительных действий с нашей стороны.
- Зарегистрировать устройство (device). Чтобы применить созданную политику к устройству, нужно создать EnrollmentToken, привязанный к выбранной policy. Затем устройство нужно сбросить к заводским настройкам, т.к. установить DPC в качестве Device owner’а можно только в момент первичной настройки системы. Это работает для устройств с ОС Android 6.0 и выше, подробности можно найти в официальной документации. Самый простой способ передать токен на устройство — сформировать QR-код на его основе. JSON для формирования QR-кода можно получить из поля qrCode у ресурса EnrollmentToken. Чтобы отсканировать QR-код, нужно тапнуть 6 раз в одном и том же месте на первом экране, появившемся после сброса заводских настроек (обычно на нём мы выбираем язык), после чего будет предложено подключиться к интернету и скачать сканер QR-кодов. Если же этот способ не сработал на выбранном устройстве, можно дойти до этапа ввода данных Google-аккаунта и ввести туда afw#setup.
Google предоставляет несколько опций, позволяющих пользоваться Android Management API. Самый простой способ выполнить все эти шаги — пройти интерактивный quickstart guide. Для обращения к API из кода можно использовать одну из библиотек на Java, .NET, Python или Ruby.
Использование Android Management API для создания SingleApp-устройства
Вернёмся теперь к списку требований для Dedicated device и рассмотрим, как их можно реализовать с помощью policy. Чтобы выбранное приложение всегда присутствовало на экране и запускалось автоматически после перезагрузки, оно должно заменить стандартное Home app. Для этого нужно добавить следующий блок в политику:
"persistentPreferredActivities": [
{
"actions": [
"android.intent.action.MAIN"
],
"categories": [
"android.intent.category.HOME",
"android.intent.category.DEFAULT"
],
"receiverActivity": "com.example.lockerApp"
}
]
Также нужно разрешить приложению запускать lockTaskMode, который позволит нам скрыть кнопки “домой” и “последние приложения”, а также не позволит выйти из приложения с помощью системной кнопки “Назад”:
"applications": [
{
"defaultPermissionPolicy": "GRANT",
"lockTaskAllowed": true,
"packageName": "com.example.lockerApp"
}
]
Чтобы запустить lockTaskMode, просто вызовите в коде основного Activity своего приложения соответствующий метод:
fun startLockTask() {
val am = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
if (am.lockTaskModeState == ActivityManager.LOCK_TASK_MODE_NONE) {
super.startLockTask()
}
}
Чтобы скрыть статус бар, нужно добавить в policy
"statusBarDisabled": true
Ну а для того, чтобы экран всегда оставался включенным, нужно просто добавить флаг android:keepScreenOn="true" в корневую ViewGroup Activity. Итоговый JSON политики будет выглядеть примерно так:
{
"adjustVolumeDisabled": true,
"appAutoUpdatePolicy": "ALWAYS",
"applications": [
{
"defaultPermissionPolicy": "GRANT",
"installType": "FORCE_INSTALLED",
"lockTaskAllowed": true,
"packageName": "com.example.lockerApp"
}
],
"persistentPreferredActivities": [
{
"actions": [
"android.intent.action.MAIN"
],
"categories": [
"android.intent.category.HOME",
"android.intent.category.DEFAULT"
],
"receiverActivity": "com.example.lockerApp"
}
],
"playStoreMode": "WHITELIST",
"safeBootDisabled": true,
"screenCaptureDisabled": true,
"statusBarDisabled": true,
"systemUpdate": {
"endMinutes": 240,
"startMinutes": 120,
"type": "WINDOWED"
}
}
Различные примеры политик можно посмотреть тут.
Есть ещё одна проблема, с которой мы столкнулись при разработке нашего решения. В одном из проектов Программные технологии заказчику требовался функционал выхода из заблокированного режима, чтобы можно было снова полноценно пользоваться устройством без сброса к заводским настройкам. Это можно сделать через создание двух разных политик — policy_locked и policy_unlocked, и инициируя их смену через backend с устройства. Но дело в том, что с устройства нельзя напрямую получить его внутренний id в Android Management API, а значит — нельзя выполнить никакие операции с ним. До Android 10 можно найти устройство в общем списке по его серийному номеру, который хранится в Device.hardwareInfo.serialNumber, сравнив его с серийным номером, полученным через Build.getSerial() или Build.SERIAL, однако начиная с Android 10, получение серийного номера запрещено для несистемных приложений.
По этой проблеме есть ответ на Stackoverflow от Google. Они советуют использовать managed configurations, фактически — это дополнительные параметры, которые можно передать на устройство, прописав их в policy. Конечно, в таком случае для каждого устройства нужна своя уникальная policy. Для того, чтобы избежать ручного ввода, можно использовать Pub/Sub нотификации, которые позволяют получить уведомление при регистрации нового устройства и сразу же записать в managed configurations его id. Не самый простой способ, но самый правильный. Прописать какой-нибудь уникальный id для устройства вручную при формировании QR-кода не получится, потому что managed configurations устроены таким образом, что записать туда что-либо возможно только после того, как устройство уже зарегистрировано.
Как опубликовать enterprise-приложение в Google Play
Итак, у нас есть policy, способная заблокировать всё и вся на устройстве, кроме нашего избранного приложения. Дело сделано? Не совсем. Наше приложение ещё требуется как-то установить на устройство, а просто так выкладывать в Google Play не очень хочется — ведь мы явно делаем его не для широкой аудитории. Можно, конечно, отправить заказчику apk и попросить поставить приложение вручную, но делать это для каждого устройства довольно утомительно, плюс это нужно будет делать при каждом обновлении приложения.
Решение — использовать Managed Google Play и выложить наше приложение как private app. Для этого нужно сначала загрузить приложение в Google Play, затем зайти в Store Presence -> Pricing & Distribution -> User programs -> Managed Google Play, отметить Turn on advanced managed Google Play features -> Privately target this app to a list of organizations. Здесь нужно выбрать id enterprise, для которой мы регистрируем устройства. Теперь, если в policy для нашего приложения будет прописано поле installType как FORCE_INSTALLED, оно будет установлено автоматически при регистрации устройства.
Заключение
Несмотря на некоторые недостатки, Android Management API в настоящий момент — самый простой и удобный способ для создания Dedicated device или устройства одного приложения в ОС Android. Большие возможности для кастомизации позволяют делегировать непосредственное выполнение кода для создания ограничений на устройстве готовому DPC, что способно существенно сократить время разработки. Нам на мобильных проектах в Программные технологии это API позволяет сократить время на выполнение “рутинной” работы по реализации ограничений и уделить больше внимания самому Single App.
Если у вас все еще остались вопросы о реализации корпоративного приложения, напишите нам, и мы с удовольствием на них ответим!