เริ่มต้นใช้งาน IMA DAI SDK

IMA SDK ช่วยให้ผสานรวมโฆษณามัลติมีเดียลงในเว็บไซต์และแอปได้อย่างง่ายดาย IMA SDK สามารถส่งคําขอโฆษณาจากเซิร์ฟเวอร์โฆษณา ที่เป็นไปตามข้อกําหนดของ VAST ใดก็ได้ และจัดการการเล่นโฆษณาในแอป เมื่อใช้ IMA DAI SDK แอปจะส่งคําขอสตรีมสําหรับโฆษณาและวิดีโอเนื้อหา ไม่ว่าจะเป็น VOD หรือเนื้อหาสด จากนั้น SDK จะแสดงผลสตรีมวิดีโอแบบรวม คุณจึงไม่ต้องจัดการการสลับระหว่างวิดีโอโฆษณากับวิดีโอเนื้อหาภายในแอป

เลือกโซลูชัน DAI ที่คุณสนใจ

DAI แบบครบวงจร

คู่มือนี้แสดงวิธีผสานรวม IMA DAI SDK เข้ากับแอปโปรแกรมเล่นวิดีโอแบบง่าย หากต้องการดูหรือทําตามตัวอย่างการผสานรวมที่เสร็จสมบูรณ์ ให้ดาวน์โหลด BasicExample จาก GitHub

ภาพรวม IMA DAI

การใช้ IMA DAI ประกอบด้วยคอมโพเนนต์ SDK หลัก 4 รายการตามที่แสดงในคู่มือนี้

  • StreamDisplayContainer: ออบเจ็กต์คอนเทนเนอร์ที่วางอยู่ด้านบนขององค์ประกอบการเล่นวิดีโอและเป็นที่เก็บองค์ประกอบ UI ของโฆษณา
  • AdsLoader: ออบเจ็กต์ที่ขอสตรีมและจัดการเหตุการณ์ที่ทริกเกอร์โดยออบเจ็กต์การตอบกลับคำขอสตรีม คุณควรสร้างอินสแตนซ์ของเครื่องมือโหลดโฆษณาเพียงรายการเดียว ซึ่งนํามาใช้ซ้ำได้ตลอดอายุการใช้งานของแอปพลิเคชัน
  • StreamRequest: ออบเจ็กต์ที่กําหนดคําขอสตรีม คำขอสตรีมอาจเป็นคำขอสำหรับวิดีโอออนดีมานด์หรือสตรีมแบบสดก็ได้ คำขอจะระบุรหัสเนื้อหา รวมถึงคีย์ API หรือโทเค็นการตรวจสอบสิทธิ์ และพารามิเตอร์อื่นๆ
  • StreamManager: ออบเจ็กต์ที่จัดการสตรีมการแทรกโฆษณาแบบไดนามิกและการโต้ตอบกับแบ็กเอนด์ DAI นอกจากนี้ เครื่องมือจัดการสตรีมยังจัดการการติดตามคําสั่ง ping และส่งต่อสตรีมและเหตุการณ์โฆษณาไปยังผู้เผยแพร่โฆษณาด้วย

ข้อกำหนดเบื้องต้น

  • Android Studio
  • ตัวอย่างแอปโปรแกรมเล่นวิดีโอสำหรับการผสานรวม SDK

ดาวน์โหลดและเรียกใช้แอปวิดีโอเพลเยอร์ตัวอย่าง

แอปตัวอย่างมีโปรแกรมเล่นวิดีโอที่ใช้งานได้ซึ่งเล่นวิดีโอ HLS ใช้ข้อมูลนี้เป็นจุดเริ่มต้นในการผสานรวมความสามารถ DAI ของ IMA DAI SDK

  1. ดาวน์โหลดตัวอย่างแอปโปรแกรมเล่นวิดีโอและดึงไฟล์ออกมา

  2. เริ่ม Android Studio แล้วเลือกเปิดโปรเจ็กต์ Android Studio ที่มีอยู่ หรือหาก Android Studio ทำงานอยู่ ให้เลือกไฟล์ > ใหม่ > นำเข้าโปรเจ็กต์ จากนั้นเลือก SampleVideoPlayer/build.gradle

  3. เรียกใช้การซิงค์ Gradle โดยเลือกเครื่องมือ > Android > ซิงค์โปรเจ็กต์กับไฟล์ Gradle

  4. ตรวจสอบว่าแอปเพลเยอร์คอมไพล์และทำงานในอุปกรณ์ Android จริงหรืออุปกรณ์เสมือนจริง Android โดยใช้เรียกใช้ > เรียกใช้ "แอป" เป็นเรื่องปกติที่สตรีมวิดีโอจะใช้เวลาสักครู่ในการโหลดก่อนที่จะเล่น

ตรวจสอบวิดีโอเพลเยอร์ตัวอย่าง

โปรแกรมเล่นวิดีโอตัวอย่างยังไม่มีโค้ดการผสานรวม IMA DAI SDK แอปตัวอย่างประกอบด้วย 2 ส่วนหลักๆ ดังนี้

  1. samplevideoplayer/SampleVideoPlayer.java: โปรแกรมเล่น HLS ที่ใช้ ExoPlayer ซึ่งใช้เป็นพื้นฐานสำหรับการผสานรวม IMA DAI

  2. videoplayerapp/MyActivity.java: กิจกรรมนี้จะสร้างวิดีโอเพลเยอร์และส่ง Context และ SimpleExoPlayerView ไปให้

เพิ่ม IMA DAI SDK ลงในแอปโปรแกรมเล่น

นอกจากนี้ คุณยังต้องใส่การอ้างอิงถึง IMA DAI SDK ด้วย ใน Android Studio ให้เพิ่มข้อมูลต่อไปนี้ลงในไฟล์ build.gradle ระดับแอปพลิเคชันซึ่งอยู่ที่ app/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.35.1'
}

ผสานรวม IMA DAI SDK

  1. สร้างคลาสใหม่ชื่อ SampleAdsWrapper ในแพ็กเกจ videoplayerapp (ใน app/java/com.google.ads.interactivemedia.v3.samples/videoplayerapp/) เพื่อรวม 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. ใช้ Listener ที่จำเป็นและเพิ่มการรองรับการจัดการข้อผิดพลาด

    โปรดสังเกตการใช้งาน AdErrorListener เนื่องจากจะเรียกใช้ URL สำรองหากโฆษณาเล่นไม่สำเร็จ เนื่องจากเนื้อหาและโฆษณาอยู่ในสตรีมเดียว คุณจึงต้องพร้อมเรียกใช้สตรีมสำรองหากสตรีม 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. แก้ไข MyActivity ใน videoplayerapp เพื่อสร้างอินสแตนซ์และเรียกใช้ 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 แล้ว หากต้องการปรับแต่งการใช้งาน ให้ดูบุ๊กมาร์ก Snapback และเอกสารประกอบของ API

การแก้ปัญหา

หากพบปัญหาในการเล่นโฆษณาวิดีโอ ให้ลองดาวน์โหลด BasicExample ที่เสร็จสมบูรณ์ หากทํางานอย่างถูกต้องใน BasicExample แสดงว่าอาจมีปัญหาเกี่ยวกับโค้ดการผสานรวม IMA ของแอป

หากยังพบปัญหาอยู่ โปรดไปที่ฟอรัม IMA SDK