IMA DAI SDK スタートガイド

IMA SDK を使用すると、マルチメディア広告をウェブサイトやアプリに簡単に統合できます。IMA SDK は、 VAST 準拠の任意の広告サーバーから広告をリクエストし、アプリ内の広告再生を管理できます。IMA DAI SDK を使用すると、アプリは広告とコンテンツ動画(VOD またはライブ コンテンツ)のストリーム リクエストを行います。SDK は統合された動画ストリームを返すため、アプリ内で広告動画とコンテンツ動画の切り替えを管理する必要はありません。

関心のある DAI ソリューションを選択する

フルサービス DAI

このガイドでは、IMA DAI SDK をシンプルな動画プレーヤー アプリに統合する方法について説明します。統合済みのサンプルを表示または確認するには、GitHub から BasicExample をダウンロードしてください。

IMA DAI の概要

IMA DAI の実装には、このガイドで説明するように、4 つの主要な SDK コンポーネントが関与します。

  • StreamDisplayContainer: 動画再生要素の上に配置され、広告 UI 要素を格納するコンテナ オブジェクト。
  • AdsLoader: ストリームをリクエストし、ストリーム リクエスト レスポンス オブジェクトによってトリガーされたイベントを処理するオブジェクト。インスタンス化すべき広告ローダは 1 つだけです。この広告ローダは、アプリの存続期間中ずっと再利用できます。
  • StreamRequest: ストリーム リクエストを定義するオブジェクト。ストリーム リクエストは、ビデオ オンデマンドまたはライブ配信のいずれかです。リクエストでは、コンテンツ ID のほか、API キーまたは認証トークンなどのパラメータを指定します。
  • StreamManager: ダイナミック広告挿入ストリームと DAI バックエンドとのインタラクションを処理するオブジェクト。ストリーム マネージャーは、トラッキング ピングも処理し、ストリーム イベントと広告イベントをパブリッシャーに転送します。

前提条件

  • Android Studio
  • SDK 統合のサンプル動画プレーヤー アプリ

サンプルの動画プレーヤー アプリをダウンロードして実行する

このサンプルアプリには、HLS 動画を再生する動作する動画プレーヤーが用意されています。これを IMA DAI SDK の DAI 機能を統合する出発点として使用します。

  1. サンプル動画プレーヤー アプリをダウンロードして解凍します。

  2. Android Studio を起動し、[Open an existing Android Studio project] を選択します。Android Studio がすでに実行されている場合は、[File] > [New] > [Import Project] を選択します。次に、SampleVideoPlayer/build.gradle を選択します。

  3. [Tools] > [Android] > [Sync Project with Gradle Files] を選択して、Gradle 同期を実行します。

  4. [Run] > [Run 'app'] を使用して、プレーヤー アプリが実機または Android 仮想デバイスでコンパイルされ、実行されることを確認します。動画ストリーミングの読み込みに時間がかかることがありますが、これは正常な動作です。

サンプル動画プレーヤーを確認する

サンプル動画プレーヤーには、IMA DAI SDK 統合コードはまだ含まれていません。サンプルアプリは、主に次の 2 つの部分で構成されています。

  1. samplevideoplayer/SampleVideoPlayer.java: IMA DAI 統合の基盤となる ExoPlayer ベースの HLS プレーヤー。

  2. videoplayerapp/MyActivity.java: このアクティビティは動画プレーヤーを作成し、ContextSimpleExoPlayerView を渡します。

IMA DAI SDK をプレーヤー アプリに追加する

また、IMA DAI SDK への参照も含める必要があります。Android Studio で、app/build.gradle にあるアプリケーション レベルの build.gradle ファイルに次のコードを追加します。

repositories {
  google()
  mavenCentral()
}

dependencies {
    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'androidx.media3:media3-exoplayer:1.3.1'
    implementation 'com.google.ads.interactivemedia.v3:interactivemedia:3.36.0'
}

