Files
EasyTier/easytier-contrib/easytier-android-jni
Mg Pig 841d525913 refactor(rpc): Centralize RPC service and unify API (#1427)
This change introduces a major refactoring of the RPC service layer to improve modularity, unify the API, and simplify the overall architecture.

Key changes:
- Replaced per-network-instance RPC services with a single global RPC server, reducing resource usage and simplifying management.
- All clients (CLI, Web UI, etc.) now interact with EasyTier core through a unified RPC entrypoint, enabling consistent authentication and control.
- RPC implementation logic has been moved to `easytier/src/rpc_service/` and organized by functionality (e.g., `instance_manage.rs`, `peer_manage.rs`, `config.rs`) for better maintainability.
- Standardized Protobuf API definitions under `easytier/src/proto/` with an `api_` prefix (e.g., `cli.proto` → `api_instance.proto`) to provide a consistent interface.
- CLI commands now require explicit `--instance-id` or `--instance-name` when multiple network instances are running; the parameter is optional when only one instance exists.

BREAKING CHANGE:  
RPC portal configuration (`rpc_portal` and `rpc_portal_whitelist`) has been removed from per-instance configs and the Web UI. The RPC listen address must now be specified globally via the `--rpc-portal` command-line flag or the `ET_RPC_PORTAL` environment variable, as there is only one RPC service for the entire application.
2025-10-02 20:30:39 +08:00
..
2025-09-06 13:49:42 +08:00
2025-09-06 13:49:42 +08:00
2025-09-06 13:49:42 +08:00

EasyTier Android JNI

这是 EasyTier 的 Android JNI 绑定库,允许 Android 应用程序调用 EasyTier 的网络功能。

功能特性

  • 🚀 完整的 EasyTier FFI 接口封装
  • 📱 原生 Android JNI 支持
  • 🔧 支持多种 Android 架构 (arm64-v8a, armeabi-v7a, x86, x86_64)
  • 🛡️ 类型安全的 Java 接口
  • 📝 详细的错误处理和日志记录

支持的架构

  • 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 开发环境

环境设置

  1. 安装 Rust

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    source ~/.cargo/env
    
  2. 安装 Android NDK

  3. 添加 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
    

构建步骤

  1. 克隆项目并进入目录

    cd /path/to/EasyTier/easytier-contrib/easytier-android-jni
    
  2. 运行构建脚本

    ./build.sh
    
  3. 构建完成后,库文件将生成在 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());
        }
    }
}

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=失败

故障排除

常见问题

  1. 构建失败: "Android NDK not found"

    • 确保设置了 ANDROID_NDK_ROOT 环境变量
    • 检查 NDK 路径是否正确
  2. 运行时错误: "java.lang.UnsatisfiedLinkError"

    • 确保 .so 文件放在正确的 jniLibs 目录下
    • 检查目标架构是否匹配
  3. 配置解析失败

    • 检查 TOML 配置格式是否正确
    • 使用 getLastError() 获取详细错误信息

调试技巧

  • 启用 Android 日志查看 JNI 层的日志输出
  • 使用 adb logcat -s EasyTier-JNI 查看相关日志
  • 检查 getLastError() 返回的错误信息

许可证

本项目遵循与 EasyTier 主项目相同的许可证。

贡献

欢迎提交 Issue 和 Pull Request 来改进这个项目。

相关链接