Nitx Publisher SDK
React Native SDK
TypeScript bridge over the native Android and iOS SDKs, with banner and native ad components.
@nitx/publisher-react-native is the React Native bridge of the Nitx Publisher SDK (Protocol §10, v1.2). It is a bridge only: every call goes through the platform channel to the native
Android SDK (io.nitx:publisher, Kotlin) or iOS SDK (NitxPublisher, Swift), which hold all ad
logic, normalisation, hashing and storage. JavaScript carries values and renders nothing itself.
- TypeScript, React Native 0.75 or newer, old-architecture native modules and view managers (they run unchanged under the New Architecture interop layer; Turbo modules and Fabric components are not required).
- Pinned native SDK: 1.0.0 on both platforms.
context.sdkreports both versions, for examplern-1.0.0/android-1.0.0andrn-1.0.0/ios-1.0.0(Protocol §10.7).
Install
Autolinking registers the native module and the two view managers through react-native.config.js
(NitxPackage on Android, the NitxPublisherReactNative pod on iOS). No manual linking.
Android
Nothing to configure for a published app. The bridge's android/build.gradle depends on
io.nitx:publisher:1.0.0; the coordinate is the same on Maven Central once published. Until then
it comes from Maven local (./gradlew :nitx-publisher:publishToMavenLocal in the Android SDK
repository) and the app's root android/build.gradle must let every project see it, because Gradle
resolves transitive dependencies with the consuming project's repositories:
Requirements inherited from the native SDK: minSdk 24, Kotlin 1.9 or newer, the INTERNET
permission (declared by the SDK). Local http backends need android:usesCleartextTraffic="true"
on the application element of the app only.
iOS
The pod NitxPublisherReactNative depends on NitxPublisher ~> 1.0.0 and iOS 15.0 or newer, so
the app's Podfile needs platform :ios, '15.0' (the React Native template default is lower).
While the NitxPublisher pod is not published, point the Podfile at a checkout of the iOS SDK:
The SDK ships PrivacyInfo.xcprivacy in its resource bundle. Clicks open in
SFSafariViewController; the IDFA is read only after the app's own App Tracking Transparency prompt.
Start
Call Nitx.start once, early (module scope of your root component or the app entry file). The
native SDK ignores a second call.
A mobile source has one code per platform; pick it with Platform.OS. The SDK loads
GET /api/ad-mobiles/show/{code}, warns when the registered bundle_id differs from the running
package or bundle identifier, and activates the source once while it is pending_verification.
Formats
Slot kinds come from the slot's format_type in the dashboard: banner_320x50, banner_300x250,
banner_adaptive, interstitial, app_open, native, rewarded (v2).
Banner
The native view sizes itself from the slot kind and reports that size to JavaScript through a
native event, so the component takes 320x50 or 300x250 dp for the fixed kinds and, for
banner_adaptive, stretches to its wrapper's width (measured with onLayout and handed to the
native view as the available width) with the height the SDK picks for that width. Until an ad
renders, and after a failure, the component is 0 dp high. style applies to the wrapper; use it
for alignment and margins rather than for a size. Image, video (muted, looping) and html creatives
are rendered natively; html uses a WebView.
Interstitial
load rejects with { code, message } (no_fill, network, not_started, render,
unavailable, invalid) when nothing is ready; failed events cover failures while showing.
Each id shows at most once and leaves the native registry after dismissed;
NitxInterstitial.destroy(id) drops one that will not be shown. The full-screen view shows a close
control after at most 5 seconds and when a video ends.
App open
Native
The SDK supplies assets only. The app renders them with its own components inside a
NitxNativeAdView carrying the ad id, and destroys the ad when the row leaves for good.
How the container works: NitxNativeAdView is a native view group (a ReactViewGroup subclass on
Android, an RCTView subclass on iOS), so React Native lays out its children and every View
prop applies. Once it is attached to a window with an adId, the native side looks the id up in
its registry and calls the SDK's NitxNativeAd.registerView(container, [container]): the SDK
records the impression, observes the container for viewability (50 percent visible for 1 second)
and opens click_url when the container is tapped. The whole container is clickable; there is no
clickable prop. On Android the container intercepts the native touch stream for a registered
clickable ad (React Native's own touch handling happens at the root view and is unaffected); on iOS
the SDK's tap recognizer does not cancel touches. NitxNativeAd.addListener('impression' | 'viewable' | 'clicked', ...) reports the interaction events (viewable is Android only; the iOS
SDK delegate has no viewable callback). With today's backend a native ad is a path-only creative:
headline is the ad name and image (or video) is the path.
Rewarded
NitxRewarded.load(slot) exists so apps can wire it; in v1 it rejects with code unavailable
("Rewarded ads are not available in v1") and show resolves false.
Consent and identify
JavaScript only validates and shapes the input (shapeTraits is exported for tests): wrong types
and unknown fields throw a TypeError, null becomes a clear entry. Normalisation (email
lowercased, phone to E.164, gender to m, f, other, birth year or age, city and country),
SHA-256 hashing of email and phone, the 20-trait limit and the under-16 rule all run in the native
SDK; raw values are never stored, logged or sent. The profile is persisted only once consent is
true; without consent only the visitor id travels.
Versioning
The bridge pins one native version per platform (android/build.gradle and the podspec). The
native modules pass the label rn-<bridge version> to the SDK's NitxOptions.bridge, and the SDK
reports context.sdk as rn-1.0.0/android-1.0.0 or rn-1.0.0/ios-1.0.0 in every POST ads
request. Nitx.versions().sdk and Nitx.state().sdk return the same string. A jest test checks
that package.json, the Kotlin and the Swift label agree.
The sections below are for working on the SDK itself: running it locally, testing and releasing. You don't need them to integrate.
Example app
example/ is a plain React Native 0.75 app that depends on the package through a local path. Its
single screen shows a 320x50 banner, a 300x250 banner, a feed with a native ad every third row
rendered by the app's own card inside NitxNativeAdView, interstitial and app open buttons, a
consent switch, identify inputs, reset and the Nitx.state() readout. It starts the SDK with
SDK-AM-DEMOA on Android and SDK-AM-DEMOI on iOS, API http://localhost:8001, debug: true,
and uses the slots SLOT-A-* / SLOT-I-* (BAN50, MREC, NATIVE, INTER, OPEN).
Build notes: the example's gradle wrapper is 8.10.2 with validateDistributionUrl=false, the
Android SDK is resolved from Maven local, and the iOS deployment target is 15.0.
Development
Package layout: src/ (TypeScript surface), android/ (Kotlin: NitxModule,
NitxBannerViewManager, NitxNativeAdViewManager, NitxPackage), ios/ (Swift modules with
ObjC RCT_EXTERN bridges), NitxPublisherReactNative.podspec, react-native.config.js,
example/.