Всем ку! Пожалуй, стоит начать с того, что меня вообще сподвигло на создание данной версии:
-
Нежелание некоторых юзеров пользоваться официальной версией для ПК по ряду причин:
а) Требовательность к железу (даже видеокарту нагружает). А некоторым по работе приходится юзать МАХ на «уставших рабочих лошадках». Заявления, типа «эта тварь жрёт ресурсов больше, чем 1С».
б) Постоянные обновления с полной переустановкой, а на момент написания статьи полный пакет официального МАХ весил 308 мб.
в) Некоторые неудобства использования веб‑версии, особенно в режиме «Инкогнито». Чуть подробнее будет дальше в статье.
г) Слежение за пользователем. Вроде, ничего особо криминального нет во встроенных трекерах, но бесит, когда тебя не спрашивают. Знаете, если Вы выходите из подъезда и бабульки на лавочке интересуются как у вас дела и куда направляетесь — это одно. Ваше дело — отвечать\не отвечать\соврать. А когда Вам при этом ещё и в трусы заглядывают без спроса — это уже другое.
-
Не нашел хорошую альтернативу. Нет, есть конечно nemax‑mod для ПК, который представляет из себя оболочку для веб‑версии, но так такое… и сырое.
Значит, будем делать своё!
Итак, для начала выберем инструмент разработки, для этого есть некоторое количество моих «юзерфрендли принципов»:
а) Запуск на всём, чём можно. Некоторые из технологий и фреймворков будем использовать «заранее устаревшими». Выбор по старинке остановил на c# +.net framework 4.7. Конечно, можно было использовать более новые.NET 8\9\10, что гораздо упростило бы разработку и решило некоторых сложности, с которыми пришлось столкнуться. Но если у юзера Win10 без предустановленного.NET или даже Win7 (да, и такие отписываются в Issue на гитхабе), это создаст некоторые неудобства при первичном запуске.
б) Малый вес. Как можно меньше. Нет перегруженного интерфейса и прочих свистогуделок и прочего мусора.
в) Максимально простая установка. Поддержка обновлений. Желательно, удобных обновлений.
Ну что ж, приступаем!
-
Для начала набросал простую оболочку, в которой запускается WebView2 с привязкой к сайту веб‑версии MAX и увидел несколько проблем:
а) Хорошо, у меня есть окно, но как получать уведомления, если оно свёрнуто?
б) При авторизации создается папка с файлами и кэшем веб‑версии в appdata. Меня это не устроило по ряду причин — по моему опыту хранение данных локально может быть на руку злоумышленникам. В своё время я легко получал доступ к перепискам различных мессенджеров, благодаря локальному хранению. И вообще, считаю папку с данными WebView2 — мусором. А пользователь не должен об этом задумываться при удалении мессенджера с рабочего компа.
в) В принципе, при работе в режиме ‑inprivate (сиречь «в режиме Инкогнито»), создается временная папка, которая удаляется при закрытии окна, но тогда придется проходить авторизацию каждый раз при запуске.
-
Мне понравилась идея с in private, но тогда нужно хранить ключ авторизации. Пишем перехватчик токенов на javascript. Легко и просто перехватываем токен авторизации, но как его хранить? Ответ лежит на поверхности — прямо в реестре с шифрованием по DPAPI — это решит сразу несколько проблем:
-
Не нужно постоянно проходить авторизацию
-
Токен «под рукой» для быстрого удаления
-
Копирование токена на другой комп не позволит использовать его на другой машине, так как DPAPI имеет жесткую привязку к windows user id, device id
-
Токен зашифрован и его нельзя «просто прочитать»
Вопрос: кто‑то другой сел за комп и открыл эту программу. Либо она запустилась сама при загрузке системы и «посторонний» видит всю переписку. Решение — добавляем функцию пин‑кода. Опциональное, пользователь может отказаться и добавить пин‑код потом или удалить его.
Логика работы парсера — при инициализации окна парсер проверяет, есть ли ключ авторизации в зашифрованном виде по месту хранения? Если есть — останавливается. Если нет — ждём авторизации от пользователя по QR‑коду. Как только токен перехвачен и сохранен — парсер останавливает работу.
Не забываем про UX — добавляем в настройки удаление данных авторизации в один клик.
3. Создаем иллюзию окна как отдельного мессенджера. Имеется ввиду необходимость сохранения положения окна и его размеров при каждом запуске. В том числе при наличии нескольких дисплеев. Сохраняем данные по размерам окна и координатам в реестре. Не шифруем )
Уведомления
-
Проводим опрос среди юзеров. Что нравится и не нравится, когда они используют оригинальную веб‑версию МАХ? Приходим к выводу, что нам необходимо:
-
Корректно всплывающие уведомления типа стандартных, но лучше и функциональнее.
-
Понимать, что было пропущено уведомление, если юзер отошел от компа. А именно — мигание иконки приложения в панели задач, либо красная точка на иконке в трее.
Значит, делаем уведомления в правом нижнем углу с нуля. Включаем логику определения получения новых сообщений. При взгляде на чат видим, что у нас есть три вида состояния — синий бейдж с количеством сообщений — новое непрочитанное. Серый бейдж — новое непрочитанное в чате, для которого пользователь выключил уведомления. Нет бейджа — нет новых сообщений. Изучаем веб‑страницу, ищем div’ы и классы, отвечающие за бейджи, парсим эти состояния. Дебажим.
Передаем из javascript в c# данные. Пишем CustomNotification.cs, который будет рисовать нам уведомления в нижнем углу Windows.
Прописываем определение состояния окна программы (мы же не хотим получать всплывающие уведомления прямо во время переписки?) — окно либо в фокусе, либо нет. Если нет — показываем уведомления. Опять дебажим…
Парсим данные из чата с синим бейджем — аватар, имя\ник пользователя и тело сообщения. Всё это добавляем в наш нотификатор и снова и снова дебажим. Не забываем про такие нюансы как — крестик на уведомлении для быстрого закрытия, положение уведомления по, скажем так, Z‑координате (мы должны видеть уведомление из нашей программы поверх всех других окон, в том числе в 3D приложениях, но это не должно приводить к их сворачиванию).
Добавляем функцию «антифлуд» — это когда кто‑то начинает спамить короткими сообщениями, и Вам это не нравится — показываем новые сообщения не чаще чем задано определённым временным лимитом. Добавляем проверку на дубли сообщений — когда Вы получили новое сообщение, то получили и уведомлении в трее, но если Вы его не прочитали в течение отведенного времени, то программа могла отправить уведомление повторно. Чтобы этого не происходило — храним в памяти тело сообщения и, если дубль, то не показываем. Это решает проблему с постоянно всплывающими уведомлениями, когда юзеру тупо некогда ответить на сообщение (допустим, пишет срочное письмо, сценарий, отвечает клиенту). И не придётся постоянно жать на крестик.
Разыгрываем в голове ситуацию — юзер отошел по своим делам. В это время пришло новое сообщение, появилось уведомление и исчезло спустя несколько секунд. Программа свёрнута и чат не виден. Хорошо, уведомление исчезло через пару секунд, значит, если юзер не отреагировал, то через пару секунд включаем ненадолго мерцающую подсветку иконки в панели задач. Моргнём два‑три раза и дальше будем просто светиться (не надо моргать почем зря, может юзеру не до чата, а так просто оранжевым светится иконка внизу и сильно глаз не мозолит). А если свернуто в трей? Тогда красная точка над иконкой в трее. И без всяких «99+» непрочитанных сообщений, это лишнее.
(пока писал эту статью, решил, что нужна будет дополнительная настройка «Показывать уведомления поверх других окон» с возможностью отключения, а то вдруг юзер катает‑нагибает? Уведомление может перекрыть ему стратегически важную информацию. Сказано‑сделано)
Собираем билд…
-
Изначально была идея собрать всё в один.exe файл, вес которого был примерно 1–1,5 мб, и потреблял примерно 15 мб RAM. Это успех… но не всё оказалось так просто. Одна из нативных библиотек, написанная на c++ никак не хотела встраиваться. Это рушило «концепцию одного файла» на корню. Да и нужно было еще проработать дополнительную безопасность. Добавляем на всякий случай защиту от XSS‑атак, блокировку трекеров, антидебаггер (с которым хапаем проблем при тестировании и получаем невозможность запуска на виртуальных машинах), отслеживание контрольных сумм. Оставался открытым вопрос последующих обновлений. Понятно, что веб‑версия сама по себе новая при каждом запуске, но как быть с обновлением билдов самой программы? Накидав всяких фич по безопасности заметил, что потребление RAM значительно выросло, но не критично. А в моей RAM еще свежи воспоминания о чаяниях юзеров по поводу полной переустановки десктопного МАХ при каждом обновлении… так быть не должно!
Подумав немного, решил использовать Velopack для обновлений. По итогу отказался от концепции «одна программа — один файл». Единственное — зашил парсер на javascript внутрь.exe, а то как‑то несекьюрно. Velopack помог решить несколько вопросов сразу:
-
Дельта‑обновления в фоне. Вышел новый билд? При запуске программы Вы получите уведомление о наличии обновлений. В случае согласия обновиться — даже глазом моргнуть не успеете, как программа получит обновления только новых файлов и быстро перезапустится. Только. Новых. Файлов. А не полный реинсталл, чем любят грешить некоторые девелоперы.
-
Пусть библиотеки не будут вшиты в.exe, зато при сборке нового билда и получении обновлённных библиотек юзеру будет проще обновиться с меньшими затратами на трафик.
-
Velopack сам контролит хэш файлов, так что эту функцию, как и несколько других, вырезал из исходного кода за ненадобностью.
-
Что не понравилось? Работа мессенджера в таком режиме потребляет RAM на уровне «телеги», скачками до 100–300 мб RAM. В среднем около 100 мб.
-
Вес установочного файла <10 мб. Пока только win‑x64. Пользуйтесь!
P. S.: У меня на гитхабе есть еще интересные штучки…
ссылка на оригинал статьи https://habr.com/ru/articles/1048178/