Files
share/apps/ios/README.md
T
TZGyn decaaa2de1 Use the tzgyn relay as the default backend
The CLI and iOS app now point at share.tzgyn.dev:9009 instead of the upstream croc relay. Both were verified against the deployed relay; local relays remain available through --relay and the app's Relay setting.
2026-10-26 22:32:15 +08:00

3.8 KiB

Share for iOS

A native SwiftUI client for the share swarm. It uses the same Go engine as the CLI, compiled for iOS with gomobile, so the phone is a real peer: it can seed files, receive files, verify chunks, and fall back to the relay pipe when a direct connection is blocked.

apps/ios/
  project.yml              XcodeGen project (source of truth)
  Share/                   SwiftUI sources, assets, Info.plist
  GoBridge/                nested Go module exposing swarm to Swift
  build-go.sh              builds Share.xcframework with gomobile
  build.sh                 simulator or signed device build
  run-device.sh            install + launch on a paired iPhone
  Branding/make-icon.swift regenerates the app icon

Build

Requirements: Xcode, xcodegen, Go 1.26+ for the gomobile bridge, and network access the first time gomobile is installed. (The CLI itself still builds with the repo's Go 1.25 requirement.)

cd apps/ios

# Simulator (Apple Silicon)
./build.sh simulator

# Signed device build (team RX6767S6BW)
./build.sh device

# Install on the paired iPhone over Wi-Fi
./run-device.sh FeelsCringeMan

build.sh regenerates Share.xcframework before running xcodegen generate; the XCFramework and the generated .xcodeproj are build artifacts and are ignored by git.

Smoke tests

The app has two launch-argument driven tests that write Documents/share-selftest.txt; console output is unreliable on a simulator and unavailable on a device.

Receive (the app is the peer that downloads):

# 1. Start a relay on the Mac (all interfaces, so a phone can reach it).
go run . relay --host 0.0.0.0 --port 9009

# 2. Launch the test. Use 127.0.0.1 for the simulator, or the Mac's LAN
#    address for a physical phone.
xcrun simctl launch <udid> dev.tzgyn.share \
  -shareSelfTest -shareSelfTestRelay 127.0.0.1:9009 \
  -shareSelfTestCode 1234-selftest-share-apple

# 3. Seed a file from the CLI.
go run . send --relay 127.0.0.1:9009 --code 1234-selftest-share-apple /tmp/test.bin

# 4. Read the report from the simulator container.
DATA=$(xcrun simctl get_app_container <udid> dev.tzgyn.share data)
cat "$DATA/Documents/share-selftest.txt"

Send (the app seeds a generated 2 MiB file):

xcrun simctl launch <udid> dev.tzgyn.share \
  -shareSelfTestSend -shareSelfTestRelay 127.0.0.1:9009 \
  -shareSelfTestCode 1234-selftest-send-apple

go run . --relay 127.0.0.1:9009 --out /tmp/received --one-time \
  1234-selftest-send-apple

On a physical phone, read the report with:

xcrun devicectl device copy from --device <device> \
  --domain-type appDataContainer --domain-identifier dev.tzgyn.share \
  --source Documents/share-selftest.txt --destination /tmp/share-selftest.txt

How it works

  • GoBridge/share.go keeps one swarm.Client per room and exposes Start, StatusJSON, and Stop. Progress crosses the gomobile boundary as JSON so Swift only decodes plain value types.
  • The app copies picked files into Documents/Seeds/ before starting a room: the document picker's security-scoped URL is only valid while the picker callback is on the stack, not for the lifetime of a transfer.
  • Received files are written to Documents/Received/. UIFileSharingEnabled makes that folder visible in Files → On My iPhone → Share.
  • The default relay is the project's own share.tzgyn.dev:9009; the CLI and the iOS app both use it. For local transfers, run share relay on a Mac and enter its LAN address (192.168.x.x:9009) under Relay in the app.

Notes

  • The app runs one room at a time; starting another requires stopping the current one.
  • Receiving uses oneTime: true, so the room stops after every file known at that moment is complete. Sending keeps seeding until Stop.
  • iOS can suspend the app when it leaves the foreground; if the relay connection dies, the room card shows the error and a new room can be started.