IMA DAI SDK を統合する

  1. videoplayerapp パッケージ(app/java/com.google.ads.interactivemedia.v3.samples/videoplayerapp/ 内)に SampleAdsWrapper という新しいクラスを作成し、既存の SampleVideoPlayer をラップして、IMA DAI を実装するロジックを追加します。これを行うには、まず、広告サーバーから広告をリクエストするために使用する AdsLoader を作成する必要があります。

    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.samplevideoplayer.SampleVideoPlayer;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    
    public class SampleAdsWrapper implements AdEvent.AdEventListener,
            AdErrorEvent.AdErrorListener, AdsLoader.AdsLoadedListener {
    
        // Livestream 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 = "2548831";
        private static final String TEST_VIDEO_ID = "tears-of-steel";
    
        private static final String PLAYER_TYPE = "DAISamplePlayer";
    
        /**
         * Log interface, so you can output the log commands to the UI or similar.
         */
        public interface Logger {
            void log(String logMessage);
        }
    
        private ImaSdkFactory sdkFactory;
        private AdsLoader adsLoader;
        private StreamDisplayContainer displayContainer;
        private StreamManager streamManager;
        private List<VideoStreamPlayer.VideoStreamPlayerCallback> playerCallbacks;
    
        private SampleVideoPlayer videoPlayer;
        private Context context;
        private ViewGroup adUiContainer;
    
        private String fallbackUrl;
        private Logger logger;
    
        public SampleAdsWrapper(Context context, SampleVideoPlayer videoPlayer,
                                ViewGroup adUiContainer) {
            this.videoPlayer = videoPlayer;
            this.context = context;
            this.adUiContainer = adUiContainer;
            sdkFactory = ImaSdkFactory.getInstance();
            playerCallbacks = new ArrayList<>();
            createAdsLoader();
            displayContainer = sdkFactory.createStreamDisplayContainer(
                this.adUiContainer,
                videoStreamPlayer
            );
        }
    
        private void createAdsLoader() {
            ImaSdkSettings settings = new ImaSdkSettings();
            adsLoader = sdkFactory.createAdsLoader(context);
        }
    
        public void requestAndPlayAds() {
            adsLoader.addAdErrorListener(this);
            adsLoader.addAdsLoadedListener(this);
            adsLoader.requestStream(buildStreamRequest());
        }
    }
    
  2. 広告付きのストリームをリクエストできるように、buildStreamRequest() メソッドを AdsLoader に追加します。広告付きのライブ配信(デフォルトで設定)または、広告付きの録画コンテンツを再生するビデオ オンデマンド(VOD)ストリームです。VOD ストリームを有効にするには、ライブ配信リクエストをコメントアウトし、VOD ストリーム リクエストのコメントを解除します。

    DAI を使用するには、プレーヤーがライブ配信の ID3 イベントを IMA DAI SDK に渡す必要があります。次のサンプルコードでは、callback.onUserTextReceived() メソッドによって行われます。

    videoplayerapp/SampleAdsWrapper.java
    private StreamRequest buildStreamRequest() {
        VideoStreamPlayer videoStreamPlayer = createVideoStreamPlayer();
        videoPlayer.setSampleVideoPlayerCallback(
                new SampleVideoPlayer.SampleVideoPlayerCallback() {
                    @Override
                    public void onUserTextReceived(String userText) {
                        for (VideoStreamPlayer.VideoStreamPlayerCallback callback :
                                playerCallbacks) {
                            callback.onUserTextReceived(userText);
                        }
                    }
    
                    @Override
                    public void onSeek(int windowIndex, long positionMs) {
                        // See if you would seek past an ad, and if so, jump back to it.
                        long newSeekPositionMs = positionMs;
                        if (streamManager != null) {
                            CuePoint prevCuePoint  =
                                    streamManager.getPreviousCuePointForStreamTime(positionMs / 1000);
                            if (prevCuePoint != null && !prevCuePoint.isPlayed()) {
                                newSeekPositionMs = (long) (prevCuePoint.getStartTime() * 1000);
                            }
                        }
                        videoPlayer.seekTo(windowIndex, newSeekPositionMs);
                    }
    
                    @Override
                    public void onContentComplete() {
                        for (VideoStreamPlayer.VideoStreamPlayerCallback callback : playerCallbacks) {
                            callback.onContentComplete();
                        }
                    }
    
                    @Override
                    public void onPause() {
                        for (VideoStreamPlayer.VideoStreamPlayerCallback callback : playerCallbacks) {
                            callback.onPause();
                        }
                    }
    
                    @Override
                    public void onResume() {
                        for (VideoStreamPlayer.VideoStreamPlayerCallback callback : playerCallbacks) {
                            callback.onResume();
                        }
                    }
    
                    @Override
                    public void onVolumeChanged(int percentage) {
                        for (VideoStreamPlayer.VideoStreamPlayerCallback callback : playerCallbacks) {
                            callback.onVolumeChanged(percentage);
                        }
                    }
                });
    
        // Livestream request.
        StreamRequest request = sdkFactory.createLiveStreamRequest(
                TEST_ASSET_KEY, null, displayContainer);
    
        // VOD request. Comment the createLiveStreamRequest() line above and uncomment this
        // createVodStreamRequest() below to switch from a livestream to a VOD stream.
        // StreamRequest request = sdkFactory.createVodStreamRequest(TEST_CONTENT_SOURCE_ID,
        //        TEST_VIDEO_ID, null, displayContainer);
        return request;
    }
    
  3. ストリームを再生するために VideoStreamPlayer も必要であるため、createVideoStreamPlayer() メソッドを追加して、VideoStreamPlayer を実装する匿名クラスを作成します。

    videoplayerapp/SampleAdsWrapper.java
    private VideoStreamPlayer createVideoStreamPlayer() {
        VideoStreamPlayer player = new VideoStreamPlayer() {
            @Override
            public void loadUrl(String url, List<HashMap<String, String>> subtitles) {
                videoPlayer.setStreamUrl(url);
                videoPlayer.play();
            }
    
            @Override
            public void addCallback(
                VideoStreamPlayerCallback videoStreamPlayerCallback) {
                    playerCallbacks.add(videoStreamPlayerCallback);
            }
    
            @Override
            public void removeCallback(
                VideoStreamPlayerCallback videoStreamPlayerCallback) {
                    playerCallbacks.remove(videoStreamPlayerCallback);
            }
    
            @Override
            public void onAdBreakStarted() {
                // Disable player controls.
                videoPlayer.enableControls(false);
                log("Ad Break Started\n");
            }
    
            @Override
            public void onAdBreakEnded() {
                // Re-enable player controls.
                videoPlayer.enableControls(true);
                log("Ad Break Ended\n");
            }
    
            @Override
            public VideoProgressUpdate getContentProgress() {
                return new VideoProgressUpdate(videoPlayer.getCurrentPosition(),
                        videoPlayer.getDuration());
            }
    
            @Override
            public int getVolume() {
                return videoPlayer.getVolume();
            }
        };
        return player;
    }
    
  4. 必要なリスナーを実装し、エラー処理のサポートを追加します。

    AdErrorListener の実装に注目してください。広告の再生に失敗した場合に、フォールバック URL を呼び出します。コンテンツと広告が 1 つのストリームに存在するため、DAI ストリームでエラーが発生した場合にフォールバック ストリームを呼び出す準備ができている必要があります。

    videoplayerapp/SampleAdsWrapper.java
    /** AdErrorListener implementation **/
    @Override
    public void onAdError(AdErrorEvent event) {
        // play fallback URL.
        videoPlayer.setStreamUrl(fallbackUrl);
        videoPlayer.enableControls(true);
        videoPlayer.play();
    }
    
    /** AdEventListener implementation **/
    @Override
    public void onAdEvent(AdEvent event) {
        switch (event.getType()) {
            case AD_PROGRESS:
                // Do nothing or else log are filled by these messages.
                break;
            default:
                log(String.format("Event: %s\n", event.getType()));
                break;
        }
    }
    
    /** AdsLoadedListener implementation **/
    @Override
    public void onAdsManagerLoaded(AdsManagerLoadedEvent event) {
        streamManager = event.getStreamManager();
        streamManager.addAdErrorListener(this);
        streamManager.addAdEventListener(this);
        streamManager.init();
    }
    
    /** Sets fallback URL in case ads stream fails. **/
    void setFallbackUrl(String url) {
        fallbackUrl = url;
    }
    
  5. ロギング用のコードを追加します。

    videoplayerapp/SampleAdsWrapper.java
    /** Sets logger for displaying events to screen. Optional. **/
    void setLogger(Logger logger) {
        this.logger = logger;
    }
    
    private void log(String message) {
        if (logger != null) {
            logger.log(message);
        }
    }
    
  6. videoplayerappMyActivity を変更して、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);
            videoPlayer = new SampleVideoPlayer(rootView.getContext(),
                    (SimpleExoPlayerView) rootView.findViewById(R.id.playerView));
            videoPlayer.enableControls(false);
    
            final SampleAdsWrapper sampleAdsWrapper = new SampleAdsWrapper(this, videoPlayer,
                (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);
                            }
                        });
                    }
                }
            });
    
            playButton = (ImageButton) rootView.findViewById(R.id.playButton);
            // Set up play button listener to play video then hide play button.
            playButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    sampleAdsWrapper.requestAndPlayAds();
                    playButton.setVisibility(View.GONE);
                }
            });
        }
    ...
    }
    
  7. アクティビティのレイアウト ファイル activity_my.xml を変更して、ロギング用の UI 要素を追加します。

    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>
    ...
    

おめでとうございます。これで、Android アプリで動画広告をリクエストして表示できるようになりました。実装を微調整するには、ブックマークスナップバックAPI のドキュメントをご覧ください。

トラブルシューティング

動画広告の再生で問題が発生した場合は、完成した BasicExample をダウンロードしてみてください。BasicExample で正常に動作する場合は、アプリの IMA 統合コードに問題がある可能性があります。

それでも問題が解決しない場合は、IMA SDK フォーラムをご覧ください。