תחילת העבודה עם IMA DAI SDK

באמצעות ערכות ה-IMA SDK קל לשלב מודעות מולטימדיה באתרים ובאפליקציות שלכם. ערכות IMA SDK יכולות לבקש מודעות מכל שרת מודעות שתואם ל-VAST ולנהל את הפעלת המודעות באפליקציות שלך. באמצעות ערכות SDK של DAI IMA, אפליקציות שולחות בקשה לסטרימינג של סרטונים ותוכן של מודעות – VOD או תוכן בשידור חי. לאחר מכן ה-SDK מחזיר שידור וידאו משולב, כך שלא יהיה צורך לנהל את המעבר בין מודעת וידאו לתוכן באפליקציה.

במדריך הזה נדגים איך לשלב את IMA SDK באפליקציה פשוטה של נגן וידאו. אם אתם רוצים להציג שילוב לדוגמה לדוגמה או לעקוב אחריו, הורידו את BasicExample מ-GitHub.

סקירה כללית של IMA DAI

בהטמעת IMA DAI יש ארבעה רכיבים עיקריים של SDK, שמודגשים במדריך הזה:

  • StreamDisplayContainer: אובייקט של מאגר הנמצא מעל לרכיב הפעלת הסרטון וכולל את הרכיבים של ממשק המשתמש של המודעות.
  • AdsLoader: אובייקט שמבקש שידורים ומטפל באירועים שהופעלו על ידי אובייקטים של תגובה לבקשה של מקור נתונים. עליכם ליצור מודעה רק בכלי אחד לטעינת מודעות, ושאפשר להשתמש בו שוב לכל אורך חיי האפליקציה.
  • StreamRequest: אובייקט שמגדיר בקשת שידור. הבקשות לסטרימינג יכולות להיות על פי דרישה (VOD) או בשידור חי. בבקשות מצוין מזהה תוכן, כמו גם מפתח API או אסימון אימות ופרמטרים אחרים.
  • StreamManager: אובייקט שמטפל בסטרימינג דינמי של הטמעת מודעות ובאינטראקציות עם הקצה העורפי של DAI. מנהל השידור גם מטפל בפינגים של מעקב ומעביר אירועים של אירועים ומודעות למפרסם.

דרישות מוקדמות

  • Android Studio
  • האפליקציה של נגן הווידאו לדוגמה שבה תשתמש כדי לשלב את ה-SDK

מורידים ומפעילים את האפליקציה של נגן הווידאו לדוגמה

האפליקציה לדוגמה מספקת נגן וידאו פועל שמפעיל סרטון HLS. השתמשו בו כנקודת ההתחלה לשילוב השילוב של IMA SDK ב-IMA Android.

  1. מורידים את האפליקציה לנגני וידאו לדוגמה ומבטלים את הדחיסה.
  2. מפעילים את Android Studio ובוחרים באפשרות פתיחת פרויקט קיים ב-Android Studio. לחלופין, אם Android Studio כבר פועל, בוחרים באפשרות File > New > Import Project. לאחר מכן, יש לבחור באפשרות SampleVideoPlayer/build.gradle.
  3. מפעילים סנכרון של Gradle בלחיצה על כלים > Android > סנכרון פרויקט עם קובצי Gradle.
  4. מוודאים שאפליקציית הנגן מהדרת ופועלת במכשיר Android פיזי או במכשיר וירטואלי של Android באמצעות הפעלה > הפעלת 'אפליקציה'. הגנת הטעינה של זרם הווידאו נמשכת מספר דקות לפני שהוא מופעל.

בדיקה של נגן הווידאו לדוגמה

נגן הווידאו לדוגמה עדיין לא מכיל קוד שילוב של IMA SDK. האפליקציה לדוגמה כוללת שני חלקים עיקריים:

  • samplevideoplayer/SampleVideoPlayer.java – נגן HLS פשוט המבוסס על ExoPlayer ומשמש כבסיס לשילוב IMA DAI.
  • videoplayerapp/MyActivity.java - פעילות זו יוצרת את נגן הווידאו ומעבירה אותו אל Context ו-SimpleExoPlayerView.

הוספת IMA Android SDK לאפליקציית הנגן

אתם צריכים לכלול גם הפניה ל-IMA SDK. ב-Android Studio, מוסיפים את הטקסט הבא לקובץ build.gradle ברמת האפליקציה, שנמצא בכתובת app/build.gradle:

repositories {
  google()
  jcenter()
}

dependencies {
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'androidx.browser:browser:1.3.0'
    implementation 'com.google.android.exoplayer:exoplayer:2.18.5'
    implementation 'com.google.ads.interactivemedia.v3:interactivemedia:3.30.1'
}

רשימת משימות: האפליקציה שלכם אמורה להיערך ולהציג אותה, אבל עדיין לא הוספתם קוד גישה או רכיבי ממשק משתמש כדי לבקש ולהציג מודעות.

שילוב ה-IMA SDK

  1. עליך ליצור מחלקה חדשה בשם SampleAdsWrapper בחבילה של videoplayerapp (ב-app/java/com.google.ads.interactivemedia.v3.samples/videoplayerapp/) כדי לעטוף את ה-SampleVideoPlayer הקיים ולהוסיף לוגיקה להטמעת IMA מודעה דינמית (DAI). כדי לעשות את זה, קודם צריך ליצור AdsLoader. המזהה הזה ישמש לבקשת מודעות משרתי מודעות.

    videoplayerapp/ExampleAdsWrapper.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 {
    
        // 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 = "2528370";
        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.

    videoplayerapp/ExampleAdsWrapper.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);
                        }
                    }
                });
    
        // Live stream 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 live stream to a VOD stream.
        // StreamRequest request = sdkFactory.createVodStreamRequest(TEST_CONTENT_SOURCE_ID,
        //        TEST_VIDEO_ID, null, displayContainer);
        return request;
    }
    
  3. כדי להפעיל את הסטרימינג צריך גם VideoStreamPlayer, לכן יש להוסיף שיטה createVideoStreamPlayer() שיוצרת כיתה אנונימית שמטמיעה את VideoStreamPlayer.

    videoplayerapp/ExampleAdsWrapper.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());
            }
        };
        return player;
    }
    
  4. מטמיעים את רכיבי ההאזנה הנדרשים ומוסיפים תמיכה לטיפול בשגיאות.

    חשוב: חשוב לשים לב להטמעה של AdErrorListener מכיוון שהיא נקראת כתובת URL לגיבוי, אם המודעות לא מופעלות. מאחר שהתוכן והמודעות מוצגים בשידור אחד, עליכם להיות מוכנים להפעיל שידור חוזר אם תתקבל שגיאה באירוע DAI.

    videoplayerapp/ExampleAdsWrapper.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/ExampleAdsWrapper.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.

    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 מוצגת עכשיו. כדי לשפר את ההטמעה, כדאי לקרוא את המדריכים של Bookmarks ו-Snapback ואת מסמכי התיעוד בנושא API.

פתרון בעיות

אם נתקלת בבעיות בהפעלת מודעת וידאו, כדאי לנסות להוריד את BasicExample המלאה. אם הוא פועל כהלכה ב-BasicExample, סביר להניח שיש בעיה בקוד השילוב של ה-IMA באפליקציה. מומלץ לעיין במדריך הזה ובמסמכי ה-API כדי לזהות אי-התאמות.

עדיין נתקלים בבעיות? שלחו לנו משוב בפורום IMA SDK.