Swift 5.9+ • iOS 15+ • SwiftPM 3.9.0+
iOS SDK
First-party Swift SDK with full deep linking, attribution, auth, push, Live Activities, geofences, Critical Alerts.
What's included
- Deep links (Branch parity): `links.create()` / `prewarm` / `handleUniversalLink` / `matchDeferred` / `revoke` / `getStats` + typed `LinkError`.
- Auth Service: anonymous, email+pass, magic, OTP, TOTP MFA, passkeys (ASAuthorization), OIDC + SAML SSO, Sign in with Apple / Google / Microsoft / LinkedIn / Facebook / Discord.
- Push: APNs, Live Activities (ActivityKit 16.1+) with auto-rotating per-activity push token, Critical Alerts (Apple entitlement).
- Geofences via `CLLocationManager` region monitoring (20 regions, Apple cap).
- SPKI certificate pinning to defend against user-installed enterprise / MitM CAs.
- Keychain-stored identity (`kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly`).
Install
# Xcode → File → Add Package Dependencies
https://github.com/sendoracloud/sdk-ios
# Or in Package.swift:
.package(url: "https://github.com/sendoracloud/sdk-ios", from: "3.9.0"),Quickstart
import SendoraCloud
// AppDelegate / @main entry
SendoraCloud.configure(apiKey: "pk_prod_...", projectId: "<uuid>")
SendoraCloud.consent.grant()
// Identify + track
SendoraCloud.identify(userId: "user_123", traits: ["email": "u@e.co"])
SendoraCloud.trackEvent("purchase", properties: ["amount": 29.99])
// Deep links — warm path (SceneDelegate)
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
guard let url = userActivity.webpageURL else { return }
SendoraCloud.links?.handleUniversalLink(url: url)
}
// Push token (UIApplicationDelegate)
func application(_ app: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken token: Data) {
let hex = token.map { String(format: "%02x", $0) }.joined()
SendoraCloud.push?.registerToken(hex, platform: .ios) { _ in }
}Security posture
- Secret-key refusal — `configure()` aborts on `sk_*`.
- HTTPS-only API client (except `localhost` in dev).
- SPKI cert pinning — opt-in via `pinnedSPKIHashes`.
- Identity tokens — `identify()` accepts an HMAC `identityToken` to block client-side spoofing.
- Keychain storage — `userId` + `deviceId` in `kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly`.
- Bundle-id gate — `links.create()` auto-forwards `Bundle.main.bundleIdentifier`; backend rejects leaked key + wrong bundle.