Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
9.7 KiB
SHX VPN для Android
Форк Android-клиента strongSwan (IKEv2/IPsec), пакет one.shx.strongswan.ext. Текущая версия — 2.18.1 (versionCode 166).
Распространяется вне Google Play: APK и манифест обновлений лежат в приватном бакете S3, приложение обновляется само.
- Дизайн: design/README.md — макет «Финал 2026» и соответствие артбордов коду.
- История UI-плана (до 2.15, устарела): ui-ux-plan.md.
Что умеет приложение
| Раздел | Возможности |
|---|---|
| Главная | Кнопка подключения, шаги подключения из журнала демона, пауза (минуты, до утра, до смены сети), трафик за сегодня, карточки проблем (нет сети, сервер не отвечает, вход отклонён, белые списки, истекает сертификат) с действием в один тап, подсказки сценариев |
| Серверы | Один сервер = один профиль .sswan. Добавление по QR, ссылке, файлу или вручную; проверка профиля перед добавлением; «Поделиться» QR-кодом без пароля; страница сервера: источник профиля, ежедневная проверка ссылки и лист изменений, запасные порты, резервный сервер, мост при белых списках, DNS, MTU, фрагментация IKE |
| Маршруты | Раздельный туннель, сайты РФ напрямую (база адресов, режимы «Стабильно»/«Гибко»), приложения напрямую, правила (сайт, адрес/сеть, шаблон пакета), недавние приложения, недоступные хосты, «Как ходит трафик» |
| Сценарии | Правила для сетей (доверенная Wi-Fi / мобильная или чужая сеть) и свои сценарии: Wi-Fi, мобильная сеть, приложение открыто, время, роуминг, белые списки → включить, выключить, пауза, сменить сервер. Общий порядок, верхний важнее; ручное действие перекрывает сценарий до его окончания |
| Защита | DNS через туннель: из профиля, Cloudflare, AdGuard (реклама и трекеры), Cloudflare 1.1.1.2 (фишинг), свой адрес; «Без VPN — без сети» (инструкция к системному Always-on) |
| Статистика | Трафик по дням/неделям/месяцам: через VPN и напрямую, по приложениям (нужен доступ к статистике использования), итоги недели |
| Диагностика | Интернет, сайты РФ и зарубежные, сервер, DNS, белые списки за ~10 секунд; проверка сайта; отчёт в поддержку |
| События | Центр событий в приложении и push по каналам (статус, проблемы, новые приложения, обновления, итоги недели) |
| Система | Виджеты трёх размеров (Glance), плитка быстрых настроек, ярлыки профилей, автообновление с проверкой SHA-256 и подписи |
Профиль без сохранённого пароля никогда не запускается сам (watchdog, правила, сценарии, резерв, мост): вместо этого приходит событие со ссылкой на сервер.
Устройство кода
app/src/main/java/org/strongswan/android/:
| Пакет | Что внутри |
|---|---|
logic/ |
CharonVpnService (туннель и уведомление), VpnStateService, WatchdogReceiver, PauseManager |
logic/autoconnect |
Правила для сетей: AutoConnectManager, NetworkMonitor, SsidReader |
logic/scenarios |
ScenarioEngine: условия, порядок, ручной приоритет |
logic/profiles |
ProfileExtras (настройки поверх .sswan), ProfileUpdater (ссылка и diff), Resilience (порты, резерв, мост) |
logic/routing |
RoutingManager, база адресов РФ (RuIpListManager), правила и шаблоны пакетов, RouteCheck, AppTraffic |
logic/connectivity |
Проверки сети и сервера, HealthCheckManager, детект белых списков |
logic/protection |
Выбор DNS и фильтрации |
logic/stats |
TrafficHistory, WeeklySummary |
logic/events |
EventLog (центр событий), Events (push) |
logic/updates |
UpdateManager, загрузка и установка APK, проверка подписи |
ui/compose |
Экраны на Compose; design/ — компоненты макета (ShxKit, ShxIcons), theme/ — цвета и шрифты макета, home/, routing/ |
ui/ |
Activity вторичных экранов, VpnTileService, widget/ShxWidget |
Нативная часть (libcharon, libstrongswan, OpenSSL) собирается NDK из app/src/main/jni.
Тулчейн
AGP 9.1.1, Gradle 9.3.1, Kotlin 2.2.21, Java 11, compileSdk 37, targetSdk 36, minSdk 24, NDK 27.3, Compose BOM 2026.09.00, material3 1.5.0-beta01 (закреплена явно до стабильной 1.5.0), Glance 1.2.
Сборка и тесты
Из src/frontends/android:
ORG_GRADLE_PROJECT_shortNdkCommands=true ./gradlew :app:assembleDebug :app:testDebugUnitTest -PshortNdkCommands
shortNdkCommands нужен на Windows в глубоких путях (worktree): иначе команда линковки libstrongswan длиннее лимита CreateProcess.
В worktree нет git-игнорируемых входов — их копируют из основного checkout: .env, local.properties, Android.common.mk,
app/src/main/jni/openssl/, сгенерированные oid.{c,h}, proposal_keywords_static.{c,h}, settings_{lexer.c,parser.c,parser.h}.
lintDebug пока падает на старых ошибках (NewApi в FgsStartRetry, MissingTranslation у неиспользуемых строк) — это не регресс.
Локализация
Языки: en (база, values/), ru, de, pl, uk, zh-CN, zh-TW. Каждая новая строка добавляется сразу во все семь.
Правила перевода:
- плейсхолдеры (
%1$s,%1$d%%) и\nсохраняются как в английской строке; - кавычки по языку: ru/uk «…», de „…“, pl „…”, zh “…” / 「…」; апостроф — ’;
- plurals: de — one/other, pl/uk/ru — one/few/many/other, zh — other;
- системные термины как в Android: «Постоянный VPN», «Durchgehend aktives VPN», «Stały VPN», «Постійно ввімкнена VPN», «始终开启的 VPN», «永久連線的 VPN»;
- после правок посмотреть de и uk на эмуляторе: длинные слова не должны переноситься в нижней навигации и заголовках.
Релиз
- Сверить
versionCodeс бакетом:aws s3 cp s3://shx-app/latest.json -(endpoint и ключи из.env). Публичный GET отдаётAccessDenied— это норма, бакет приватный. - Поднять
versionCode/versionNameвapp/build.gradle. - Обновить
NOTES_RUв.env(одна строка; текст попадёт в диалог обновления)..envчитается построчно, безsource/eval. - Собрать без выгрузки:
ORG_GRADLE_PROJECT_shortNdkCommands=true ./build-local.sh --skip-upload(илиbuild-local.ps1 -SkipUpload). Успех — строкиBUILD SUCCESSFULи==> Built. - Smoke-тест: установить
build/publish/shx-vpn.apkна эмулятор (AVDshx36), пройти онбординг и все вкладки, проверитьadb logcat -b crash. - Выложить именно проверенный APK:
aws s3 cpсначалаshx-vpn.apk, потомlatest.json(оба с--cache-control no-cache, json ещё с--content-type application/json), затем прочитатьlatest.jsonиз бакета и сверить sha256.
Известное ограничение Android 13+: приложению, установленному не из магазина, система блокирует «Статистику использования» («Контролируется настройками с ограниченным доступом»). Обычно снимается в «Информации о приложении» → ⋮ → «Разрешить ограниченные настройки» (пункт появляется после попытки включить разрешение); на Samsung может мешать «Автоблокировщик», крайний вариант — adb shell appops set one.shx.strongswan.ext GET_USAGE_STATS allow.