Add a native iOS client for relay-based file sharing
The SwiftUI app bundles the Go swarm engine through gomobile, so an iPhone is a real peer using the existing PAKE handshake, chunk verification, and relay fallback. XcodeGen builds the project and devicectl installs it on the paired phone.
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
# 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.)
|
||||
|
||||
```sh
|
||||
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):
|
||||
|
||||
```sh
|
||||
# 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):
|
||||
|
||||
```sh
|
||||
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:
|
||||
|
||||
```sh
|
||||
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 `croc.schollz.com:9009`. 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.
|
||||
Reference in New Issue
Block a user