Formal releases with iOS runtime changes now bump MARKETING_VERSION, archive the tag via Xcode Cloud, wait until App Store Connect marks the build Valid, and submit App Review. GitHub publication stays independent of iOS outcome.
138 lines
5.1 KiB
Markdown
138 lines
5.1 KiB
Markdown
# EdgeEver iOS (Swift)
|
|
|
|
Native SwiftUI client for EdgeEver. This replaces the React Native / Expo iOS target.
|
|
|
|
**App Store binaries on macOS beta:** use **Xcode Cloud** — [`docs/ios-xcode-cloud.md`](../../docs/ios-xcode-cloud.md). Formal Releases start Cloud through store-delivery.
|
|
|
|
## Status
|
|
|
|
UI/interaction is aligned with the Android RN app (`apps/mobile`):
|
|
|
|
- Login / session (Keychain with UserDefaults fallback) / device id
|
|
- GRDB local mirror + bootstrap / incremental sync
|
|
- SQLite outbox (create/update, create-absorbs-update, conflict/retry)
|
|
- Workspace chrome: notebook title picker, search (250ms debounce), filter chips, list options (sort/density/batch), FAB create, long-press multi-select, swipe pin/delete
|
|
- Memo detail + create/edit autosave, share link, revisions, soft delete
|
|
- EditorBundle (WKWebView body + toolbar)
|
|
- Image pick + materialize-for-upload (K24) + protected resource blob loading
|
|
- Settings: general / account / tags / API tokens / devices / users (owner) / about
|
|
- Share Extension (text/URL → App Group → new draft)
|
|
- Locale (system/zh/en) + theme + list density
|
|
|
|
Android remains Expo / React Native in `apps/mobile`. Store builds for iOS use this native tree (`Scripts/archive-app-store.sh`), not EAS.
|
|
|
|
## Motion / animations
|
|
|
|
Motion stack: **SwiftUI Animation** (timing / springs) + **[Pow](https://github.com/EmergeTools/Pow)** (Emerge).
|
|
|
|
| Effect | Where |
|
|
|--------|--------|
|
|
| **Jump** (physics hop + squash) | First list open (whole list); create/edit return on that memo |
|
|
| **Boing** (elastic drop-in) | Staggered first-paint cards |
|
|
| **Ping** | Create button / returned memo highlight |
|
|
| **Shine / Shake / Haptic** | Pin success, errors, selection |
|
|
| SwiftUI scale press | Card / create / filter finger-down |
|
|
|
|
Curves & wrappers: `EdgeEver/DesignSystem/Motion.swift`.
|
|
|
|
## Requirements
|
|
|
|
- Xcode 16+ (Xcode 27 beta OK for local dev)
|
|
- iOS 17+ deployment target
|
|
- [XcodeGen](https://github.com/yonaskolb/XcodeGen) to regenerate the project
|
|
|
|
```sh
|
|
brew install xcodegen
|
|
```
|
|
|
|
## Generate & open
|
|
|
|
```sh
|
|
cd apps/ios
|
|
xcodegen generate
|
|
open EdgeEver.xcodeproj
|
|
```
|
|
|
|
## Tests
|
|
|
|
```sh
|
|
# Unit + live API tests (live tests skip if local server is down)
|
|
xcodebuild test \
|
|
-project EdgeEver.xcodeproj \
|
|
-scheme EdgeEver \
|
|
-destination 'platform=iOS Simulator,name=iPhone 17 Pro'
|
|
```
|
|
|
|
Live API tests login to `http://127.0.0.1:8787` using `EDGE_EVER_AUTH_PASSWORD` or monorepo `.env.wrangler.generated.local`.
|
|
|
|
## Simulator auto-login (QA)
|
|
|
|
With local `bun run dev` running:
|
|
|
|
```sh
|
|
xcrun simctl launch booted org.edgeever.mobile \
|
|
-EdgeEverAutoLoginURL "http://127.0.0.1:8787" \
|
|
-EdgeEverAutoLoginUser admin \
|
|
-EdgeEverAutoLoginPassword "$EDGE_EVER_AUTH_PASSWORD"
|
|
```
|
|
|
|
## Versioning
|
|
|
|
| Field | File | Notes |
|
|
| --- | --- | --- |
|
|
| `MARKETING_VERSION` | `Config/Version.xcconfig` | Align with monorepo release `X.Y.Z` on store submissions |
|
|
| `CURRENT_PROJECT_VERSION` | `Config/Version.xcconfig` | Local floor for build numbers |
|
|
|
|
**Xcode Cloud** stamps `CFBundleVersion` from App Store Connect → Xcode Cloud → **Build Number** (not only this file). Before a Cloud store run, set that counter **above** the latest ASC build (`Scripts/ensure-xcode-cloud-build-number.sh` prints the recommended value).
|
|
|
|
## App Store archive
|
|
|
|
### Preferred: Xcode Cloud
|
|
|
|
If the Mac runs **macOS beta**, local archives are rejected by App Store Connect (**ITMS-90111**) even with release Xcode. Day-to-day development stays local; **only store / TestFlight binaries** should use **Xcode Cloud** (25 compute hours/month with Apple Developer Program). Formal Releases start Cloud through store-delivery; keep the Cloud workflow start condition **Manual** so git pushes do not consume hours.
|
|
|
|
- Setup and workflow: **[`docs/ios-xcode-cloud.md`](../../docs/ios-xcode-cloud.md)**
|
|
- Cloud hooks: `ci_scripts/ci_post_clone.sh` → `ci_pre_xcodebuild.sh` → `ci_post_xcodebuild.sh`
|
|
- Workflow start condition must stay **Manual** so hours are not burned on every push
|
|
- Put ASC API secrets in Xcode Cloud **shared environment variables** so `ci_post_xcodebuild.sh` auto-uploads the App Store IPA
|
|
|
|
```sh
|
|
# Before Start Build (optional but recommended)
|
|
cd apps/ios
|
|
bash Scripts/ensure-xcode-cloud-build-number.sh
|
|
|
|
# If Cloud produced ARCHIVE_EXPORT but ASC has no build:
|
|
bash Scripts/upload-app-store-ipa.sh /path/to/EdgeEver-*-app-store.zip
|
|
```
|
|
|
|
### Local archive (release macOS only)
|
|
|
|
Use the stable Xcode app (not beta) on a **non-beta** host OS:
|
|
|
|
```sh
|
|
cd apps/ios
|
|
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer bash Scripts/archive-app-store.sh
|
|
bash Scripts/upload-app-store-ipa.sh build/export/EdgeEver.ipa
|
|
```
|
|
|
|
On a beta host the script **exits** unless you set `EDGE_EVER_IOS_ALLOW_BETA_HOST=1` (upload will still likely fail ASC).
|
|
|
|
Signing in the Xcode project is **Automatic** (Cloud-friendly). Local export still uses `ExportOptions.plist` with App Store profiles. Then submit the exact build with:
|
|
|
|
```sh
|
|
cd apps/ios
|
|
APP_STORE_VERSION=X.Y.Z APP_STORE_BUILD_NUMBER=N \
|
|
APP_STORE_CONNECT_API_KEY_ID=... \
|
|
APP_STORE_CONNECT_API_ISSUER_ID=... \
|
|
APP_STORE_CONNECT_API_KEY_P8_BASE64=... \
|
|
fastlane ios submit_review
|
|
```
|
|
|
|
## Regenerating the Xcode project
|
|
|
|
Edit `project.yml`, then:
|
|
|
|
```sh
|
|
xcodegen generate
|
|
```
|