Documentation
iOS (Swift)
Add the SDK, configure it, handle ATT properly, bind purchases, forward universal links.
Requirements
- The package ships its own privacy manifest (
PrivacyInfo.xcprivacy) with the required-reason API declarations, so App Store Connect's ITMS-91053 check passes without work on your side. NSUserTrackingUsageDescriptioninInfo.plist. Without it the ATT prompt cannot appear at all, and without consent there is no advertising id.- Your App Privacy answers on App Store Connect should include the SDK's collection: device identifiers (IDFV, and IDFA when authorised), purchase history, product interaction and usage data, used for analytics and, if you push conversions back to ad platforms, third-party advertising. Confirm against your own app's actual usage.
1. Add the dependency
CocoaPods, pinned to a tag. The pod is served from git, not the CocoaPods trunk, so the source must be named:
pod 'RoasSensor', :git => 'https://github.com/rishabhrk2345/Roas-ios-SDK.git', :tag => '0.1.10'Or Swift Package Manager: add the same repository URL as a package and pin the same version.
2. Configure
The entry point is configure, not initialize -- the Android name does not compile here. Call it once at launch.
import RoasSensor
// AppDelegate.application(_:didFinishLaunchingWithOptions:), or your SwiftUI App's init
Roas.configure(
publicKey: "YOUR_PUBLIC_KEY",
requestTrackingAuthorization: false, // ask later, at a moment of your choosing (§3)
appSecret: Bundle.main.infoDictionary?["ROAS_APP_SECRET"] as? String,
baseUrl: "https://api.roassensor.com"
)baseUrl is printed by the panel and must be passed explicitly, for the same reason as on Android: the default is the production host, and a wrong one fails silently.
3. App Tracking Transparency
Left at its default, the ATT prompt fires about half a second after configure -- a cold-start system alert before the user has seen anything, which is the classic way to depress opt-in. Every denial costs the IDFA, and iOS never asks again.
Pass requestTrackingAuthorization: false and ask at a moment you choose, after onboarding:
Roas.requestTrackingAuthorization {
// called once the user has answered, either way
}SKAdNetwork registration happens once, at install, automatically. If you use SKAN conversion values, Roas.updateConversionValue(...) forwards them; it never lowers a value you have already set.
4. The app secret
An .xcconfig that is not committed, surfaced through Info.plist:
// Secrets.xcconfig (gitignored)
ROAS_APP_SECRET = your-secret
// Info.plist
<key>ROAS_APP_SECRET</key>
<string>$(ROAS_APP_SECRET)</string>nil, which is exactly right: absent must mean absent, never an empty string.5. Bind purchases to the install
Apple's notification names the transaction, not the buyer. The field that carries our visitor id through a purchase is StoreKit's appAccountToken. It must be a UUID; Roas.appAccountToken() derives one from the visitor id, and the server reverses it.
var options: Set<Product.PurchaseOption> = []
if let token = Roas.appAccountToken() { // nil before configure() -- never pass an empty token
options.insert(.appAccountToken(token))
}
let result = try await product.purchase(options: options)
// Optional: report it now instead of waiting for Apple's notification.
if case .success(.verified(let transaction)) = result {
Roas.verifyPurchase(transactionId: String(transaction.id))
await transaction.finish()
}verifyPurchase only ever names a transaction id; we fetch Apple's own signed copy of it and book what Apple says it was worth. It needs an In-App Purchase key on your account, and it dedupes against the notification that follows.
6. Universal links
// SwiftUI
.onOpenURL { url in Roas.handleDeepLink(url) }
// UIKit
func application(_ application: UIApplication, continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
if let url = userActivity.webpageURL { Roas.handleDeepLink(url) }
return true
}A first install from an ad is attributed through Apple Search Ads attribution or a deferred match; a tap by someone who already has the app arrives here.
7. Identity and funnel events
Roas.identify(email: user.email) // hashed on device
Roas.track(.beginCheckout, properties: [RoasProps.productId: "pro_yearly"])Same event vocabulary as Android, same rule: productId must equal the App Store product id so the funnel and the sale line up, and nothing sent here is ever revenue.
Check it worked
- Run the app on a device once.
Roas.setLogLevel(.debug)prints each delivery; a healthy launch showsfirst-open -> 201. - On the app's Overview tab, an install row appears with your
sdk_versionandsigned = true. - Before submitting: a Release archive contains
RoasSensor.bundle/PrivacyInfo.xcprivacy, and Xcode Organizer's Privacy Report lists it.

