Files
pangolin/client/android/app/src/main/assets/poc_config.json
T
wangjia 83c23f968a feat(android): 实现 M2 Android VPN 隧道 — PangolinVpnService 接入 libbox [tsk_w1NvZdmwGPyd]
接线 11B libbox.aar + 11C Dart 桥接骨架,完成 Android 端 M2 PoC:

### PangolinVpnService(完整实现)
- `handleStart(configJson)` → 后台线程 → `Libbox.newBoxService(platformInterface, json)` → `start()`
- 内 inner class `PangolinPlatformInterface` 实现 libbox `PlatformInterface`:
  - `openTun(TunOptions)`: 调用 `VpnService.Builder()` 配置地址/MTU/路由,`establish()` 取 TUN fd
  - `autoDetectInterfaceControl(fd)`: `VpnService.protect(fd)` 防环路
  - 安全 getter 兜底:TunOptions 方法名与 libbox.aar 不符时降级到 PoC 默认值
- 统计双轨:优先 libbox `CommandClient`(status/traffic)→ 失败时退回 `TrafficStats` 定时器
- 幂等 `doStop()`:commandClient.disconnect → boxService.close → tunPfd.close → stopForeground
- `onRevoke()` 推 error 状态再 doStop,不留假 on

### VpnEventBus
- 新增 `currentStatus` 字段(volatile),供 `getStatus()` 一次性查询

### MainActivity
- `VpnService.prepare()` 权限流程:未授权 → 弹 prepare Intent → `onActivityResult` 后启动
- `getStatus()` 从 `VpnEventBus.currentStatus` 返回真实状态
- 首次连接时引导 `REQUEST_IGNORE_BATTERY_OPTIMIZATIONS`(后台存活)

### AndroidManifest.xml
- `android:foregroundServiceType="specialUse"`(Android 14 API 34 强制要求)
- 新增权限:`FOREGROUND_SERVICE_SPECIAL_USE`、`REQUEST_IGNORE_BATTERY_OPTIMIZATIONS`

### build.gradle
- `implementation files('../../../app/kernel/dist/android/libbox.aar')`(条件存在检查)
- `minSdkVersion` 提升至 21(gomobile -androidapi 21 要求)

### 新增文件
- `assets/poc_config.json`: PoC 单节点测试配置模板(含占位符 __NODE_HOST__ 等)

通知文案已过红线词扫描:「加速已开启」「正在连接…」「穿山甲加速」,无 VPN/翻墙等禁词。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 17:45:13 +08:00

102 lines
2.1 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"_comment": "PoC M2 单节点测试配置(11E / tsk_w1NvZdmwGPyd",
"_usage": "填入真实节点参数后,在 Dart 侧 VpnNativeBridge.start(configJson) 传入",
"log": {
"level": "warn",
"timestamp": true
},
"inbounds": [
{
"type": "tun",
"tag": "tun-in",
"address": ["172.19.0.1/30"],
"mtu": 9000,
"auto_route": true,
"strict_route": true,
"stack": "system"
}
],
"outbounds": [
{
"type": "vless",
"tag": "reality-out",
"server": "__NODE_HOST__",
"server_port": 11443,
"uuid": "__REALITY_UUID__",
"flow": "xtls-rprx-vision",
"tls": {
"enabled": true,
"server_name": "www.apple.com",
"utls": {
"enabled": true,
"fingerprint": "chrome"
},
"reality": {
"enabled": true,
"public_key": "__REALITY_PUBLIC_KEY__",
"short_id": "__REALITY_SHORT_ID__"
}
}
},
{
"type": "hysteria2",
"tag": "hy2-out",
"server": "__NODE_HOST__",
"server_port": 443,
"password": "__HY2_PASSWORD__",
"tls": {
"enabled": true,
"insecure": true,
"alpn": ["h3"]
}
},
{
"type": "urltest",
"tag": "auto",
"outbounds": ["reality-out", "hy2-out"],
"url": "https://www.gstatic.com/generate_204",
"interval": "3m",
"tolerance": 50
},
{
"type": "block",
"tag": "block"
},
{
"type": "direct",
"tag": "direct"
}
],
"route": {
"rules": [
{
"ip_cidr": [
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16",
"127.0.0.0/8"
],
"outbound": "direct"
}
],
"final": "auto",
"auto_detect_interface": true
},
"dns": {
"servers": [
{
"tag": "remote",
"address": "tls://8.8.8.8",
"detour": "auto"
},
{
"tag": "local",
"address": "223.5.5.5",
"detour": "direct"
}
],
"final": "remote",
"strategy": "ipv4_only"
}
}