Nitx Publisher SDK
Android SDK
Native Kotlin library for banner, interstitial, app open and native ads.
Native Android implementation of the Nitx Publisher SDK (Protocol §10, v1.2).
Kotlin, minSdk 24, no third-party networking or image libraries. The sample module shows
every format in a plain Activity.
Modules:
nitx-publisher: the library (io.nitx.publisher).sample: a demo app (com.nitx.publisher.sample).
Install
The library depends only on the Kotlin stdlib, kotlinx-coroutines-android, androidx.annotation,
androidx.core and androidx.browser (Chrome Custom Tabs). JSON is parsed with org.json.
Images are loaded with HttpURLConnection and BitmapFactory; videos play in VideoView.
Start
Call Nitx.start once, ideally from Application.onCreate:
NitxOptions: api (base URL override, default https://api.nitx.app), debug (logcat tag
Nitx), personalization (default true; false means no storage, no visitor block, and
consent, identify, reset are no-ops), testMode (reserved for v2), bridge (label set by
the React Native and Flutter bridges, for example rn-1.0.0; context.sdk then reports
rn-1.0.0/android-1.0.0 as Protocol §10.7 asks; apps using the SDK directly leave it null).
On start the SDK loads GET /api/ad-mobiles/show/{code}, compares the registered bundle_id
with the app's package name (a mismatch logs a warning and never blocks), and calls
GET /api/ad-mobiles/init/{code} once per process only while the source is
pending_verification. Every public call is safe on the main thread and never throws into the
app; failures are logged in debug mode only.
Nitx.state() returns a snapshot (mode, counters, consent, visitor id, hashed profile) for
debugging and tests; toString() prints it as JSON.
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 view sizes itself from the slot kind (320x50 dp, 300x250 dp, or full width and 50 to 90 dp
for banner_adaptive) unless the layout gives exact dimensions. Image, video (muted, looping)
and html creatives are rendered natively; html uses a WebView.
Interstitial
The full-screen activity shows a close control after at most 5 seconds and when a video ends.
App open
Foreground detection uses ActivityLifecycleCallbacks; no lifecycle library is required.
Native
The SDK supplies assets only; the app renders them with its own layout and registers the view.
With today's backend a native ad is a path-only creative: headline is the ad name and image
(or video for mp4 and webm) is the path. Structured assets are passed through when present.
Rewarded
NitxRewarded.load(context, slot, callback) exists so apps can wire it; in v1 it fails with
"Rewarded ads are not available in v1" and show returns false.
Consent and identify
Normalisation runs on the device: email trimmed and lowercased, phone reduced to E.164 (numbers
without a country code are dropped), gender mapped to m, f, other, birth year 1900 to the
current year (or derived from age), city and country lowercased and cut at 64 characters,
at most 20 traits with keys [a-z0-9_]{1,32}. Email and phone are hashed with SHA-256 at once;
raw values are never stored, logged or sent. Calls implying an age under 16 are discarded.
The profile is persisted only once consent is true; without consent only the visitor id travels.
Storage (SharedPreferences file nitx): nitx.visitor_id, nitx.consent, nitx.profile
(hashes only), nitx.app_open_last_shown. The advertising id is read at start and after consent
changes, held in memory only, and sent in context.ad_id only with consent.
Serving
Today creatives come from GET /api/ad-slots/show/{code} per slot: ads with a null path are
ignored, filler_content = static shows the first ad, otherwise one is picked at random. The
creative type is the ad's creative field when present, else by path extension (mp4 and webm
are video, everything else image). Clicks open click_url in Chrome Custom Tabs (falling back
to ACTION_VIEW); without click_url the creative is not clickable.
When the config response carries the sdk block, the SDK switches to POST {ads_endpoint} with
the app context block of Protocol §10.4, batches impression and viewable events every 2 seconds
(and on background) to {events_endpoint}, and posts {forget_endpoint} on reset. Paths that
are not relative to the API base are ignored; a 404, 405 or 501 from the POST falls back to GET
for the rest of the process.
Viewability: a banner or native ad is viewable after at least 50 percent of the view was visible for 1 second; interstitial and app-open ads are viewable when shown.
Permissions and Play data safety
The library manifest declares:
android.permission.INTERNETcom.google.android.gms.permission.AD_ID(remove it withtools:node="remove"if your app must not use the advertising id)
Play Console data safety entries for an app that ships the SDK:
Data is encrypted in transit (https in production). Users can request deletion through the app's
Nitx.reset() or Nitx support. The equivalent of Apple's PrivacyInfo.xcprivacy on Android is
this table plus the AD_ID permission declaration; there is no manifest file to ship.
ProGuard and R8
consumer-rules.pro ships with the library and is applied automatically: it keeps the public
API and the reflectively loaded AdvertisingIdClient. No app-side rules are needed.
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
The sample talks to a local backend on http://localhost:8001 and expects creative files on
http://localhost:4300. On an emulator, forward both ports from the host first:
The sample starts the SDK with source SDK-AM-DEMOA, debug on, and uses the slots
SLOT-A-BAN50, SLOT-A-MREC, SLOT-A-NATIVE, SLOT-A-INTER and SLOT-A-OPEN.
Cleartext http is enabled in the sample manifest only (android:usesCleartextTraffic="true").
Unit tests (nitx-publisher/src/test) run on the JVM with JUnit 4 and an in-memory HTTP fake;
fixtures under src/test/resources/fixtures are real backend responses.