Introduction

This book describes how to work with AdPlayer Lite library.

Tags

AdPlayer Lite library works with publishers and tags. Publisher is a unique ID for the whole organization, while Tag is a placement configration on the screen. There can be any number of tags but only one publisher.

Tags can be created and configured by using the admin console.

Types of Tags

Tags can be split into to categories:

  • Outstream - displays only a series of Ads
  • Instream - displays video content interleaved with Ads

Running Example App

Running example application requires publisher and tag ids. They can be configured in the root local.properties file like this:

sdk.dir=...

av_pub_id={published id goes here}
av_tag_id={tag id goes here}

After this project can simply be opened in the Android Studio and built.

Project Configuration

Before using AdPlayer Lite library project must be properly configured.

  1. Add Maven repository to settings.gradle.kts:
dependencyResolutionManagement {
    repositories {
        maven("https://us-central1-maven.pkg.dev/mobile-sdk-fd2e4/adservr-maven")
    }
}
  1. Add library dependencies to the app's module build.gradle.kts:
dependencies {
    implementation("com.adservrs:ad-player-lite:1.0.0")
}
  1. Add GMS configuration to the AndroidManifest.xml:
<application>
    <meta-data
        android:name="com.google.android.gms.ads.APPLICATION_ID"
        android:value="ca-app-pub-6746653557725812~6678258028" />
    <meta-data
        android:name="com.google.android.gms.ads.flag.OPTIMIZE_INITIALIZATION"
        android:value="true" />
    <meta-data
        android:name="com.google.android.gms.ads.flag.OPTIMIZE_AD_LOADING"
        android:value="true" />
</application>

Now your project is configured and you can move to creating first in-read placement.

Creating In-Read Placement

Creating AdPlayerView

AdPlayerView is the main View that is responsible for displaying in-read ads.

This view can be added via code:

val view = AdPlayerView(context)
view.load(pubId = "PUBLISHER_ID", tagId = "TAG_ID")
addView(view)

Or though the layout xml files:

<com.adservrs.adplayer.lite.AdPlayerView
    android:id="@+id/ad_player"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

It is not possible to load content from the xml file so it is still required to call AdPlayerView.load from the code.

Releasing AdPlayerView

AdPlayerView will try its best to release all used resources when GC-ed but it is highly recommended to explicitly release it to avoid unwanted side-effects:

val view: AdPlayerView = TODO()
view.release()

Releasing AdPlayerView will immediately free all used resources (including attached AdPlayerInReadController).

Layout Contract

AdPlayerView will strictly follow any measuring specs provided. View will try to fit 16/9 video and any required decorations (like labels, close buttons, etc.) into given constraints.

In case both width and height constraint are unbounded it will fallback to the predefined hard-coded size.

Creating In-Read Placement

Creating AdPlayerView

AdPlayerView is the main View that is responsible for displaying in-read ads.

This view can be added via code:

val view = AdPlayerView(context)
view.load(pubId = "PUBLISHER_ID", tagId = "TAG_ID")
addView(view)

Or though the layout xml files:

<com.adservrs.adplayer.lite.AdPlayerView
    android:id="@+id/ad_player"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

It is not possible to load content from the xml file so it is still required to call AdPlayerView.load from the code.

Releasing AdPlayerView

AdPlayerView will try its best to release all used resources when GC-ed but it is highly recommended to explicitly release it to avoid unwanted side-effects:

val view: AdPlayerView = TODO()
view.release()

Releasing AdPlayerView will immediately free all used resources (including attached AdPlayerInReadController).

Layout Contract

AdPlayerView will strictly follow any measuring specs provided. View will try to fit 16/9 video and any required decorations (like labels, close buttons, etc.) into given constraints.

In case both width and height constraint are unbounded it will fallback to the predefined hard-coded size.

Launching Interstitials

Unlike in-read mode, interstitials don't require any placement view. Instead the are always displayed in fullscreen. Interstitials, unlike regular fullscreen, will also be automatically closed after the first video finishes.

Creating Interstitial Controller

An AdPlayerInterstitialController must be created before launching interstitial:

val tag = AdPlayer.getTag(context, pubId = "...", tagId = "...")
val controller: AdPlayerInterstitialController = tag.newInterstitialController()

Additional configuration can also be provided during creation if needed:

