30 行代码接入 ZeroTier Android SDK
【免费下载链接】ZeroTierOneA Smart Ethernet Switch for Earth项目地址: https://gitcode.com/GitHub_Trending/ze/ZeroTierOne
想让 App 里的设备绕开公网、像同一局域网那样直接对话?这篇带你把 ZeroTier Android SDK 一次跑通,适合准备集成虚拟组网能力的 Android 工程师。
🔍 机制速览:三层结构到底在干嘛
先给结论:ZeroTier SDK 是典型的"薄壳 + 回调"式设计。真正的虚拟交换机逻辑全在原生侧,Java 层只有一组接口,把存储、发包、收帧、事件这四类事交还给你实现。
| 层级 | 负责什么 | 你会碰到的入口 |
|---|---|---|
| Java 层 | Node 对象 + 7 个监听接口,纯声明 | Node.java |
| JNI 层 | 把 Java 调用翻译成 C++ 函数,用 nodeId 当句柄 | com_zerotierone_sdk_Node.cpp |
| Native 层 | 加密、组网、路由,真正的"交换机"本体 | Node 的 native 方法实现 |
所以集成的心智模型是:你不是在"驱动"SDK,而是 SDK 在"驱动"你。你只做三件事——把数据入口喂给它、接住它推出来的帧、再给它一个节拍。
📦 准备清单:5 样东西凑齐再开工
为什么先列清单?因为 JNI 部分的环境变量只影响构建环节,很多人照抄教程却在构建期卡住。要求都写在 java/README.md,逐项对照:
- JDK 8 以上,编译期用到 ANT
- Android NDK(r21+),提供
ndk-build - Android SDK 平台,API 21 以上
- 环境变量:
NDK_BUILD_LOC指向 ndk-build 脚本,ANDROID_PLATFORM指向 android.jar 所在目录 - 产物
libZeroTierOneJNI.so按 ABI 放进app/src/main/jniLibs/
如果只消费预编译好的 .so,前四项可以跳过,直奔最后一条。
⚡ 核心流程:3 个逻辑块跑通全链路
放对 SO:加载与入网
Node 类内部已经写死了loadLibrary("ZeroTierOneJNI"),你不用写任何加载代码,.so 放好位置就等于完成接入。这一步只是建节点、注入监听器、宣告入网:
Node node = new Node(System.currentTimeMillis()); ResultCode rc = node.init(getL, putL, sender, eventL, frameL, configL, null); node.join(0x8F31C2D4A9B6L);init返回RESULT_OK后join才会生效;重复加入同一网络会被忽略并直接返回 OK,可以放心幂等调用。
接回调:把发包口交给你的 UDP 套接字
7 个监听器里,get/put 是持久化存储的读写两半,event 收状态通知,frame 和 config 推虚拟网数据与配置变化,真正往物理网络发包的只有 PacketSender——它是组网的唯一出口。物理通道我们用一块 UDP 套接字:
public int onSendPacketRequested(long socket, InetSocketAddress addr, byte[] data, int ttl) { udpSocket.send(new DatagramPacket(data, data.length, addr)); return 0; }返回 0 表示"已递交",对端收不收得到属于网络层的事,SDK 不会替你重传,可靠性交给上层协议。
喂数据:两个入口 + 一个节拍器
ZeroTier One 是被动式的:物理线上收到的包要喂给processWirePacket,你自己 App 产出的帧要走processVirtualNetworkFrame。两个函数都会把下次后台任务的截止时间写进deadline数组,拿它挂定时器最省心:
byte[] buf = new byte[1500]; long[] deadline = new long[1]; node.processWirePacket(now, -1, remoteAddr, buf, deadline); node.processVirtualNetworkFrame(now, nwid, srcMac, dstMac, 0x0800, 0, payload, deadline); while (node.isInited()) { Thread.sleep(Math.max(0L, deadline[0] - System.currentTimeMillis())); node.processBackgroundTasks(System.currentTimeMillis(), deadline); }到这里闭环就形成了:对端来包 → processWirePacket → 交换机转发 → onVirtualNetworkFrame → 你的业务层。
🚀 进阶:让 ARP 和 Moon 都听话
让 ARP 可规模化
普通广播 ARP 在虚拟网里不划算,ZeroTier 的解法是对广播 MAC 做订阅、把 ADI 设成各 IPv4 地址(主机字节序),每个 IP 订一次,ARP 就变成精确多播:
for (long ip : assignedIps) { node.multicastSubscribe(nwid, 0xFFFFFFFFFFFFL, ip); }给组网加一颗 Moon
Moon 是缩短跨网段路径的中继枢纽,orbit加入、deorbit移除,定义会持久化到数据目录里。业务只追求"局域网感"的话,这两项可以先不碰。
另外leave、peers、status、networkConfigs这些查询方法都挂在同一个 Node 上,用到再查注释即可。
🕳️ 踩坑实录:5 个高频翻车现场
1. 启动即崩现象:首启抛UnsatisfiedLinkError。 根因:.so 没进 jniLibs,或 ABI 与设备对不上。 解法:按app/src/main/jniLibs/<abi>/摆放libZeroTierOneJNI.so,NDK 目标架构与设备一致。
2. 首次 init 卡住数秒现象:第一次init时 UI 冻结。 根因:首次运行要生成节点身份,弱设备上明显偏慢。 解法:丢到后台线程执行,界面展示"身份生成中"状态。
3. 数据源致命错误现象:返回RESULT_FATAL_ERROR_DATA_STORE_FAILED,之后调用全部失效。 根因:get/put 监听器背后的持久化目录不可写。 解法:init之前先确保监听器实现的目录已创建、权限已就绪。
4. Ping 通但 ARP 解析失败现象:首包可达,之后通信时断时续。 根因:漏了按 IP 做 ADI 订阅,广播 ARP 无法规模化。 解法:拿到网段配置后,对每个 IP 各跑一次multicastSubscribe。
5. close 之后复用现象:close()后新建 Node 行为异常。 根因:旧对象已失效,而监听器实例还在跨 Node 共享。 解法:整套监听器重建、重新init,实例绝不复用。
join 返回 RESULT_OK 的那一刻,你的 App 就接进同一颗星球了。回调细节直接翻 java/src/com/zerotier/sdk 下的接口注释。
【免费下载链接】ZeroTierOneA Smart Ethernet Switch for Earth项目地址: https://gitcode.com/GitHub_Trending/ze/ZeroTierOne
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考