Repository navigation
App Banner
App Banner is a data-only API. The OmniSegment SDK selects eligible content and returns it to the host application. The host application owns parsing, rendering, user interaction, and removal of the native UI.
- OmniSegment Android SDK
1.1.0or later. - Android
minSdk 24or later. - An OmniSegment API key and TID.
- A
pageKeyandbannerKeyconfigured with OmniSegment. - An agreed JSON content schema between OmniSegment and the host application.
The 1.1.0 dependency graph includes androidx.webkit:webkit:1.16.0. Kotlin 1.8 consumers may encounter incompatible Kotlin metadata from transitive dependencies; validate the consumer project's dependency resolution before release.
Follow the installation guide, then initialize the SDK once from Application.onCreate():
import android.app.Application
import com.bebittech.omnisegment.OmniSegment
class App : Application() {
override fun onCreate() {
super.onCreate()
OmniSegment.initialize(this, "API_KEY", "TID")
}
}pageKey identifies the current app screen. bannerKey identifies one banner slot on that screen. Both values must be non-empty and must match the values configured in OmniSegment.
The callback is asynchronous and runs on the Android main thread. Keep the returned OSGBannerRequest while the request is pending, and cancel it when the screen no longer needs the result.
import com.bebittech.omnisegment.OSGBannerContentStatus
import com.bebittech.omnisegment.OSGBannerRequest
import com.bebittech.omnisegment.OmniSegment
private var bannerRequest: OSGBannerRequest? = null
fun loadBanner() {
bannerRequest = OmniSegment.requestBannerContent("home", "top") { result ->
bannerRequest = null
when (result.status) {
OSGBannerContentStatus.CONTENT -> {
val delivery = result.delivery ?: return@requestBannerContent
val contentJSON = delivery.contentJSON
// Parse contentJSON using the schema agreed with OmniSegment,
// then render the banner in the host application.
renderBanner(contentJSON)
// Call from the host application's actual UI lifecycle:
// delivery.reportDisplayed() after the banner becomes visible.
// delivery.reportClicked() from the banner click handler.
// delivery.reportClosed() from the banner close handler.
}
OSGBannerContentStatus.NO_CONTENT -> removeBannerIfPresent()
OSGBannerContentStatus.FAILED -> {
handleBannerError(result.error?.code)
}
}
}
}
fun stopLoadingBanner() {
bannerRequest?.cancel()
bannerRequest = null
}Call stopLoadingBanner() from the screen's teardown lifecycle, such as onStop() or onDestroyView(), if a request is still pending. Do not cancel immediately after creating the request.
import com.bebittech.omnisegment.OSGBannerContentDelivery;
import com.bebittech.omnisegment.OSGBannerContentStatus;
import com.bebittech.omnisegment.OSGBannerRequest;
import com.bebittech.omnisegment.OmniSegment;
private OSGBannerRequest bannerRequest;
private void loadBanner() {
bannerRequest = OmniSegment.requestBannerContent("home", "top", result -> {
bannerRequest = null;
if (result.getStatus() == OSGBannerContentStatus.CONTENT) {
OSGBannerContentDelivery delivery = result.getDelivery();
if (delivery == null) {
return;
}
String contentJSON = delivery.getContentJSON();
renderBanner(contentJSON);
// Call from the host application's actual UI lifecycle:
// delivery.reportDisplayed() after the banner becomes visible.
// delivery.reportClicked() from the banner click handler.
// delivery.reportClosed() from the banner close handler.
} else if (result.getStatus() == OSGBannerContentStatus.NO_CONTENT) {
removeBannerIfPresent();
} else {
handleBannerError(result.getError() == null ? null : result.getError().getCode());
}
});
}
private void stopLoadingBanner() {
if (bannerRequest != null) {
bannerRequest.cancel();
bannerRequest = null;
}
}renderBanner, removeBannerIfPresent, and handleBannerError are placeholders for host-application code; they are not SDK methods.
| Status | delivery |
error |
Meaning |
|---|---|---|---|
CONTENT |
Present | null |
Eligible content was selected. Parse and render delivery.contentJSON. |
NO_CONTENT |
null |
null |
No eligible content is available. This is not an error. |
FAILED |
null |
Present | The request failed. Inspect error.code. |
App Banner obtains the selected banner from /ma_cms/get-web-popup/, but the SDK does not return the complete API response. delivery.contentJSON contains only this value:
response.PAYLOAD.data.options.content
For example, when /get-web-popup/ returns a WebBannerEmbed whose options.content is a card, contentJSON has the following shape:
{
"card": {
"image": {
"enabled": false,
"customRatio": {}
},
"title": {
"text": "Banner title",
"enabled": false
},
"device": "mobile",
"ctaButton": {
"text": "Learn more",
"color": "#10A1B5",
"style": "text",
"enabled": true,
"fontSize": 14,
"textAlign": "left"
},
"image_src": null,
"appearance": {
"topMargin": 16,
"bottomMargin": 16,
"backgroundColor": "#f5f9fb",
"borderRadiusTopLeft": 12,
"borderRadiusTopRight": 12,
"borderRadiusBottomLeft": 12,
"borderRadiusBottomRight": 12
},
"closeButton": {
"size": 20,
"color": "#C8C8C8",
"enabled": true
},
"description": {
"text": "Banner description",
"color": "#262626",
"enabled": true,
"fontSize": 14,
"textAlign": "left"
},
"redirectUrl": "https://example.com/landing"
},
"type": "card"
}redirectUrl is a plain string. It is not a Markdown link.
| Path | Meaning |
|---|---|
type |
Content type. The current card content uses card. |
card.image |
Media enablement and ratio settings. When enabled is false, do not render an image or video. |
card.image_src |
Preferred media-source array when configured; otherwise it may be null. A source can represent an image or video. |
card.visual_src |
Compatibility media-source array. The test app uses it as a fallback when image_src has no valid URL. |
card.title |
Optional title content and text style. Check enabled before rendering. |
card.description |
Optional description content and text style. Check enabled before rendering. |
card.ctaButton |
Optional CTA content and style. Check enabled before rendering. |
card.appearance |
Background, margins, border radii, and other card appearance values. |
card.closeButton |
Close-button visibility and style. Check enabled before rendering. |
card.redirectUrl |
External URL or application-defined internal destination handled by the host application. |
Fields can be omitted when a block is disabled or not configured, and new fields may be added without an SDK release. Parse defensively: check type, tolerate missing and unknown fields, and do not require the example above to be byte-for-byte identical.
Do not assume that a configured media source is always an image. Each entry in image_src or visual_src can contain a remote url and a media type.
Image source:
{
"image_src": [
{
"url": "https://cdn.example.com/banner.jpg",
"type": "image"
}
]
}Video source:
{
"image_src": [
{
"url": "https://cdn.example.com/banner.mp4",
"type": "video"
}
]
}The current Android test app parser selects the first image_src entry with a non-blank URL, then falls back to visual_src. It treats type: "video" case-insensitively as video and renders other or missing types as images. Its banner screen demonstrates image loading, muted looping video playback, playback-error handling, and stopping the video when the screen is destroyed.
Applications may use a different UI implementation, but should follow these data-handling rules:
- Hide the media block when
card.image.enabledisfalseor no valid media URL is available. - Use a video-capable player for
type: "video"; use an image loader for image or unspecified media types. - Handle image-load and video-playback failures without failing the rest of the banner.
- Stop and release video playback when the banner or screen is removed.
- Call
reportDisplayed()only after the rendered banner is actually visible, not merely after starting an asynchronous media load.
The following /get-web-popup/ fields are used internally and are not part of contentJSON: name, pageId, frequency, need_login, behaviorRecords, clientPlatformVariable, routers, template_uid, and other values outside options.content.
import org.json.JSONObject
val content = JSONObject(delivery.contentJSON)
when (content.optString("type")) {
"card" -> {
content.optJSONObject("card")?.let { card ->
// Render only the enabled blocks that the application supports.
}
}
else -> {
// Ignore or log unsupported future content types.
}
}| Method | Call timing |
|---|---|
reportDisplayed() |
After the rendered banner is actually visible to the user. |
reportClicked() |
From the host application's banner click handler. |
reportClosed() |
From the host application's banner close or dismiss handler. |
These methods are idempotent for each delivery. reportClicked() and reportClosed() also report displayed first if it has not already been reported. Receiving content alone does not report an impression.
| Error code | Meaning |
|---|---|
INVALID_ARGUMENT |
pageKey or bannerKey is missing or blank. |
NOT_INITIALIZED |
OmniSegment.initialize(...) has not completed. |
NETWORK |
The content request failed because of a network error. |
TIMED_OUT |
The request did not complete within 30 seconds. |
INVALID_CONTENT |
The selected content or tracking payload is malformed. |
INTERNAL |
The SDK or JavaScript bridge encountered an unexpected failure. |
- Each call creates an independent request. Concurrent requests are supported.
-
cancel()suppresses the callback only while the request is pending. It is safe to call more than once. - Keep the delivery associated with the UI rendered from that delivery.
- Do not report displayed before rendering succeeds and the banner is visible.
- Treat
NO_CONTENTas a normal empty state rather than a retryable error.