Overview
A full-featured SwiftUI iOS starter with Supabase, RevenueCat, push notifications, and analytics wired in.
The Swift (iOS) template is a full-featured SwiftUI starter for iPhone and iPad. It ships with authentication, a Supabase backend, cross-platform subscriptions via RevenueCat, push notifications, deep links, analytics, crash reporting, and a full launch-gate stack (onboarding, legal consent, biometric lock, forced update) already wired together — so you build your product instead of the plumbing.
The core services above are wired end to end. A few surfaces are working Example features or a Removable demo meant to be replaced before you ship. The feature status table below is explicit about what is integrated and what you are expected to swap out.
Minimum iOS: 17.0. Targeted devices: iPhone + iPad. Built with Xcode 16+.
Graceful degradation
Every secret is optional. Missing keys don't crash the app — the owning
controller flips to isConfigured = false and no-ops, so the project builds
and boots with zero configuration. You wire services in one at a time as you
need them. This is a headline behavior of the template; each service page notes
exactly what happens when its key is absent. See
Configuration.
Tech stack
| Layer | Choice |
|---|---|
| UI | SwiftUI (iOS 17+) |
| Architecture | MVVM (@Observable view models) + Repository pattern |
| Dependency injection | AppEnvironment container via @Environment (no Swinject/Factory) |
| Navigation | NavigationStack + Hashable route enums; TabView main shell |
| Backend | supabase-swift (Auth, PostgREST, Storage) |
| Concurrency | Swift Concurrency (async/await, AsyncStream), MainActor default isolation |
| Session storage | iOS Keychain (via supabase-swift's KeychainLocalStorage) |
| App state | UserDefaults (AppPreferences wrapper) |
| Image loading | Kingfisher (via a small RemoteImage wrapper) |
| Subscriptions | RevenueCat (purchases-ios) |
| Push | APNs via UNUserNotificationCenter + UIApplicationDelegateAdaptor |
| Analytics | PostHog (posthog-ios) |
| Crash reporting | Sentry (sentry-cocoa) |
| Biometric | LocalAuthentication (LAContext) |
| In-app review | StoreKit requestReview(in:) |
| Deep links | Universal Links + custom soar:// scheme |
| i18n | Localizable.xcstrings String Catalog (English + Simplified Chinese) |
Feature status
Features are labelled consistently throughout these docs:
- Integrated — fully wired; activates when its key or service is configured.
- Example — a working demo feature meant to be replaced with your own.
- Removable demo — the Showcase tab; delete it without touching core code.
- Device-only — needs a physical device and a paid Apple Developer team.
| Feature | Status | Notes |
|---|---|---|
| Authentication | Integrated | Email/password, sign-up + email OTP, forgot/reset, change email/password, sign out other sessions, delete account |
| Google Sign-In | Integrated | Native SDK ID token → Supabase; needs GOOGLE_IOS_CLIENT_ID (tile is dimmed until set) |
| Apple Sign-In | Integrated | ASAuthorizationController → Supabase signInWithIdToken; needs the Sign in with Apple capability |
| Subscriptions | Integrated | RevenueCat paywall (monthly/yearly/lifetime); entitlement read from the shared Supabase subscriptions table |
| Push notifications | Device-only | APNs registration only succeeds on a real device with a paid team |
| Deep links | Integrated | soar:// scheme + Universal Links, routable to every major destination |
| Analytics | Integrated | PostHog typed events, consent-gated start, identify/reset on auth changes |
| Crash reporting | Integrated | Sentry with user tagging, ErrorBoundary, user-feedback hook |
| Launch gates | Integrated | Biometric lock, forced/soft update, onboarding, legal consent |
| Store review | Integrated | StoreKit smart trigger (action count + version + 90-day cooldown) |
| i18n | Integrated | English + Simplified Chinese, runtime language switch |
| Theming | Integrated | Light / Dark / System, persisted |
| Offline banner | Integrated | NetworkObserver (NWPathMonitor) mounted app-wide |
| Toast / haptics | Integrated | Top-of-screen toast overlay with success/error haptics |
| Todos | Example | Full CRUD reference feature — copy its shape for your own data |
| Upload sample | Example | PhotosPicker → Supabase Storage with per-job progress |
| Profile | Example | Avatar, personal info, account & security screens |
| Refer a friend | Example | ShareLink + referral URL |
| Showcase | Removable demo | Catalog of every capability; deletable in one step |
App surface map
The app is composed as three layers, outside-in:
- Gate stack —
RootViewwraps everything in gates, evaluated in order:ErrorBoundary → Biometric → Update → Onboarding → Consent → Auth. Each gate blocks the layers below it until satisfied. See App Gates. - Auth stack — when there's no session, a small
NavigationStackdrives the login / sign-up / verify / forgot-password screens. See Authentication. - Main shell — once signed in,
MainShellViewmounts aTabViewwith four tabs (Home, Component, Showcase, Me) plus a side drawer. Each tab owns its ownNavigationStack(path:)so back-stacks survive tab switches.
Cross-platform entitlement
Subscriptions are account-bound, not device-bound. A purchase flows through
the RevenueCat webhook into a shared Supabase subscriptions read-model, and the
app reads that table — not the RevenueCat SDK's CustomerInfo — as the
source of truth. The same read-model is shared with the desktop template, so an
entitlement bought on one platform is honored on the other. See
Subscriptions.
Start here
Follow this path from clone to a shippable app:
Installation
Open the project and boot it in the simulator.
Configuration
The Secrets.xcconfig key reference.
Supabase Setup
Stand up the backend and database.
Authentication
Sessions, OTP, and social sign-in.
Subscriptions
RevenueCat and account-bound entitlement.
App Store Release
Archive, TestFlight, and submit.
