Go to file
Mathias Beaulieu-Duncan acae157519 Exclude macOS/Linux/x86_64 binaries from pub.dev to fit 100MB limit
Ship iOS + Android arm64 in the package (23MB compressed).
macOS, Linux, and Android x86_64 (emulator): build from source with ./build_go.sh

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 08:10:42 -04:00
.gitea/workflows Update CI pipeline to use refresh token for pub.dev auth 2026-03-14 06:28:12 -04:00
android Add Android and Linux platform support (local gRPC working, tsnet WIP) 2026-03-14 07:49:11 -04:00
ios Add Android and Linux platform support (local gRPC working, tsnet WIP) 2026-03-14 07:49:11 -04:00
lib Add Android and Linux platform support (local gRPC working, tsnet WIP) 2026-03-14 07:49:11 -04:00
linux Add Android and Linux platform support (local gRPC working, tsnet WIP) 2026-03-14 07:49:11 -04:00
macos Add macOS support, idempotent start(), bump to 0.2.0 2026-03-14 07:11:01 -04:00
test Update README with full platform docs, API reference, and binary sizes 2026-03-14 07:58:38 -04:00
.gitignore Initial commit: embedded Tailscale tsnet Flutter plugin for remote heater access 2026-03-14 05:13:55 -04:00
.pubignore Exclude macOS/Linux/x86_64 binaries from pub.dev to fit 100MB limit 2026-03-14 08:10:42 -04:00
build_go.sh Add Android and Linux platform support (local gRPC working, tsnet WIP) 2026-03-14 07:49:11 -04:00
CHANGELOG.md Bump to 0.3.0 for pub.dev — Android + Linux support 2026-03-14 08:08:37 -04:00
LICENSE Rename package to tsnet_flutter for pub.dev publishing under Svrnty 2026-03-14 06:10:34 -04:00
pubspec.lock Add Android and Linux platform support (local gRPC working, tsnet WIP) 2026-03-14 07:49:11 -04:00
pubspec.yaml Bump to 0.3.0 for pub.dev — Android + Linux support 2026-03-14 08:08:37 -04:00
README.md Update README with full platform docs, API reference, and binary sizes 2026-03-14 07:58:38 -04:00

tsnet_flutter

Embed Tailscale's 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

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.

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:

<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:

<uses-permission android:name="android.permission.INTERNET" />

Linux

No special setup needed. The shared library is bundled automatically.

Requirements

Building from source

The pre-built binaries are included in the package. To rebuild from Go source:

# 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.