- Document all 4 platforms with status and architecture details - Add API reference table - Add platform setup sections (iOS, macOS, Android, Linux) - Document build commands for all platforms - Add binary size table - Note Android Tailscale tunnel limitation and path forward - Add Linux test file Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
133 lines
4.4 KiB
Markdown
133 lines
4.4 KiB
Markdown
# tsnet_flutter
|
|
|
|
Embed [Tailscale's tsnet](https://pkg.go.dev/tailscale.com/tsnet) in Flutter apps. Provides a userspace WireGuard tunnel with a localhost TCP proxy — **no VPN entitlement needed** on iOS.
|
|
|
|
## How it works
|
|
|
|
```
|
|
Flutter App (Dart)
|
|
└── tsnet_flutter plugin
|
|
├── iOS/macOS: Swift MethodChannel → C bridge → Go static library (.a)
|
|
└── Android/Linux: Dart FFI → Go shared library (.so)
|
|
↓
|
|
Go tsnet (WireGuard + userspace netstack)
|
|
↓
|
|
localhost TCP proxy (127.0.0.1:PORT)
|
|
↓
|
|
WireGuard tunnel → remote device (100.x.x.x)
|
|
```
|
|
|
|
Your app connects to `localhost:PORT`. Traffic is forwarded through a WireGuard tunnel to the target device's Tailscale IP. Your app doesn't know about Tailscale — it just sees a localhost port.
|
|
|
|
## Usage
|
|
|
|
```dart
|
|
import 'package:tsnet_flutter/tsnet_flutter.dart';
|
|
|
|
final tsnet = TsnetFlutter();
|
|
|
|
// Join the Tailnet
|
|
await tsnet.start(authKey: 'tskey-auth-...');
|
|
|
|
// Create a local proxy to the remote device
|
|
final localPort = await tsnet.startProxy('100.64.0.5', port: 5050);
|
|
|
|
// Connect your client to the proxy
|
|
yourClient.connect('127.0.0.1', port: localPort);
|
|
|
|
// Clean up
|
|
await tsnet.stopProxy();
|
|
await tsnet.stop();
|
|
```
|
|
|
|
## API
|
|
|
|
| Method | Description |
|
|
|--------|-------------|
|
|
| `start(authKey, hostname)` | Join a Tailnet with an auth key. Idempotent — safe to call multiple times. |
|
|
| `startProxy(ip, port)` | Create a localhost TCP proxy to a remote Tailscale IP. Returns the local port. |
|
|
| `stopProxy()` | Stop the localhost proxy. |
|
|
| `stop()` | Disconnect from the Tailnet. |
|
|
| `status()` | Get the current Tailscale connection status (state, peers, IPs). |
|
|
| `tailscaleIP()` | Get this device's Tailscale IPv4 address (100.x.x.x). |
|
|
|
|
## Platform support
|
|
|
|
| Platform | Tailscale tunnel | Binary type | Architectures |
|
|
|----------|-----------------|-------------|---------------|
|
|
| iOS | Supported | c-archive (.a in xcframework) | arm64 device + arm64 simulator |
|
|
| macOS | Supported | c-archive (.a in xcframework) | arm64 + x86_64 universal |
|
|
| Linux | Supported | c-shared (.so) | amd64 |
|
|
| Android | Local only (WIP) | c-shared (.so in jniLibs) | arm64-v8a + x86_64 |
|
|
|
|
**Android note:** Local TCP connections work. Tailscale tunnel is blocked by Go's `net.Interfaces()` requiring `CAP_NET_ADMIN` on Android. Full tunnel support will require `libtailscale` integration from [tailscale-android](https://github.com/tailscale/tailscale-android).
|
|
|
|
## Platform setup
|
|
|
|
### iOS
|
|
|
|
No special entitlements or permissions needed. No VPN entitlement required.
|
|
|
|
### macOS
|
|
|
|
macOS apps run sandboxed. Add these entitlements to both `DebugProfile.entitlements` and `Release.entitlements`:
|
|
|
|
```xml
|
|
<key>com.apple.security.network.client</key>
|
|
<true/>
|
|
<key>com.apple.security.network.server</key>
|
|
<true/>
|
|
```
|
|
|
|
`network.client` allows the app to connect to the localhost proxy and external networks.
|
|
`network.server` allows the Go layer to open a localhost listener for the proxy.
|
|
|
|
### Android
|
|
|
|
Add the `INTERNET` permission to your `AndroidManifest.xml`:
|
|
|
|
```xml
|
|
<uses-permission android:name="android.permission.INTERNET" />
|
|
```
|
|
|
|
### Linux
|
|
|
|
No special setup needed. The shared library is bundled automatically.
|
|
|
|
## Requirements
|
|
|
|
- Tailscale auth key — generate at [login.tailscale.com/admin/settings/keys](https://login.tailscale.com/admin/settings/keys)
|
|
- Auth keys can be reusable and tag-scoped for ACL isolation
|
|
|
|
## Building from source
|
|
|
|
The pre-built binaries are included in the package. To rebuild from Go source:
|
|
|
|
```bash
|
|
# Prerequisites: Go 1.23+, Xcode (for Apple platforms), Android NDK (for Android)
|
|
|
|
./build_go.sh # build all platforms
|
|
./build_go.sh ios # iOS only
|
|
./build_go.sh macos # macOS only
|
|
./build_go.sh android # Android only (requires NDK)
|
|
./build_go.sh linux # Linux only (uses Docker on macOS)
|
|
./build_go.sh apple # iOS + macOS
|
|
```
|
|
|
|
## Binary sizes
|
|
|
|
| Platform | Size | Notes |
|
|
|----------|------|-------|
|
|
| iOS (device) | ~23 MB | After App Store compression: ~14 MB |
|
|
| iOS (simulator) | ~23 MB | Development only |
|
|
| macOS (universal) | ~49 MB | arm64 + x86_64 |
|
|
| Android (arm64) | ~20 MB | |
|
|
| Android (x86_64) | ~22 MB | Emulator only |
|
|
| Linux (amd64) | ~24 MB | |
|
|
|
|
Size is dominated by WireGuard + gVisor netstack + Go runtime. Feature tags strip ~35 unused Tailscale subsystems (SSH, Drive, Serve, etc.).
|
|
|
|
## License
|
|
|
|
BSD-3-Clause — compatible with Tailscale's license. See [LICENSE](LICENSE).
|