# SHX VPN для Android Форк Android-клиента strongSwan (IKEv2/IPsec), пакет `one.shx.strongswan.ext`. Текущая версия — **2.18.1 (versionCode 166)**. Распространяется вне Google Play: APK и манифест обновлений лежат в приватном бакете S3, приложение обновляется само. - Дизайн: [design/README.md](design/README.md) — макет «Финал 2026» и соответствие артбордов коду. - История UI-плана (до 2.15, устарела): [ui-ux-plan.md](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`: ```bash 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 на эмуляторе: длинные слова не должны переноситься в нижней навигации и заголовках. ## Релиз 1. Сверить `versionCode` с бакетом: `aws s3 cp s3://shx-app/latest.json -` (endpoint и ключи из `.env`). Публичный GET отдаёт `AccessDenied` — это норма, бакет приватный. 2. Поднять `versionCode`/`versionName` в `app/build.gradle`. 3. Обновить `NOTES_RU` в `.env` (одна строка; текст попадёт в диалог обновления). `.env` читается построчно, без `source`/`eval`. 4. Собрать без выгрузки: `ORG_GRADLE_PROJECT_shortNdkCommands=true ./build-local.sh --skip-upload` (или `build-local.ps1 -SkipUpload`). Успех — строки `BUILD SUCCESSFUL` и `==> Built`. 5. Smoke-тест: установить `build/publish/shx-vpn.apk` на эмулятор (AVD `shx36`), пройти онбординг и все вкладки, проверить `adb logcat -b crash`. 6. Выложить именно проверенный 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`.