mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-09-02 09:09:17 +00:00
* feat(mobile): add embedded iOS runtime API Add a thin panic-safe C ABI crate for embedding no-TUN instances on iOS. Expose lifecycle, status, JSON-RPC, string ownership, and error handling. Build device and simulator XCFramework static libraries on macOS. Add exact named-instance deletion to the iOS and Android wrappers. Cover wrapper lifecycle and the port-forward patch flow on host targets. * fix(gateway): recover TCP port-forward listeners Release an unusable TCP port-forward listener after an accept failure. Retry binding until the forward is cancelled. Keep the old listener released while rebinding so mobile sockets can recover. Expose opt-in iOS diagnostics for listener and connection events. Trace configuration removal and adapter shutdown. Add tests for recovery, release-before-rebind, and cancellation. * feat(web): persist incremental managed config patches Add a revision-CAS PATCH contract for managed configs while keeping the existing Full PUT path for compatibility and recovery. Apply Full and Patch mutations with their revision in one SQLite transaction. Reject ownership conflicts and invalidate revisions on alternate web-owned writes. Document limits, failure semantics, rollout order, and verification. Cover delta updates, conflicts, idempotency, and transaction rollback. * feat(web): apply managed config patches to live sessions Carry Patch fences and touched instance IDs into live sessions. Reconcile only those instances when the applied revision matches the Patch base. Fall back to Full reconciliation for gaps and restarts. Invalidate the applied revision around every direct runtime mutation. Fence revision advancement with the runtime cache epoch so stale reconcile rounds cannot overwrite a newer invalidation. Require deletion responses to confirm each requested instance before advancing the revision. Raise the managed PUT and PATCH body limit to 32 MiB and return typed conflicts for publisher recovery. * fix(core): retry transient accepted TCP errors Keep TCP tunnel listeners alive when an accepted socket fails during upgrade with a retryable connection-state error. Share the retryable I/O classifier with the socket listener. Cover a rejected connection followed by success and propagation of permanent errors. * feat(core): add internal Peer Relay edge projection Derive the local advertised OSPF row from physical adjacency and transport-authenticated credential relay coverage. Keep full local adjacency only in the temporary SPF snapshot so direct destinations retain a fallback route. Leave Peer Relay disabled at the public configuration seam. A follow-up change can expose the preference without coupling route projection to credential reauthorization. feat(config): expose Peer Relay routing preference Add prefer_peer_relay to public protobuf, TOML, management patch, and hosted runtime surfaces. Read the preference from live peer context so runtime config updates take effect. Refresh authenticated peer metadata when the option is enabled. Cover dynamic enable and disable in a five-node, dual-admin credential topology, including forwarded relay coverage and local fallback.
EasyTier Android JNI
这是 EasyTier 的 Android JNI 绑定库,允许 Android 应用程序调用 EasyTier 的网络功能。
功能特性
- 🚀 完整的 EasyTier FFI 接口封装
- 📱 原生 Android JNI 支持
- 🔧 支持多种 Android 架构 (arm64-v8a, armeabi-v7a, x86, x86_64)
- 🛡️ 类型安全的 Java 接口
- 🔌 支持通过 JSON 调用已暴露的 EasyTier RPC 查询/管理接口
- 📝 详细的错误处理和日志记录
支持的架构
arm64-v8a(aarch64-linux-android)armeabi-v7a(armv7-linux-androideabi)x86(i686-linux-android)x86_64(x86_64-linux-android)
构建要求
系统要求
- Rust 1.70+
- Android NDK r21+
- Linux/macOS 开发环境
环境设置
-
安装 Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source ~/.cargo/env -
安装 Android NDK
- 下载 Android NDK: https://developer.android.com/ndk/downloads
- 解压到合适的目录
- 设置环境变量:
export ANDROID_NDK_ROOT=/path/to/android-ndk
-
添加 Android 目标
rustup target add aarch64-linux-android rustup target add armv7-linux-androideabi rustup target add i686-linux-android rustup target add x86_64-linux-android
构建步骤
-
克隆项目并进入目录
cd /path/to/EasyTier/easytier-contrib/easytier-android-jni -
运行构建脚本
./build.sh -
构建完成后,库文件将生成在
target/android/目录下target/android/ ├── arm64-v8a/ │ └── libeasytier_android_jni.so ├── armeabi-v7a/ │ └── libeasytier_android_jni.so ├── x86/ │ └── libeasytier_android_jni.so └── x86_64/ └── libeasytier_android_jni.so
Android 项目集成
1. 复制库文件
将生成的 .so 文件复制到您的 Android 项目中:
your-android-project/
└── src/main/
├── jniLibs/
│ ├── arm64-v8a/
│ │ └── libeasytier_android_jni.so
│ ├── armeabi-v7a/
│ │ └── libeasytier_android_jni.so
│ ├── x86/
│ │ └── libeasytier_android_jni.so
│ └── x86_64/
│ └── libeasytier_android_jni.so
└── java/
└── com/easytier/jni/
└── EasyTierJNI.java
2. 复制 Java 接口
将 java/com/easytier/jni/EasyTierJNI.java 复制到您的 Android 项目的相应包路径下。
3. 添加权限
在 AndroidManifest.xml 中添加必要的权限:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
使用示例
基本使用
import com.easytier.jni.EasyTierJNI;
import java.util.Map;
public class EasyTierManager {
// 初始化网络实例
public void startNetwork() {
String config = """
inst_name = "my_instance"
network = "my_network"
""";
try {
// 解析配置
int result = EasyTierJNI.parseConfig(config);
if (result != 0) {
String error = EasyTierJNI.getLastError();
throw new RuntimeException("配置解析失败: " + error);
}
// 启动网络实例
result = EasyTierJNI.runNetworkInstance(config);
if (result != 0) {
String error = EasyTierJNI.getLastError();
throw new RuntimeException("网络实例启动失败: " + error);
}
System.out.println("EasyTier 网络实例启动成功");
} catch (RuntimeException e) {
System.err.println("启动失败: " + e.getMessage());
}
}
// 获取网络信息
public void getNetworkInfo() {
try {
Map<String, String> infos = EasyTierJNI.collectNetworkInfosAsMap(10);
for (Map.Entry<String, String> entry : infos.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
} catch (RuntimeException e) {
System.err.println("获取网络信息失败: " + e.getMessage());
}
}
// 停止所有实例
public void stopNetwork() {
try {
int result = EasyTierJNI.stopAllInstances();
if (result == 0) {
System.out.println("所有网络实例已停止");
}
} catch (RuntimeException e) {
System.err.println("停止网络失败: " + e.getMessage());
}
}
}
通用 JSON RPC
EasyTierJNI.callJsonRpc(serviceName, methodName, domainName, payloadJson) 可以调用已暴露的
EasyTier RPC 服务,payload 和返回值均为 protobuf JSON。该接口不支持
api.manage.WebClientService;实例启动、保留、删除、信息收集仍使用专用 JNI API。
String response = EasyTierJNI.callJsonRpc(
"api.logger.LoggerRpcService",
"get_logger_config",
"{}"
);
VPN 服务集成
如果您要在 Android VPN 服务中使用:
public class EasyTierVpnService extends VpnService {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 建立 VPN 连接
ParcelFileDescriptor vpnInterface = establishVpnInterface();
if (vpnInterface != null) {
int fd = vpnInterface.getFd();
// 设置 TUN 文件描述符
try {
EasyTierJNI.setTunFd("my_instance", fd);
} catch (RuntimeException e) {
Log.e("EasyTier", "设置 TUN FD 失败", e);
}
}
return START_STICKY;
}
private ParcelFileDescriptor establishVpnInterface() {
Builder builder = new Builder();
builder.setMtu(1500);
builder.addAddress("10.0.0.2", 24);
builder.addRoute("0.0.0.0", 0);
builder.setSession("EasyTier VPN");
return builder.establish();
}
}
API 参考
EasyTierJNI 类方法
| 方法 | 描述 | 参数 | 返回值 |
|---|---|---|---|
parseConfig(String config) |
解析 TOML 配置 | config: 配置字符串 | 0=成功, -1=失败 |
runNetworkInstance(String config) |
启动网络实例 | config: 配置字符串 | 0=成功, -1=失败 |
setTunFd(String instanceName, int fd) |
设置 TUN 文件描述符 | instanceName: 实例名, fd: 文件描述符 | 0=成功, -1=失败 |
retainNetworkInstance(String[] names) |
保留指定实例 | names: 实例名数组 | 0=成功, -1=失败 |
collectNetworkInfos(int maxLength) |
收集网络信息 | maxLength: 最大条目数 | 信息字符串数组 |
collectNetworkInfosAsMap(int maxLength) |
收集网络信息为 Map | maxLength: 最大条目数 | Map<String, String> |
getLastError() |
获取最后错误 | 无 | 错误消息字符串 |
stopAllInstances() |
停止所有实例 | 无 | 0=成功, -1=失败 |
retainSingleInstance(String name) |
保留单个实例 | name: 实例名 | 0=成功, -1=失败 |
故障排除
常见问题
-
构建失败: "Android NDK not found"
- 确保设置了
ANDROID_NDK_ROOT环境变量 - 检查 NDK 路径是否正确
- 确保设置了
-
运行时错误: "java.lang.UnsatisfiedLinkError"
- 确保
.so文件放在正确的jniLibs目录下 - 检查目标架构是否匹配
- 确保
-
配置解析失败
- 检查 TOML 配置格式是否正确
- 使用
getLastError()获取详细错误信息
调试技巧
- 启用 Android 日志查看 JNI 层的日志输出
- 使用
adb logcat -s EasyTier-JNI查看相关日志 - 检查
getLastError()返回的错误信息
许可证
本项目遵循与 EasyTier 主项目相同的许可证。
贡献
欢迎提交 Issue 和 Pull Request 来改进这个项目。