Get Started

Note: Dynamic ad insertion requires that you have an Ad Manager 360 account and an account manager. Please contact your account manager if you are interested in signing up.

This guide shows how to integrate the Interactive Media Ads SDK using Dynamic Ad Insertion (DAI) into a sample video player app on Android Mobile/Tablet, Android TV, or FireTV. Start by downloading the sample video player app (without any IMA integration) from GitHub. At the end of the exercise the app will play HTTP Live Streaming (HLS) video that contains both content and ads.

Prerequisites

  • Android Studio
  • The Sample HLS Video Player app which you'll use to integrate the SDK

Download and run the sample video player app

The sample app provides a working video player that plays HLS video. Use this as a starting point for integrating the IMA Android SDK's DAI functionality.

  1. Download the Sample HLS Video Player App and unzip.
  2. Start Android Studio and select Open an existing Android Studio project, or if Android Studio is already running, select File > New > Import Project. Then choose SampleHlsVideoPlayer/build.gradle.
  3. Run a Gradle sync by selecting Tools > Android > Sync Project with Gradle Files.
  4. Ensure that the player app compiles and runs on a physical Android device or an Android Virtual Device using Run > Run 'app'. It's normal for the video stream to take a few moments to load before playing.

Examine the sample video player

The sample video player doesn't contain any IMA SDK integration code yet. The sample app consists of two major parts:

  • samplehlsvideoplayer/SampleHlsVideoPlayer.java - A simple ExoPlayer-based HLS player that serves as the basis for IMA DAI integration.
  • videoplayerapp/MyActivity.java - This activity creates the video player and passes it a Context and SimpleExoPlayerView.

Add the IMA Android SDK to the player app

Add the Google Maven repository to your project-level build.gradle:

allprojects {
    repositories {
        google()
        jcenter()
    }
}
You must also include a reference to the IMA SDK. For Android Studio, do the following:
  1. Add the following to your application-level build.gradle file, located at app/build.gradle:
    dependencies {
        implementation 'com.android.support:appcompat-v7:25.+'
        implementation 'com.google.android.exoplayer:exoplayer:r2.4.1'
        implementation 'com.google.ads.interactivemedia.v3:interactivemedia:3.7.2'
        implementation 'com.google.android.gms:play-services-ads-identifier:17.0.0'
    }

Checkpoint: your application should compile and run, but you haven't yet added UI elements or code to request and display ads.

