Nitx Publisher SDK
Flutter SDK
Dart plugin over the native SDKs, with banner widgets and native ad views.
nitx_publisher is the Flutter bridge over the Nitx Publisher SDKs for Android (io.nitx:publisher, Kotlin) and iOS (NitxPublisher, Swift). It exposes the public API of Protocol §10.5 and renders nothing itself: every call crosses a platform channel to the native SDK, which owns the ad logic, hashing, storage, creative rendering, viewability and click handling (Protocol §10.7). Dart holds no ad state beyond handle ids and the last event.
- Flutter 3.22+, Dart 3.13+. Android minSdk 24, iOS 15.
- Native versions are pinned by the bridge: 1.0.0 of both SDKs.
context.sdkon the wire readsflutter-1.0.0/android-1.0.0orflutter-1.0.0/ios-1.0.0.
Install
Until the package is on pub.dev, depend on the git repository:
Android
The plugin depends on io.nitx:publisher:1.0.0. Until the public Maven repository is live, the artifact comes from your local Maven repository (~/.m2): clone nitx-publisher-sdk-android and run ./gradlew :nitx-publisher:publishToMavenLocal once. The plugin's android/build.gradle.kts already lists mavenLocal(); the example's android/settings.gradle.kts does too. The public coordinate will be the same, so nothing changes in your app when Maven publishing lands.
The native SDK's manifest adds INTERNET, the AD_ID permission (remove it with tools:node="remove" if you never want the advertising id) and the full-screen ad activity. Clicks open Chrome Custom Tabs.
iOS
The plugin podspec depends on the NitxPublisher pod (~> 1.0). While the pod is not yet in a spec repository, point your ios/Podfile at a checkout of nitx-publisher-sdk-ios:
Set IPHONEOS_DEPLOYMENT_TARGET to 15.0 in the Runner project. The native SDK ships its privacy manifest; clicks open SFSafariViewController. The plugin uses CocoaPods (no Swift Package Manager manifest) because the native dependency is consumed as a pod.
Start
Call Nitx.start once, before runApp, with the mobile source code from the publisher dashboard (SDK-AM-XXXXX). Options mirror the native NitxOptions; the bridge label is added for you.
NitxState is the union of both native snapshots; fields only one platform tracks (for example impressions, clicks, bundleIdMatches) are null on the other. state.raw holds the untouched map.
Consent and identify
Formats
Every handle exposes a Stream<NitxAdEvent>; an event has a type (loaded, failed, shown, impression, viewable, clicked, dismissed) and, for failed, an error with a code from NitxErrorCode (no_fill, network, not_started, unavailable, render, invalid, not_ready) and a message. Futures that fail natively throw NitxException.
Banner (banner_320x50, banner_300x250, banner_adaptive)
NitxBanner wraps the native NitxBannerView in a platform view. The native view loads when attached, and once the creative is rendered it measures itself from the slot kind and sends a size event; the widget resizes to it. Adaptive banners need the layout width: the widget passes the width its LayoutBuilder gives it and the native side picks the height (50 to 90). Before the size arrives the widget reserves placeholderHeight (default 50); after a failure it collapses to zero height unless collapseOnFailure: false.
Interstitial (interstitial)
App open (app_open)
showIfAvailable(minInterval: ...) applies the frequency rule on iOS; the Android SDK applies it to auto show only, so a manual show on Android always presents.
Native (native) with NitxNativeAdView
The app renders the assets with its own widgets. NitxNativeAd.load returns the assets (any field may be null); wrap your rendering in NitxNativeAdView so the SDK tracks viewability and clicks.
The transparent-view design
The native SDKs track viewability and clicks on native views (registerView(container, clickableViews)), and Flutter widgets are not native views. NitxNativeAdView therefore pairs your child with a transparent native platform view of exactly the same bounds: a Stack with StackFit.passthrough (your child lays out exactly as it would without the wrapper) and a Positioned.fill platform view. The plugin registers that view with the SDK, so the SDK's viewability tracker (50 percent visible for one second) observes the same rectangle the user sees, including while the row scrolls through a list, and the impression is recorded when the view is registered.
Clicks differ per platform because of what each native SDK exposes:
- Android: the overlay sits underneath the child. A
GestureDetectoraround the child forwards the tap through the method channel (nativeClick), and the plugin callsView.performClick()on the overlay, which runs the SDK's own click listener (records the click, opens Custom Tabs, firesclicked). Your child stays fully interactive. - iOS: the same design. The overlay sits underneath the child and is registered for viewability only; the
GestureDetectorforwards the tap throughnativeClickand the plugin callsNitxNativeAd.performClick()(iOS SDK 1.0.0 or later from commit 7d89533), which records the click, opensSFSafariViewControllerand firesclicked. The child keeps all of its own gestures.
The overlay is created when the widget is built; if the ad finishes loading later, the plugin registers the overlay as soon as both exist.
Rewarded (rewarded, v2)
NitxRewarded.load(slot) returns a handle whose stream reports failed with code unavailable in v1; isReady is false and show() returns false. The shape is stable so apps can wire it today.
Version string
The bridge pins the native SDK versions and passes bridge: 'flutter-1.0.0' to the native NitxOptions. The native SDK prefixes the label to its own tag, so context.sdk in every ad and event request reads flutter-1.0.0/android-1.0.0 or flutter-1.0.0/ios-1.0.0, and Nitx.state() returns the same value in sdk. Nitx.version is the bridge version.
The sections below are for working on the SDK itself: running it locally, testing and releasing. You don't need them to integrate.
Example
example/ is a one-screen app against the local stack: a 320x50 banner (SLOT-A-BAN50 on Android, SLOT-I-BAN50 on iOS), 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 fields, reset and a state readout. Codes SDK-AM-DEMOA / SDK-AM-DEMOI, API http://localhost:8001, debug on.
The example allows cleartext HTTP (usesCleartextTraffic, NSAllowsArbitraryLoads) for the local stack only.
Tests
flutter test runs the Dart unit tests: method channel argument shapes for start, consent and identify, state parsing, native error mapping, and event stream mapping for interstitial, app open and native handles, against a mocked channel.