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.
109 lines
3.8 KiB
Markdown
109 lines
3.8 KiB
Markdown
# 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.
|