
Revenue Sharing iOS SDK
Passive StoreKit 2 monitoring SDK for reliable revenue attribution and fraud prevention.
Links
Quick facts
• Role: iOS SDK engineer (hired to harden StoreKit monitoring + reporting)
• Timeframe: Short engagement + follow-up scope planned, then paused by client
• Platform: iOS 15+ (Swift Package), plus a SwiftUI example app
• Status: Paused (client postponed further SDK work)
• Team: Small founder-led team (me + founder)
Summary
An iOS SDK for referral revenue attribution. Apps integrate it once, and it monitors StoreKit purchases to report transactions to a backend for verification and commission splitting. I joined to improve reliability, reduce duplicate reporting, and align expectations with real StoreKit behavior.
Key highlights:
• Passive StoreKit 2 listener with automatic reporting (no “report purchase” calls from host app)
• Stronger deduplication and bounded retries to prevent backend spam
• Clear documentation of unavoidable platform limits (especially for consumables)
Problem
• SDK had to detect purchases even if the host app “forgets” to report them. Anti-fraud requirement.
• StoreKit 2 doesn’t provide a true always-on callback for same-device purchases independent of purchase handling.
• Backend was getting spammed from replays and retry loops, especially on app launch.
Solution
I implemented a two-path capture strategy: Transaction.updates for replay/out-of-app cases plus periodic Transaction.currentEntitlements polling for near-real-time detection of subscriptions and non-consumables. I also tightened reporting to be idempotent on-device and bounded on failures, and clarified what must be enforced server-side.
• Added device-side dedupe + max retry attempts per transaction, and recommended backend idempotency
Architecture
• Swift Package entry point (AppRevShareSDK) wrapping APIClient + StoreKitManager
• StoreKitManager runs a single listener, consumes Transaction.updates and currentEntitlements polling
• Verified transactions only (StoreKit VerificationResult gating)
• Local persistence in UserDefaults for devKey, identifiers, processed transaction IDs, attempt counters
• Thread-safe dedupe helpers (locks around processed IDs / attempt counts)
• Network layer with typed request/response models for register, update identifier, report payment
• Opt-in logger with header masking and structured request/response/error logs
• SwiftUI example app to validate integration: init, register, update identifier, purchase trigger
Hard problems solved
• Identified and corrected a key assumption: Transaction.updates is not a universal “every purchase” stream for same-device purchases
• Designed a practical capture strategy that improves reliability without heavy CPU/RAM cost (updates + entitlements polling)
• Reduced backend spam by preventing duplicate re-reporting on replayed transactions and by adding bounded retries
• Implemented safe on-device idempotency while documenting its limits (reinstall wipes storage; backend must be idempotent)
• Worked within a backend constraint where registration could disable the SDK entirely (success=false) and ensured zero calls after disable
• Validated flows despite referral-gated registration and server-side transaction verification rejecting mismatched sandbox data
Impact / Results
• Improved purchase detection reliability for subscriptions and non-consumables while documenting consumable limitations
• Prevented repeated reporting loops and reduced noisy traffic patterns during app boot/replay scenarios
• Delivered changes via a feature branch and proof via recorded demos against a test app
Tech stack
• iOS: Swift, StoreKit 2, SwiftUI (example app)
• Architecture: Swift Package, passive listener, on-device idempotency + retry control
• Backend/Infra: REST API contract (register/update/report), server-side App Store verification (client-owned)
• Tooling: Xcode, XCTest, structured logging utilities