Integrate the IMA SDK

  1. Create a new class called SampleAdsWrapper in the videoplayerapp package (in app/java/com.google.ads.interactivemedia.v3.samples/videoplayerapp/) to wrap the existing SampleHlsVideoPlayer and add logic implementing IMA Dynamic Ad Insertion (DAI). To do this, you must first create an AdsLoader, which is used to request ads from ad servers.

    videoplayerapp/SampleAdsWrapper.java

    package com.google.ads.interactivemedia.v3.samples.videoplayerapp;
    
    import android.annotation.TargetApi;
    import android.content.Context;
    import android.os.Build;
    import android.view.ViewGroup;
    import android.webkit.WebView;
    
    import com.google.ads.interactivemedia.v3.api.AdErrorEvent;
    import com.google.ads.interactivemedia.v3.api.AdEvent;
    import com.google.ads.interactivemedia.v3.api.AdsLoader;
    import com.google.ads.interactivemedia.v3.api.AdsManagerLoadedEvent;
    import com.google.ads.interactivemedia.v3.api.CuePoint;
    import com.google.ads.interactivemedia.v3.api.ImaSdkFactory;
    import com.google.ads.interactivemedia.v3.api.ImaSdkSettings;
    import com.google.ads.interactivemedia.v3.api.StreamDisplayContainer;
    import com.google.ads.interactivemedia.v3.api.StreamManager;
    import com.google.ads.interactivemedia.v3.api.StreamRequest;
    import com.google.ads.interactivemedia.v3.api.player.VideoProgressUpdate;
    import com.google.ads.interactivemedia.v3.api.player.VideoStreamPlayer;
    import com.google.ads.interactivemedia.v3.samples.samplehlsvideoplayer.SampleHlsVideoPlayer;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    
    public class SampleAdsWrapper implements AdEvent.AdEventListener,
            AdErrorEvent.AdErrorListener, AdsLoader.AdsLoadedListener {
    
        // Live stream asset key.
        private static final String TEST_ASSET_KEY = "sN_IYUG8STe1ZzhIIE_ksA";
    
        // VOD content source and video IDs.
        private static final String TEST_CONTENT_SOURCE_ID = "19463";
        private static final String TEST_VIDEO_ID = "googleio-highlights";
    
        private static final String PLAYER_TYPE = "DAISamplePlayer";
    
        /**
         * Log interface, so we can output the log commands to the UI or similar.
         */
        public interface Logger {
            void log(String logMessage);
        }
    
        private ImaSdkFactory mSdkFactory;
        private AdsLoader mAdsLoader;
        private StreamDisplayContainer mDisplayContainer;
        private StreamManager mStreamManager;
        private List<VideoStreamPlayer.VideoStreamPlayerCallback> mPlayerCallbacks;
    
        private SampleHlsVideoPlayer mVideoPlayer;
        private Context mContext;
        private ViewGroup mAdUiContainer;
    
        private String mFallbackUrl;
        private Logger mLogger;
    
        public SampleAdsWrapper(Context context, SampleHlsVideoPlayer videoPlayer,
                                ViewGroup adUiContainer) {
            mVideoPlayer = videoPlayer;
            mContext = context;
            mAdUiContainer = adUiContainer;
            mSdkFactory = ImaSdkFactory.getInstance();
            mPlayerCallbacks = new ArrayList<>();
            createAdsLoader();
            mDisplayContainer = mSdkFactory.createStreamDisplayContainer();
        }
    
        private void createAdsLoader() {
            ImaSdkSettings settings = new ImaSdkSettings();
            mAdsLoader = mSdkFactory.createAdsLoader(mContext);
        }
    
        public void requestAndPlayAds() {
            mAdsLoader.addAdErrorListener(this);
            mAdsLoader.addAdsLoadedListener(this);
            mAdsLoader.requestStream(buildStreamRequest());
        }
    }
              
  2. Add a buildStreamRequest() method to the AdsLoader so it can request a stream with ads. This will either be a live stream with ads (set by default), or a video-on-demand(VOD) stream that plays pre-recorded content with ads. To enable the VOD stream, comment out the live stream request and uncomment the VOD stream request.

    videoplayerapp/SampleAdsWrapper.java

    private StreamRequest buildStreamRequest() {
        VideoStreamPlayer videoStreamPlayer = createVideoStreamPlayer();
        mVideoPlayer.setSampleHlsVideoPlayerCallback(
                new SampleHlsVideoPlayer.SampleHlsVideoPlayerCallback() {
                    @Override
                    public void onUserTextReceived(String userText) {
                        for (VideoStreamPlayer.VideoStreamPlayerCallback callback :
                                mPlayerCallbacks) {
                            callback.onUserTextReceived(userText);
                        }
                    }
                    @Override
                    public void onSeek(int windowIndex, long positionMs) {
                        // See if we would seek past an ad, and if so, jump back to it.
                        long newSeekPositionMs = positionMs;
                        if (mStreamManager != null) {
                            CuePoint prevCuePoint  =
                                    mStreamManager.getPreviousCuePointForStreamTime(positionMs / 1000);
                            if (prevCuePoint != null && !prevCuePoint.isPlayed()) {
                                newSeekPositionMs = (long) (prevCuePoint.getStartTime() * 1000);
                            }
                        }
                        mVideoPlayer.seekTo(windowIndex, newSeekPositionMs);
                    }
                });
        mDisplayContainer.setVideoStreamPlayer(videoStreamPlayer);
        mDisplayContainer.setAdContainer(mAdUiContainer);
        // Live stream request.
        StreamRequest request = mSdkFactory.createLiveStreamRequest(
                TEST_ASSET_KEY, null, mDisplayContainer);
    
        // VOD request. Comment the createLiveStreamRequest() line above and uncomment this
        // createVodStreamRequest() below to switch from a live stream to a VOD stream.
        //StreamRequest request = mSdkFactory.createVodStreamRequest(TEST_CONTENT_SOURCE_ID,
        //        TEST_VIDEO_ID, null, mDisplayContainer);
        return request;
    }
    
  3. You'll also need a VideoStreamPlayer to play the stream, so add a createVideoStreamPlayer() method, which will create an anonymous class that implements VideoStreamPlayer.

    videoplayerapp/SampleAdsWrapper.java

    private VideoStreamPlayer createVideoStreamPlayer() {
        VideoStreamPlayer player = new VideoStreamPlayer() {
            @Override
            public void loadUrl(String url, List<HashMap<String, String>> subtitles) {
                mVideoPlayer.setStreamUrl(url);
                mVideoPlayer.play();
            }
    
            @Override
            public void addCallback(
                VideoStreamPlayerCallback videoStreamPlayerCallback) {
                    mPlayerCallbacks.add(videoStreamPlayerCallback);
            }
    
            @Override
            public void removeCallback(
                VideoStreamPlayerCallback videoStreamPlayerCallback) {
                    mPlayerCallbacks.remove(videoStreamPlayerCallback);
            }
    
            @Override
            public void onAdBreakStarted() {
                // Disable player controls.
                mVideoPlayer.enableControls(false);
                log("Ad Break Started\n");
            }
    
            @Override
            public void onAdBreakEnded() {
                // Re-enable player controls.
                mVideoPlayer.enableControls(true);
                log("Ad Break Ended\n");
            }
    
            @Override
            public VideoProgressUpdate getContentProgress() {
                return new VideoProgressUpdate(mVideoPlayer.getCurrentPosition(),
                        mVideoPlayer.getDuration());
            }
        };
        return player;
    }
    
  4. Implement the required listeners and add support for error handling.

    Important: Please note the AdErrorListener implementation, as it calls a fallback URL if the ads fail to play. Since the content and ads are in one stream, you must be ready to call a fallback stream if the DAI stream encounters an error.

    videoplayerapp/SampleAdsWrapper.java

    /** AdErrorListener implementation **/
    @Override
    public void onAdError(AdErrorEvent event) {
        // play fallback URL.
        mVideoPlayer.setStreamUrl(mFallbackUrl);
        mVideoPlayer.enableControls(true);
        mVideoPlayer.play();
    }
    
    /** AdEventListener implementation **/
    @Override
    public void onAdEvent(AdEvent event) {
        switch (event.getType()) {
            case AD_PROGRESS:
                // Do nothing or else log will be filled by these messages.
                break;
            default:
                log(String.format("Event: %s\n", event.getType()));
                break;
        }
    }
    
    /** AdsLoadedListener implementation **/
    @Override
    public void onAdsManagerLoaded(AdsManagerLoadedEvent event) {
        mStreamManager = event.getStreamManager();
        mStreamManager.addAdErrorListener(this);
        mStreamManager.addAdEventListener(this);
        mStreamManager.init();
    }
    
    /** Sets fallback URL in case ads stream fails. **/
    void setFallbackUrl(String url) {
        mFallbackUrl = url;
    }
    
  5. Add in code for logging.

    videoplayerapp/SampleAdsWrapper.java

    /** Sets logger for displaying events to screen. Optional. **/
    void setLogger(Logger logger) {
        mLogger = logger;
    }
    
    private void log(String message) {
        if (mLogger != null) {
            mLogger.log(message);
        }
    }
    
  6. Modify MyActivity in videoplayerapp to instantiate and call SampleAdsWrapper.

    videoplayerapp/MyActivity.java

    import android.view.ViewGroup;
    import android.widget.ScrollView;
    …
    public class MyActivity extends AppCompatActivity {
    …
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_my);
            View rootView = findViewById(R.id.videoLayout);
            mVideoPlayer = new SampleHlsVideoPlayer(rootView.getContext(),
                    (SimpleExoPlayerView) rootView.findViewById(R.id.playerView));
            mVideoPlayer.enableControls(false);
    
            final SampleAdsWrapper sampleAdsWrapper = new SampleAdsWrapper(this, mVideoPlayer,
                (ViewGroup) rootView.findViewById(R.id.adUiContainer));
            sampleAdsWrapper.setFallbackUrl(DEFAULT_STREAM_URL);
    
            final ScrollView scrollView = (ScrollView) findViewById(R.id.logScroll);
            final TextView textView = (TextView) findViewById(R.id.logText);
    
            sampleAdsWrapper.setLogger(new SampleAdsWrapper.Logger() {
                @Override
                public void log(String logMessage) {
                    Log.i(APP_LOG_TAG, logMessage);
                    if (textView != null) {
                        textView.append(logMessage);
                    }
                    if (scrollView != null) {
                        scrollView.post(new Runnable() {
                            @Override
                            public void run() {
                                scrollView.fullScroll(View.FOCUS_DOWN);
                            }
                        });
                    }
                }
            });
    
            mPlayButton = (ImageButton) rootView.findViewById(R.id.playButton);
            // Set up play button listener to play video then hide play button.
            mPlayButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    sampleAdsWrapper.requestAndPlayAds();
                    mPlayButton.setVisibility(View.GONE);
                }
            });
        }
    …
    }
  7. Modify the Activity's layout file, activity_my.xml to add UI elements for logging.

    res/layout/activity_my.xml

    …
        <TextView
            android:id="@+id/playerDescription"
            android:text="@string/video_description"
            android:textAlignment="center"
            android:gravity="center_horizontal"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="0.1"
            android:textSize="@dimen/font_size" />
        <!-- UI element for viewing SDK event log -->
        <ScrollView
            android:id="@+id/logScroll"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="0.5"
            android:padding="5dp"
            android:background="#DDDDDD">
    
            <TextView
                android:id="@+id/logText"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
            </TextView>
        </ScrollView>
    

Congrats! You're now requesting and displaying video ads in your Android application. To fine tune your implementation, read the Bookmarks and Snapback guides, and the API documentation.

Troubleshooting

If you're experiencing issues playing a video ad, try downloading the completed BasicExample. If it works properly in the BasicExample then there's likely an issue with your app's IMA integration code. Review this guide and API docs to detect any discrepancies.

Still having issues? Drop us a line on the IMA SDK forum.

Send feedback about...

IMA DAI SDK for Android
Need help? Visit our support page.