# Android-часть плагина

Нативный Kotlin-код, к которому обращается `src/mobile.rs` через
`PluginHandle::run_mobile_plugin`. Отдельный Gradle-модуль (`com.android.library`),
подключается в `gen/android` как `:tauri-plugin-vpn` — см.
`android/settings.gradle`.

## `src/main/java/.../VpnPlugin.kt`

Файл содержит два класса:

- **`TunVpnService`** (`android.net.VpnService`) — foreground-сервис,
  который реально держит туннель: строит `VpnService.Builder` (адрес/DNS/MTU),
  сплит-туннелинг (allow-list для Telegram sandbox-режима **или**
  disallow-list для обычного режима — взаимоисключающе), отдаёт `fd`
  созданного TUN-интерфейса в `SessionManager.spawnSession(...)`, крутит
  цикл статистики и рассылает статус/трафик через `sendBroadcast`. Вибро-фидбек
  при подключении/отключении.
- **`VpnPlugin`** (`@TauriPlugin`) — мост Tauri-команд к сервису:
  `startVpn` запрашивает системное разрешение VPN (`VpnService.prepare`)
  перед стартом, `stopVpn`/`checkActualVpnStatus`/`getInstalledApps`/`launchApp`.
  Транслирует broadcast от `TunVpnService` в Tauri-события
  (`trigger("status-change" / "traffic-stats", ...)`), которые ловит
  `guest-js` на JS-стороне.

`AndroidManifest.xml` — разрешения `INTERNET`, `FOREGROUND_SERVICE`
(`specialUse`), `POST_NOTIFICATIONS`, `VIBRATE`; `<queries>` для обнаружения
установленных приложений (нужно для сплит-туннелинга).

## ⚠️ Обязательно прочитать до правок

**`SessionManager.spawnSession(...)` — не обычный Kotlin-класс, а UniFFI-биндинг
поверх нативной `.so`-библиотеки.** Три вещи должны совпадать между собой
всегда, иначе сборка падает (или, хуже, крашится в рантайме):

1. Сигнатура `spawn_session` в `.udl`/`lib.rs` крейта `netrunner_client`
   (репозиторий `netrunner-proxy`/`netrunner-core`).
2. `android/src/main/java/uniffi/netrunner_client/netrunner_client.kt` —
   сгенерированные Kotlin-биндинги.
3. `android/src/main/jniLibs/<abi>/libnetrunner_client.so` — скомпилированная
   нативная библиотека.

Все три файла из пп. 2–3 **гитигнорены** (`*uniffi`, `*jniLibs` в
`.gitignore` плагина) — они не часть репозитория, их нужно вручную
регенерировать/копировать при каждом изменении `.udl` в `netrunner-core`:

```bash
# в репозитории netrunner-proxy
make build-android            # пересобирает .so под все ABI + генерит Kotlin-биндинги
                               # (tools/bindgen — обёртка над uniffi_bindgen_main)
# результат: gen/uniffi/netrunner_client/netrunner_client.kt
#            gen/<abi>/libnetrunner_client.so

# скопировать в netrunner-app:
cp gen/uniffi/netrunner_client/netrunner_client.kt \
   <netrunner-app>/src-tauri/src/plugins/vpn-plugin/android/src/main/java/uniffi/netrunner_client/
cp gen/<abi>/libnetrunner_client.so \
   <netrunner-app>/src-tauri/src/plugins/vpn-plugin/android/src/main/jniLibs/<abi>/
```

Забытый шаг копирования — уже реальная причина падения сборки (Kotlin
компилятор ругается на несовпадение сигнатуры `spawnSession`, если `.kt`
отстал от `.so`/UDL). Если сборка падает быстро (~секунды, до NDK-этапа) —
проверяйте это в первую очередь.
