nfcGuard
Блокирует отвлекающие приложения, пока вы не коснётесь физической NFC-метки. Оставьте метку где-нибудь подальше, и открыть Instagram будет стоить прогулки.
- Платформа
- Android 8.0+
- Технологии
- Kotlin, Jetpack Compose
- Тесты
- 333 модульных теста
- Пользователи
- 1 250+, все органические
Программные блокировщики не работают по одной причине: выключатель находится на том же экране, что и то, чего вы избегаете. nfcGuard переносит выключатель в физический мир. Заблокированное приложение остаётся заблокированным, пока вы не коснётесь конкретной NFC-метки. Если метка лежит на кухне, каждый порыв полистать ленту стоит похода на кухню.






Как это работает
Режим — это набор приложений, которые заблокированы или разрешены. Включите его вручную или привяжите расписание, чтобы он включался сам по рабочим дням. Пока режим активен, эти приложения не откроются. Касание привязанной NFC-метки снимает блокировку.
Каждая метка сама решает, сколько свободы даёт. Одна снимает режим полностью, другая ограничена пятью минутами, после чего режим возвращается сам. Щедрую метку держите дома, строгую в офисе. Режим без привязанных меток принимает любой NFC-объект, например транспортную карту или наушники.
Потеряли метку? Процедура восстановления на главном экране предлагает задание на внимание с таймером, а затем позволяет выбрать, какие метки потеряны. Режимы выключаются, эти метки удаляются, остальная настройка сохраняется.
Распространение
nfcGuard пользуются больше 1 250 человек, и каждый нашёл его сам: без рекламы и платного продвижения.
Архитектура
Проект разделён на два Gradle-модуля, чтобы правила можно было тестировать без телефона.
-
:domain— чистый Kotlin: состояние приложения и четыре объекта логики (NfcUnlockLogic,ScheduleTransitions,ModeActivationLogic,BlockDecider). Он не может импортировать Android, это проверяет компилятор, и тесты идут на обычной JVM. -
:appсодержит Compose UI, сервисы, ресиверы и виджет. Слои идут в одном направлении: домен, данные, побочные эффекты, сервис и UI, у каждой задачи один владелец. -
AppStateRepositoryвладеет сохранённым состоянием. Каждое изменение проходит через одинupdate { }под мьютексом, и только один файл знает ключ хранилища. -
StateSyncerвладеет побочными эффектами. После каждой записи он перезапускает сервис блокировки, переставляет будильники и обновляет виджеты, так что ни одному экрану не нужно об этом помнить. -
BlockerServiceна каждом такте проверяет активное приложение и применяет решение: оверлеем или принудительным закрытием, если включены специальные возможности, которых требуют Pixel и Samsung.
Режимы, расписания и метки экспортируются в JSON или YAML и импортируются обратно с полной заменой или слиянием по id.
Чему я научился
Android жёстко борется с долгоживущими приложениями, и каждый производитель делает это по-своему. Большая часть работы ушла на то, чтобы оставаться в живых: автозапуск на Xiaomi и Oppo, исключения из оптимизации батареи, путь через специальные возможности для Pixel и страница разрешений, которая перепроверяет каждое при возвращении. Логика в модуле без Android и сделала эти постоянные изменения безопасными.