Как я слал нотификации из Android телефона в Windows компьютер

Дело было вечером, делать было нечего. Я решил, что было бы здорово получать уведомления с моего смартфона на один из моих компьютеров (Windows). Так как я болен Not invented here, то сразу открыл IDE и начал творить. В этом посте кратко о результатах.

TL;DR На финальное решение вы можете посмотреть тут — https://github.com/Hixon10/NotificatiionsFromAndroidToWindows.

Требования к решению

Давайте начнем с правильного решения. Если у вас смартфон на базе Android, а на компьютере стоит Windows, то вы можете получать нотификации на компе автоматически — https://support.microsoft.com/en-us/topic/view-and-manage-mobile-notifications-on-your-pc-77e13ff9-1d7f-6d2f-f5ec-80c7b5cdfbcf. Для этого просто достаточно просто выполнить пару простых шагов. Мне этот путь не подошел, так как я не хочу иметь никакую связь между телефоном и компьютером, так как это может быть один из векторов атаки.

По сути, перед началом разработки я имел только одно главное требование: оба устройства (телефон и компьютер) ничего не должны знать друг о друге. Если одно из устройств будет скомпрометировано, другое из них не должно никак пострадать. Отсюда выходит, что мы не хотим иметь встроенную в Windows синхронизацию, и не хотим строить никакие прямые тунели между парой девайсов.

Как работает приложение

Я решил построить это костыльное решение на основе git(hub), где я использую git — как бесплатную базу данных с кучей вкусных плюшек, а github — как PaaS, который даёт мне аутентификацию к этой базе данных. Если кратко, то решение работает вот так вот:

  • Android приложение слушает все Нотификации, которые случаются в телефоне, фильтрует ненужные нотификации, и оставшиеся нотификации коммитит в git (используется REST API от github).
  • Windows своим аналогом Cron запускает моё консольное приложение (например, раз в минуту). Это приложение проверяет, есть ли новые коммиты в origin. Если есть — значит случились новые нотификации, и их нужно показать пользователю.

Зачем используется Git, как база данных

Во-первых, это прикольно. Git — очень мощная бд (ясно красно, для серьзного OLTP оно не подойдет, но когда игрушечная задача — почему нет?). А, во-вторых:

  • База в Git — это бесплатно.
  • Простая поддержка сценария — Один писатель — Несколько читатель (Single Writer Multiple Reader — SWMR). Если у нас несколько компьютеров, где мы хотим показывать нотификации, то в каждом из них будет свой локальный git-репозиторий, и не придется придумывать, как показать одно событие на всех устройствах, и не потерять текущий курсор.
  • Git — это дерево коммитов. Так как мы хроним нотификации в виде «одна нотификация — один коммит», то мы получаем упорядоченный лог евентов из коробки, и можем реализовать разные сценарии (например, показывать нотификации в правильном порядке, или показывать только последнюю нотификацию).
  • Если вы хотите повысить качество приложения, то вы можете реализовать at least once семантику. Сначала вы проверяете, что в origin есть новые коммиты (git fetch origin), потом показываете юзеру нотификацию, а потом сдвигаете курсор локально (git merge origin/main).

Про проблемы

Ух, в этом решение прям куча проблем. Оно того и гляди, как само развалится. Вот главные из них:

  • Я ваще не умею разрабатывать под android, но я не нашел железного способа, как сделать две вещи — включить приложение после рестарта телефона, и как гарантировать, что Сервис, который слушает нотификации, не будет убит операционной системой, чтобы не жрать батарейку. Для включения приложения после ребута я использую BroadcastReceiver. Для попытки держать приложение активным в течение всей жизни я делаю две вещи. Во-первых, выключаю в настройках оптимизацию батарейки. Во-вторых, использую Foreground сервис. Однако я не уверен, что это пуленепробиваемое решение, и не знаю, как сделать лучше.
  • В Windows нет Cron. Зато есть пяток других способов, как заскедулить джобу. Сначала я воспользовался schtasks.exe, чтобы запускать раз в минуту мою консольное приложение. Но оказывается, что я, как пользователь, буду видеть в течение 1 секунды консольную программу, и это будет каждую 1 минуту. В общем, не рабочее решение. Оказывается, что это известная проблема, как запустить периодическую задачу фоново, и есть несколько костылей разной степени паршивости — https://serverfault.com/a/9039/190769
  • Я не смог слать из Windows консольного приложения нативные нотификации. Они отправляются, но сразу появляются в боковом меню. Пользователь не видит плашки с нотификацией, и не получает никакого шума. Оказывается, в одном из обновлений Windows 10 майкрасофт ввёл какие-то новые правила, и из коробки щас так просто не показать нотификацию. Я пробовал разные решения, но так и не получил результата. В общем, я забил и тупо показываю Окно Алерта. Не нативно, но работает.
  • Очевидно, что это не продукт, а штука, сделанная на коленке. Нет никаких настроек. Если бы это был продукт, нужно было бы уметь настраивать какие евенты слать из андроида, и какие показывать в винде. Щас это требует перекомпиляци, но who cares. Надо будет — пересобиру. А если вам надо будет — пересобирете.

Выводы

В общем, решение получилось поистине костыльным, но вроде пока работает, что меня радует. Если будут критические баги, я их пофишку и закину апдейт в эту статью по результатам.

Категории: Программирование