Skip to content

Nitx Publisher SDK

Flutter SDK

Dart plugin over the native SDKs, with banner widgets and native ad views.

Dart
nitx_publisher
Flutter 3.22+
Dart 3.13+
Android minSdk 24 · iOS 15
Updated Nov 1, 2026

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.sdk on the wire reads flutter-1.0.0/android-1.0.0 or flutter-1.0.0/ios-1.0.0.

Install

Until the package is on pub.dev, depend on the git repository:

YAML
dependencies:
  nitx_publisher:
    git:
      url: https://github.com/NitxTech/nitx-publisher-sdk-flutter.git
      ref: v1.0.0

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:

Ruby
platform :ios, '15.0'
target 'Runner' do
  use_frameworks!
  pod 'NitxPublisher', :path => '../../nitx-publisher-sdk-ios'   # or :git => 'https://github.com/NitxTech/nitx-publisher-sdk-ios.git', :tag => 'v1.0.0'
  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end

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.

Dart
import 'package:nitx_publisher/nitx_publisher.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Nitx.start('SDK-AM-XXXXX', options: const NitxOptions(
    api: 'https://api.nitx.app',   // base URL override
    debug: true,                   // logcat tag "Nitx" / unified log io.nitx.publisher
    personalization: true,         // false: no storage, no visitor block, consent/identify/reset are no-ops
  ));
  await Nitx.setScreen('Home');    // optional, sent as context.app.screen
  runApp(const MyApp());
}

final NitxState s = await Nitx.state();   // counters, mode, consent, visitor id, profile keys, s.sdk

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.

Dart
await Nitx.consent(true);                       // stores the consent record, allows identity on the wire
await Nitx.identify(const NitxTraits(
  email: 'ada@example.com',                     // hashed natively (SHA-256) at once, never stored raw
  phone: '+966 50 123 4567',
  gender: 'f',
  birthYear: 1990,
  country: 'SA',
  traits: <String, Object?>{'plan': 'pro'},
));
await Nitx.identify(const NitxTraits(clear: <String>['phone']));   // delete a stored field
await Nitx.reset();                              // forget the visitor, profile, consent and ad id

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.

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.

Dart
Center(
  child: NitxBanner(
    slot: 'SLOT-XXXXXX',
    onLoaded: () => debugPrint('loaded'),
    onFailed: (NitxError e) => debugPrint('failed $e'),
    onImpression: () {},
    onClicked: () {},
  ),
)

Interstitial (interstitial)

Dart
final NitxInterstitial ad = await NitxInterstitial.load('SLOT-XXXXXX');   // preload starts natively
ad.events.listen((NitxAdEvent e) => debugPrint('$e'));                    // loaded, failed, shown, clicked, dismissed
await ad.whenLoaded;                                                      // or check ad.isReady
final bool shown = await ad.show();                                       // over the current activity / root view controller
await ad.dispose();                                                       // after dismissed; load a new handle for the next show

App open (app_open)

Dart
NitxAppOpen.events.listen((NitxAdEvent e) => debugPrint('app open $e'));
await NitxAppOpen.load('SLOT-XXXXXX');
await NitxAppOpen.showIfAvailable();                                      // true when shown
await NitxAppOpen.enableAutoShow('SLOT-XXXXXX', const Duration(minutes: 15));   // on every foreground return, at most once per interval
await NitxAppOpen.disableAutoShow();

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.

Dart
final NitxNativeAd ad = await NitxNativeAd.load('SLOT-XXXXXX');   // throws NitxException on no fill
ad.events.listen((NitxAdEvent e) => debugPrint('native $e'));    // impression, viewable, clicked

NitxNativeAdView(
  ad: ad,
  child: Card(
    child: Column(children: <Widget>[
      Text(ad.assets.headline ?? 'Sponsored'),
      if (ad.assets.image != null) Image.network(ad.assets.image!),
      if (ad.assets.body != null) Text(ad.assets.body!),
      if (ad.isClickable) Text(ad.assets.cta ?? 'Learn more'),
    ]),
  ),
)

await ad.destroy();   // unregisters the native view when the row leaves the feed for good

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 GestureDetector around the child forwards the tap through the method channel (nativeClick), and the plugin calls View.performClick() on the overlay, which runs the SDK's own click listener (records the click, opens Custom Tabs, fires clicked). Your child stays fully interactive.
  • iOS: the same design. The overlay sits underneath the child and is registered for viewability only; the GestureDetector forwards the tap through nativeClick and the plugin calls NitxNativeAd.performClick() (iOS SDK 1.0.0 or later from commit 7d89533), which records the click, opens SFSafariViewController and fires clicked. 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.

Contributing

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.

Shell
# backend on 127.0.0.1:8001 and the creative server on :4300 (nitx-publisher-sdk/local/start-stack.sh)
cd example
adb reverse tcp:8001 tcp:8001 && adb reverse tcp:4300 tcp:4300
flutter run -d emulator-5554             # Android: logcat -s Nitx shows config and slot loads
flutter build ios --simulator --no-codesign   # iOS (pod install picks NitxPublisher from ../../../nitx-publisher-sdk-ios)

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.

Generated from README.md in NitxTech/nitx-publisher-sdk-flutter at 34e3311 · Nov 1, 2026