Adaptive DAI SDK – User Guide (Android TV / Fire TV)

This guide explains how to install and integrate Adaptive DAI SDK into your Android TV / Fire TV application using the public API surface.

1. Installation

1.1. Gradle setup (typical remote Maven usage)

In a typical setup you will consume the SDK as a binary AAR from a Maven repository:

dependencies {
    implementation "com.adaptivedai:adaptivedai:"
}

If you publish the SDK to an internal Maven repository, add it to the repositories section of your Gradle configuration as usual.

Note: In this repository, a local Maven flow is provided for development (publish-sdk-local.sh and local-maven-repo/). This is a development detail and not required for external consumers of the SDK.

1.2. Platform requirements

  • minSdk: 24
  • targetSdk / compileSdk: 35
  • Java: 17 (with core library desugaring enabled)

1.3. Example build.gradle for an app using Adaptive DAI SDK

Below is a minimal example of an app module build.gradle configured to use the SDK. Adjust package IDs, versioning and additional dependencies as needed for your project.

plugins {
    id 'com.android.application'
}

android {
    namespace 'com.example.myapp'           // your app package

    compileSdk 35

    defaultConfig {
        applicationId "com.example.myapp"
        minSdk 24
        targetSdk 35

        versionCode 1
        versionName "1.0"

        // Limit resources if desired
        // resConfigs "en", "ru"
    }

    buildTypes {
        debug {
            debuggable true
            minifyEnabled false
        }
        release {
            // You may enable minify here; the SDK ships with its own consumer rules
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    compileOptions {
        // Java 17 + desugaring for lower API levels
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
        coreLibraryDesugaringEnabled true
    }

    // If you use Kotlin, configure kotlinOptions.jvmTarget = "17" as usual

    buildFeatures {
        // no special features required by the SDK itself
        buildConfig true
    }

    // Packaging tweaks required when using libraries with multi-release JARs
    packaging {
        resources {
            // Required for Adaptive DAIS SDK: exclude Java 9 OSGi manifest from transitive dependencies
            // to avoid packaging/merge errors in Android builds.
            excludes += 'META-INF/versions/9/OSGI-INF/MANIFEST.MF'

            // Example: exclude other duplicate META-INF entries if they appear
            // excludes += 'META-INF/DEPENDENCIES'
        }
    }
}

dependencies {
    // Adaptive DAI SDK – main dependency
    implementation "com.adaptivedai:adaptivedai:"

    // Java 17 desugaring library (recommended when minSdk < 26)
    coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'

    // Your app UI dependencies (examples only – not required by the SDK itself)
    implementation 'androidx.appcompat:appcompat:1.7.1'
    implementation 'com.google.android.material:material:1.11.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
}

Key points:

  • The SDK pulls in Media3, IMA, Retrofit and other libraries as transitive dependencies – you do not need to declare them manually unless your app directly uses those APIs.
  • Enabling coreLibraryDesugaringEnabled true with desugar_jdk_libs is recommended when targeting API 24 while using Java 17.
  • The packaging { resources { excludes += 'META-INF/versions/9/OSGI-INF/MANIFEST.MF' } } block is required: one of the SDK’s transitive dependencies ships as a multi‑release JAR that includes a Java 9‑specific OSGi manifest. This resource is not needed on Android and can cause packaging/merge errors (duplicate or unsupported META‑INF entries), so it must be excluded from the final APK/AAB.
  • You can freely add additional dependencies (RecyclerView, Glide, Leanback, etc.) that your app needs; they do not affect the core Adaptive DAI SDK integration.

2. Core Concepts

Before integrating, it is important to understand the main public classes and interfaces.

2.1. MediaItem

Represents content metadata used by the SDK:

  • id – content identifier;
  • title – display title;
  • streamUrl – URL of the video stream (e.g. HLS);
  • catId – category identifier;
  • durationSec – duration in seconds;
  • macros – optional map of extra macro values that can be injected into ad/VMAP URLs.

You construct MediaItem instances and pass them to the SDK when starting playback. The macros map can be null if you do not need any custom macro substitutions.

2.2. AdaptiveDAISDK

The main SDK facade and singleton entry point:

  • holds global configuration and partner/distribution identifiers;
  • manages internal AdaptiveDAIPlayer instance;
  • exposes methods to:
    • initialize the SDK (initialize(VideoPlayerConfiguration)),
    • bind SDK to your UI (setupPlayer(...)),
    • control playback (playMedia(...), pause(), resume(), release()),
    • handle lifecycle (onActivityPaused(), onActivityResumed()).

Typical call order:

  1. AdaptiveDAISDK.getInstance(...)
  2. initialize(VideoPlayerConfiguration)
  3. setupPlayer(...)
  4. playMedia(...)
  5. onActivityPaused()/onActivityResumed()/release() from Activity.

2.3. AdaptiveDAILauncher

A convenience utility for minimal integration:

  • Init(Context, partnerId, distributionId, applicationName, exoFactory?, imaFactory?) – one‑time initialization.
  • playVideo(Context, MediaItem, boolean adsEnabled) – launches playback in a built‑in PlayerActivity from the SDK.
  • playVideo(Context, MediaItem, boolean adsEnabled, PlaybackListener listener) – same as above, but also registers a PlaybackListener

Use this when you want the fastest path to ad‑enabled playback with minimal custom UI integration.

2.4. PlaybackListener

Callback interface for tracking playback and ad state:

  • onPlaybackStarted() – content has started playing for the first time;
  • onPlaybackPaused() – content is paused (user/system);
  • onPlaybackResumed() – content resumed after a pause;
  • onPlaybackCompleted() – end of content reached;
  • onAdsStarted() – an ad break has started (including on‑pause ads);
  • onAdsFinished() – the current ad break has finished and content is resuming or has resumed;
  • onPlaybackError(String error) – an error occurred.

Passed to AdaptiveDAISDK.playMedia(MediaItem, PlaybackListener) in advanced integrations. Internally the SDK can fan‑out events to multiple listeners when AdaptiveDAIPlayer.addPlaybackListener(...) is used.

2.5. Configuration: VideoPlayerConfiguration and DefaultVideoPlayerConfiguration

VideoPlayerConfiguration defines how ads are configured:

  • whether ads are enabled;

AdaptiveDAISDK.DefaultVideoPlayerConfiguration is a public builder‑style implementation with common setters:

  • setAdsEnabled(boolean)

2.6. Factory adapters (advanced)

For advanced control over ExoPlayer and IMA you can implement and pass:

  • ExoPlayerFactoryAdapter – customize how ExoPlayer is built (track selection, buffering, renderers, etc.).
  • ImaSdkFactoryAdapter – customize how IMA SDK components are created.

These are optional and usually needed only in more complex integrations (see CustomExoDemo / FullDemo).

3. Quick Start – Minimal Integration with AdaptiveDAILauncher

This scenario is best illustrated by the SimpleDemo app. It assumes you are happy to use the SDK’s built‑in PlayerActivity and do not need a custom player UI.

3.1. One‑time SDK initialization

Call AdaptiveDAILauncher.Init(...) once, for example in your Application subclass or in the first Activity:

AdaptiveDAILauncher.Init(
    applicationContext,
    "1",          // partnerId
    "167",        // distributionId
    "DemoApp",    // application name
    null,         // optional ExoPlayerFactoryAdapter
    null          // optional ImaSdkFactoryAdapter
);

3.2. Creating a MediaItem

MediaItem mediaItem = new MediaItem(
    "https://example.com/video.m3u8", // streamUrl
    "Movie Title",                    // title
    "1",                              // id
    "456",                            // category id
    3600,                             // duration in seconds
    null                              // optional macros map (can be null)
);

3.3. Starting playback

From any Activity or Fragment:

AdaptiveDAILauncher.playVideo(
    this,          // Activity or Context
    mediaItem,     // MediaItem for playing
    true           // adsEnabled
);

The SDK will:

  • open its own PlayerActivity;
  • initialize ExoPlayer and IMA;
  • play the specified content with the configured ad schedule.

Lifecycle and UI management are handled internally by the SDK.

4. Standard Integration with AdaptiveDAISDK

When you need more control over the player layout and lifecycle, use AdaptiveDAISDK directly. This scenario corresponds to the FullDemo app (with custom Activity) or intermediate variants like CustomExoDemo.

4.1. Initialize the SDK

Create configuration and get the SDK instance:

// 1. Build configuration
AdaptiveDAISDK.DefaultVideoPlayerConfiguration config =
    new AdaptiveDAISDK.DefaultVideoPlayerConfiguration()
        .setAdsEnabled(true)
        .setVASTTag("https://example.com/vast.xml");

// 2. Obtain SDK instance
AdaptiveDAISDK sdk = AdaptiveDAISDK.getInstance(
    context,
    "1",          // partnerId
    "167",        // distributionId
    "DemoApp",    // application name
    null,          // optional ExoPlayerFactoryAdapter
    null           // optional ImaSdkFactoryAdapter
);

// 3. Initialize with configuration
sdk.initialize(config);

Tip: If you rely on remote configuration (via distribution ID), you can attach an SDKReadyListener before calling initialize(...) and only begin playback after onSDKReady().

4.2. Bind SDK to your layout

In your custom Activity layout you typically define:

  • PlayerView for main content;
  • VideoView for ads (optional, required for video ads);
  • parent ViewGroup for layout management;
  • optional overlay View for fade animations;
  • optional ImageView for on‑pause image ads.

In your Activity.onCreate() or onResume():

sdk.setupPlayer(
    playerView,       // androidx.media3.ui.PlayerView
    adsVideoView,     // android.widget.VideoView for ads (optional)
    mainLayout,       // parent layout (e.g. RelativeLayout)
    fadeOverlayView,  // overlay for fade transitions (optional)
    contentImageView  // ImageView for on-pause image ads (optional)
);

The exact mapping between views and setupPlayer(...) parameters is demonstrated in the FullDemo layout (activity_player_dai.xml).

4.3. Start playback

Create a MediaItem and call playMedia(...):

MediaItem mediaItem = new MediaItem(
    "https://example.com/video.m3u8", // streamUrl
    "Movie Title",                    // title
    "1",                              // id
    "456",                            // category id
    3600,                              // duration in seconds
    null                               // optional macros map (can be null)
);

sdk.playMedia(mediaItem, new PlaybackListener() {
    @Override
    public void onPlaybackStarted() {
        // content started
    }
 
    @Override
    public void onPlaybackPaused() {
        // content paused or activity backgrounded
    }
 
    @Override
    public void onPlaybackResumed() {
        // content resumed after pause
    }
 
    @Override
    public void onPlaybackCompleted() {
        // content reached the end
    }
 
    @Override
    public void onAdsStarted() {
        // ad break started
    }
 
    @Override
    public void onAdsFinished() {
        // ad break finished, content resuming/resumed
    }
 
    @Override
    public void onPlaybackError(String error) {
        // log or show error to the user
    }
});

4.4. Forward lifecycle events

To keep playback state consistent across Activity lifecycle transitions, forward events to the SDK:

@Override
protected void onPause() {
    super.onPause();
    sdk.onActivityPaused();
}

@Override
protected void onResume() {
    super.onResume();
    sdk.onActivityResumed();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    sdk.release();
}

This ensures:

  • proper handling of on‑pause ads;
  • correct cleanup of ExoPlayer and IMA resources;
  • no background leaks when the Activity is destroyed.

5. Configuration and Ads

DefaultVideoPlayerConfiguration controls where the SDK takes its ad configuration from and whether the app/backend can influence how ads are rendered.

5.1. Default behavior (backend-driven configuration)

The SDK contacts the backend and retrieves ad configuration based on the partnerId and distributionId values passed to AdaptiveDAISDK.getInstance(...) or AdaptiveDAILauncher.Init(...).

  • All scheduling and layout details are defined by the backend.
  • The ad layout (including side‑by‑side behavior) is controlled by the SDK and backend; the app does not explicitly control the layout in this mode.

5.2. Controlling ads via DefaultVideoPlayerConfiguration

Warning: all ad configuration modes other than backend‑driven configuration (VAST, VMAP, ACF) are experimental and may change or be removed entirely in the release version of the SDK.

Enable / disable ads

DefaultVideoPlayerConfiguration config =
   new AdaptiveDAISDK.DefaultVideoPlayerConfiguration()
       .setAdsEnabled(true);  // or false to disable ads completely

If you call setAdsEnabled(false), ads are fully disabled regardless of backend configuration or documents you pass.

6. Error Handling and Logging

6.1. Playback and ads errors

All critical playback and ad errors are surfaced via PlaybackListener.onPlaybackError(String error).

Recommended pattern:

  • log the error (e.g. to Logcat + your analytics);
  • optionally show a user‑friendly message;
  • decide whether to retry, continue without ads, or exit the player.

6.2. Logging

Internally the SDK uses a logging utility (e.g. SdkLogger) and standard Android Log APIs. In debug builds more detailed information is typically available.

For troubleshooting:

  • enable verbose logs for the host app package and for com.adaptivedai tags;
  • reproduce the issue and inspect log output around playback/ads events.

7. Best Practices

  • Start simple: begin with AdaptiveDAILauncher (SimpleDemo pattern) to verify that your content and ad configuration work, then move to more advanced integrations.
  • Keep lifecycle wired: always forward onPause()/onResume()/onDestroy() to the SDK.
  • Test on real devices: especially Fire TV vs Android TV, as ad ID and some behaviors differ.
  • Monitor network conditions: handle transient network issues gracefully using onPlaybackError() callbacks.
  • Avoid blocking the UI thread: let the SDK perform heavy work (ads, playback) on its own threads; keep your callbacks light.

8. Where to Go Next

  • For a high‑level conceptual view of the SDK internals, read SDK_OVERVIEW_EN.md and the technical warp.md document.
  • For concrete, end‑to‑end examples based on the demo apps, see SDK_INTEGRATION_EXAMPLES_EN.md.
  • For API‑level reference, consult the generated JavaDoc for the public classes and interfaces (matching the public API exported via ProGuard rules).