Skip to content
Sendora Cloud
Create account
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.

Related