val controller: AdPlayerInterstitialController = tag.newInterstitialController {
    // change background color of the window
    backgroundColor = Color.BLACK

    // disable back buttons/gestures so interstitial cannot be skipped
    dismissOnBack = false

    // this callback will be triggered when interstitial is closed
    onDismissListener = {
        Log.d("TAG", "Interstitial was closed")
    }
}

Some of these configurations above can be also configured on the admin portal. Values provided though the code will always override portal configuration.

Releasing Interstitial Controller

AdPlayerInterstitialController, like any other controller, must be always released when no longer needed to release underlying resources:

val controller: AdPlayerInterstitialController = TODO()
controller.release()

Launching or Dismissing Interstitial

Interstitial can be launched after creating AdPlayerInterstitialController:

val controller: AdPlayerInterstitialController = TODO()
controller.launchInterstitial()

Interstitial can also be forcibly closed if needed:

val controller: AdPlayerInterstitialController = TODO()
controller.dismissInterstitial()

It is important to remember that each controller can at most launch one interstitial at the same time.

Controlling Playback

What is Controller?

Controller is the main entity responsible for loading and controlling (pausing, skipping, unmuting, etc.) a content. All controllers inherit AdPlayerController, which provides most common functionality.

There are also more specialized controllers available:

  • AdPlayerInReadController - for working with in-read content
  • AdPlayerInterstitialController - for displaying interstitials

Creating Controller

There are few ways to get controller instance:

  1. When loading content via AdPlayerView:
val view: AdPlayerView
val controller: AdPlayerInReadController = view.load(...)
  1. Reading already loaded controller from AdPlayerView:
val view: AdPlayerView
val controller: AdPlayerInReadController? = view.controller
  1. Creating controller manually:
val tag = AdPlayer.getTag(context, pubId = "...", tagId = "...")

val controller: AdPlayerInReadController = tag.newInReadController()
// or
val controller: AdPlayerInReadController = tag.newInterstitialController()

Releasing Controller

All controllers must be always released when no longer needed to free underlying resources:

val controller: AdPlayerController
controller.release()

In cases when AdPlayerInReadController is attached to the AdPlayerView, it will be automatically released with the view itself.

Controlling Video Playback

Most basic functionality, that controllers allow, is to control video playback:

val controller: AdPlayerController

// pause playback
controller.pause()

// resume playback
controller.resume()

// skip current Ad
controller.skipAd()

AdPlayerInReadController also provides additional functinality:

val controller: AdPlayerInReadController

// toggle fullscreen mode
controller.toggleFullscreen()

Listening for State Changes / Events

One of the things controller provides is ability to listen for state changes and events:

val controller: AdPlayerController

// reading current state
Log.d("TAG", "Currect state is ${controller.state.value}")

// listening for state changes
coroutineScope.launch {
    controller.state.collect {
        if (it is AdPlayerState.Playing) {
            Log.d("TAG", "AdPlayer started a playback")
        }
    }
}

// listening for events
coroutineScope.launch {
    controller.events.collect {
        if (it is AdPlayerEvent.AdImpression) {
            Log.d("TAG", "Ad impressions was triggered")
        }
    }
}

Content and Playlist

Both content and playlists are only available for insteam tags.

Managing Playlist

Playlist contains list of content videos that are played one after the other. We can read current playlist like this:

val controller: AdPlayerController

val playlist = controller.playlist.value
Log.d("TAG", "playlist is $playlist")

One important note here is that playlist is loaded by the library asynchronously and might not be available right after the controller is created. This might result in the above API returning empty playlist. It is adviced, in most cases, for the application to track when playlist changes:

val controller: AdPlayerController

coroutineScope.launch {
    controller.playlist.collect {
        Log.d("TAG", "new playlist is $it")
    }
}

Currently Played Content

AdPlayerController can be used to track which content is currently playing:

val controller: AdPlayerController

// reading current content
Log.d("TAG", "${controller.content.value} is currently playing")

// tracking content changes
coroutineScope.launch {
    controller.content.collect {
        Log.d("TAG", "$it is now playing")
    }
}

// reading playback progress
coroutineScope.launch {
    val position = controller.getContentPosition()
    val duration = controller.getContentDuration()
    Log.d("TAG", "content at $position / $duration")
}

Choosing Content to Play

In order to play different video from the playlist we can use these functions:

val controller: AdPlayerController

// play next video
controller.playNextContent()

// play previous video
controller.playPrevContent()

// play specific video
controller.playContentByIndex(3)