flutter-tsnet/build_go.sh
Mathias Beaulieu-Duncan 2dbadcd8ed Initial commit: embedded Tailscale tsnet Flutter plugin for remote heater access
Go layer (c-archive) provides a localhost TCP proxy through a WireGuard tunnel.
Flutter connects gRPC to localhost:PORT, Go forwards via tsnet to heater's Tailscale IP.
No VPN entitlement needed — uses userspace netstack.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 05:13:55 -04:00

150 lines
4.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# Build the Go static library for iOS using go build -buildmode=c-archive.
#
# This is the production-grade approach (same as Tailscale's own iOS app).
# No gomobile dependency — just the standard Go compiler + Xcode SDK.
#
# Prerequisites:
# - Go 1.23+
# - Xcode with iOS SDK
#
# Usage:
# cd /path/to/tailscale_kit
# ./build_go.sh
#
# Output: ios/TailscaleKit.xcframework (static library xcframework)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
GO_DIR="$SCRIPT_DIR/ios/Go"
BUILD_DIR="$SCRIPT_DIR/ios/build"
OUTPUT="$SCRIPT_DIR/ios/TailscaleKit.xcframework"
MIN_IOS="14.0"
# Omit Tailscale features we don't need — we only use tsnet.Dial() for proxying.
OMIT_TAGS="ts_omit_ssh,ts_omit_drive,ts_omit_taildrop,ts_omit_serve"
OMIT_TAGS="$OMIT_TAGS,ts_omit_webclient,ts_omit_capture,ts_omit_appconnectors"
OMIT_TAGS="$OMIT_TAGS,ts_omit_debug,ts_omit_doctor,ts_omit_portlist,ts_omit_posture"
OMIT_TAGS="$OMIT_TAGS,ts_omit_cli,ts_omit_kube,ts_omit_aws,ts_omit_bird"
OMIT_TAGS="$OMIT_TAGS,ts_omit_synology,ts_omit_tpm,ts_omit_tap,ts_omit_conn25"
OMIT_TAGS="$OMIT_TAGS,ts_omit_qrcodes,ts_omit_relayserver,ts_omit_systray"
OMIT_TAGS="$OMIT_TAGS,ts_omit_webbrowser,ts_omit_completion,ts_omit_completion_scripts"
OMIT_TAGS="$OMIT_TAGS,ts_omit_colorable,ts_omit_clientupdate,ts_omit_wakeonlan"
OMIT_TAGS="$OMIT_TAGS,ts_omit_usermetrics,ts_omit_desktop_sessions,ts_omit_ace"
OMIT_TAGS="$OMIT_TAGS,ts_omit_acme,ts_omit_hujsonconf,ts_omit_tailnetlock"
OMIT_TAGS="$OMIT_TAGS,ts_omit_netlog,ts_omit_syspolicy,ts_omit_cachenetmap"
rm -rf "$BUILD_DIR" "$OUTPUT"
mkdir -p "$BUILD_DIR/ios-arm64/Headers" "$BUILD_DIR/ios-arm64-simulator/Headers"
cd "$GO_DIR"
echo "==> Tidying Go modules..."
go mod tidy
# --- Build for iOS device (arm64) ---
echo "==> Building for iOS device (arm64)..."
IPHONEOS_SDK=$(xcrun --sdk iphoneos --show-sdk-path)
IPHONEOS_CC=$(xcrun --sdk iphoneos --find clang)
CGO_ENABLED=1 \
GOOS=ios \
GOARCH=arm64 \
CC="$IPHONEOS_CC" \
CGO_CFLAGS="-isysroot $IPHONEOS_SDK -arch arm64 -miphoneos-version-min=$MIN_IOS" \
CGO_LDFLAGS="-isysroot $IPHONEOS_SDK -arch arm64 -miphoneos-version-min=$MIN_IOS" \
go build \
-buildmode=c-archive \
-tags "$OMIT_TAGS" \
-ldflags="-s -w" \
-o "$BUILD_DIR/ios-arm64/libtailscale.a" \
.
# Helper: create a framework bundle from a static library
create_framework() {
local lib_path="$1"
local header_path="$2"
local framework_dir="$3"
mkdir -p "$framework_dir/Headers" "$framework_dir/Modules"
# Copy the static library as the framework binary
cp "$lib_path" "$framework_dir/TailscaleKit"
# Copy and clean the header (remove Go-internal types)
cp "$header_path" "$framework_dir/Headers/tailscale.h"
# Module map
cat > "$framework_dir/Modules/module.modulemap" <<'MODMAP'
framework module TailscaleKit {
header "tailscale.h"
export *
}
MODMAP
# Info.plist
cat > "$framework_dir/Info.plist" <<PLIST
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>com.constellation-heating.TailscaleKit</string>
<key>CFBundleName</key>
<string>TailscaleKit</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
</dict>
</plist>
PLIST
}
create_framework \
"$BUILD_DIR/ios-arm64/libtailscale.a" \
"$BUILD_DIR/ios-arm64/libtailscale.h" \
"$BUILD_DIR/ios-arm64/TailscaleKit.framework"
# --- Build for iOS simulator (arm64) ---
echo "==> Building for iOS simulator (arm64)..."
SIMULATOR_SDK=$(xcrun --sdk iphonesimulator --show-sdk-path)
SIMULATOR_CC=$(xcrun --sdk iphonesimulator --find clang)
CGO_ENABLED=1 \
GOOS=ios \
GOARCH=arm64 \
CC="$SIMULATOR_CC" \
CGO_CFLAGS="-isysroot $SIMULATOR_SDK -arch arm64 -miphoneos-version-min=$MIN_IOS -target arm64-apple-ios${MIN_IOS}-simulator" \
CGO_LDFLAGS="-isysroot $SIMULATOR_SDK -arch arm64 -miphoneos-version-min=$MIN_IOS -target arm64-apple-ios${MIN_IOS}-simulator" \
go build \
-buildmode=c-archive \
-tags "$OMIT_TAGS" \
-ldflags="-s -w" \
-o "$BUILD_DIR/ios-arm64-simulator/libtailscale.a" \
.
create_framework \
"$BUILD_DIR/ios-arm64-simulator/libtailscale.a" \
"$BUILD_DIR/ios-arm64-simulator/libtailscale.h" \
"$BUILD_DIR/ios-arm64-simulator/TailscaleKit.framework"
# --- Create xcframework from framework bundles ---
echo "==> Creating xcframework..."
xcodebuild -create-xcframework \
-framework "$BUILD_DIR/ios-arm64/TailscaleKit.framework" \
-framework "$BUILD_DIR/ios-arm64-simulator/TailscaleKit.framework" \
-output "$OUTPUT"
# Clean up build artifacts
rm -rf "$BUILD_DIR"
# Also copy the header to Classes/ for CocoaPods umbrella header
cp "$OUTPUT/ios-arm64/TailscaleKit.framework/Headers/tailscale.h" "$SCRIPT_DIR/ios/Classes/tailscale.h"
echo "==> Built: $OUTPUT"
du -sh "$OUTPUT"
echo "==> Device framework:"
ls -lh "$OUTPUT/ios-arm64/TailscaleKit.framework/TailscaleKit"