Nitx Publisher SDK
iOS SDK
Swift package with native rendering, App Tracking Transparency support and a privacy manifest.
Swift Package NitxPublisher, the iOS implementation of the Nitx Publisher SDK (Protocol §10 of the web SDK repository). It serves banner, interstitial, app open and native ads from a Nitx mobile source, with the same visitor, consent, identify and hashing rules as the web SDK 1.2.
- iOS 15+, Swift 5.9, no third-party dependencies (Foundation, UIKit, CryptoKit, AVFoundation, SafariServices, AdSupport, AppTrackingTransparency).
- Image and video creatives render natively; clicks open the backend click URL in
SFSafariViewController. - Every public call is safe from any thread and never throws into the app. Callbacks arrive on the main thread.
Install (Swift Package Manager)
In Xcode: File > Add Package Dependencies, enter the repository URL and add the NitxPublisher product to your app target. Or in Package.swift:
Start
Call Nitx.start once, as early as possible (app delegate or @main App init). The code is the mobile source code shown in the publisher dashboard (SDK-AM-XXXXX).
The SDK loads GET /api/ad-mobiles/show/{code}, warns when the source's bundle_id differs from the app's bundle identifier, and calls GET /api/ad-mobiles/init/{code} once per process while the source is pending_verification.
Formats
Banner (banner_320x50, banner_300x250, banner_adaptive)
UIKit: NitxBannerView loads when it enters a window, load() reloads. Give it the slot's size (adaptive banners take the full width and a height of 50 to 90 points).
SwiftUI:
Interstitial (interstitial)
The ad is preloaded (video creatives are downloaded first), presented full screen, and gets a close control after at most 5 seconds and on video end. Shown counts as both impression and viewable.
App open (app_open)
The last show time is kept in UserDefaults under nitx.app_open_last_shown.
Native (native)
The SDK supplies assets; the app owns the layout. Register the container so the SDK can track viewability and attach click handling to the views you choose.
Until the backend ships structured assets, a path-only ad arrives as headline = ad name and image = creative path.
Hosts that draw the ad outside UIKit (Flutter, game engines) can register a transparent view behind their rendering for viewability and forward their own tap with ad.performClick(). It records the click and opens the destination exactly like a tap on a registered clickable view, and does nothing before registerView, after destroy(), or when the ad has no click URL.
SwiftUI: NitxNativeAdLoader is an ObservableObject with load(slot:), ad, error and isLoading. Put .background(NitxNativeAdRegistration(ad: ad)) on the view that renders the assets so the SDK tracks it.
Rewarded (rewarded)
NitxRewarded.load(slot:) exists so the API is stable, and always fails with "Rewarded ads are not available in v1".
Consent and identify
The SDK never reads your forms, cookies or contacts. Identity enters only through identify, and identity fields leave the device only after consent(true).
Rules: email trimmed and lowercased, phone reduced to E.164 (+ and 8 to 15 digits, numbers without a country code are dropped), gender m, f or other, birth year 1900 to the current year (or derived from age), city and country lowercased and cut at 64 characters, traits at most 20 keys of [a-z0-9_]{1,32}. Calls implying an age under 16 are discarded.
Storage (UserDefaults, prefix nitx.): visitor_id, consent, profile (hashes only, persisted only with a consent record and discarded on load without one), app_open_last_shown.
Request mode
Today the SDK reads creatives with GET /api/ad-slots/show/{code} per slot and sends no tracking (no impression ids exist). When the config response carries the sdk block with relative ads_endpoint, events_endpoint and forget_endpoint paths, the SDK switches to POST ads with the visitor and app context blocks, queues impression and viewable events (batched every 2 seconds, flushed when the app resigns active or enters the background), and sends forget on reset. Off-origin paths are ignored, and a 404, 405 or 501 from the POST endpoint falls back to GET for the rest of the process. NitxOptions.ads (.auto, .get, .post) is a developer override.
The context block contains the bundle id, app version and build, the screen name, OS name and version, phone or tablet, language, time zone, screen size and the SDK tag ios-1.0.0. The SDK never sends the IP address, user agent or location.
App Tracking Transparency
The SDK never shows the ATT prompt. It reads ATTrackingManager.trackingAuthorizationStatus at start and after consent changes, and includes the IDFA in context.ad_id only when the status is .authorized. If you want the IDFA on the wire, request authorization yourself (with NSUserTrackingUsageDescription in your Info.plist) before Nitx.start or before the first ad request. Without it the block is null and everything still works.
Privacy manifest
The package ships Sources/NitxPublisher/PrivacyInfo.xcprivacy, declaring: email address and phone number (hashed, optional, with consent, linked to the user, advertising), coarse location (derived from the IP on the server), device id (optional, advertising), product interaction (ad impressions and clicks), and the UserDefaults required-reason API (CA92.1). Tracking is declared as false and no tracking domains are listed. Merge these entries into your own app privacy answers on App Store Connect.
The sections below are for working on the SDK itself: running it locally, testing and releasing. You don't need them to integrate.
Local testing against the Mac backend
The sample app in Sample/ is generated with XcodeGen:
It starts with code SDK-AM-DEMOI, API http://127.0.0.1:8001 and debug: true, and shows a 320x50 banner, a 300x250 rectangle, a feed with a native ad every third row, interstitial and app open buttons, a consent switch, identify fields, a reset button and the Nitx.state() output. The simulator reaches the Mac's localhost directly, so run the backend on port 8001 and the creative server on port 4300 as for the web SDK. NSAllowsArbitraryLoads is on in the sample only.
Launch argument -nitxAutoShowInterstitial 1 makes the sample show the interstitial 3 seconds after launch (handy for automated screenshots).
Logs: xcrun simctl spawn booted log stream --predicate 'subsystem == "io.nitx.publisher"'.
Run the package tests on a simulator:
Note: Xcode needs an iOS simulator runtime matching its SDK major version installed (Xcode > Settings > Components, or xcodebuild -downloadPlatform iOS), otherwise it reports "iOS X is not installed" and refuses every simulator destination. Without it you can still compile for the simulator with swift build --triple x86_64-apple-ios15.0-simulator --sdk $(xcrun --sdk iphonesimulator --show-sdk-path) (use arm64-apple-ios15.0-simulator on Apple silicon).
Deviations from Protocol §10 in v1
htmlcreatives are not rendered (no WebKit dependency); they fail withcreativeFailed.- Video creatives are downloaded to the caches directory before playback instead of streamed.
- Rewarded ads are a stub.