הוספת מודעה

אפשר להשתמש ב-ExoPlayer להוספת מודעות גם בצד הלקוח וגם בצד השרת.

הצגת מודעות בצד הלקוח

בהוספת מודעות בצד הלקוח, הנגן עובר בין טעינת מדיה מכתובות URL שונות כשהוא עובר בין הפעלת תוכן לבין הפעלת מודעות. המידע על המודעות נטען בנפרד מהמדיה, למשל מתג מודעה בפורמט XML‏ VAST או VMAP. המידע הזה יכול לכלול את מיקומי האותות להצגת מודעות ביחס לתחילת התוכן, את כתובות ה-URI של המדיה של המודעות עצמן ואת המטא-נתונים שלהן, למשל אם אפשר לדלג על מודעה מסוימת.

כשמשתמשים ב-AdsMediaSource של ExoPlayer להוספת מודעות בצד הלקוח, לנגן יש מידע על המודעות שיוצגו. יש לזה כמה יתרונות:

  • הנגן יכול לחשוף מטא-נתונים ופונקציונליות שקשורים למודעות באמצעות ה-API שלו.
  • רכיבי ממשק המשתמש של ExoPlayer יכולים להציג סמנים למיקומי מודעות באופן אוטומטי, ולשנות את אופן הפעולה שלהם בהתאם למצב ההפעלה של המודעה.
  • באופן פנימי, הנגן יכול לשמור על מאגר נתונים זמני עקבי במהלך המעברים בין מודעות לתוכן.

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

כשמכינים סרטוני תוכן ותגים של מודעות לשימוש בהוספת מודעות בצד הלקוח, מומלץ למקם את המודעות בדגימות סנכרון (פריים מרכזי) בסרטון התוכן, כדי שהנגן יוכל להמשיך את הפעלת התוכן בצורה חלקה.

תמיכה דקלרטיבית במודעות

אפשר לציין URI של תג מודעה כשיוצרים MediaItem:

Kotlin

val mediaItem =
  MediaItem.Builder()
    .setUri(videoUri)
    .setAdsConfiguration(MediaItem.AdsConfiguration.Builder(adTagUri).build())
    .build()

Java

MediaItem mediaItem =
    new MediaItem.Builder()
        .setUri(videoUri)
        .setAdsConfiguration(new MediaItem.AdsConfiguration.Builder(adTagUri).build())
        .build();

כדי להפעיל תמיכה בנגן עבור פריטי מדיה שבהם מצוינים תגי מודעות, צריך ליצור ולהוסיף אובייקט DefaultMediaSourceFactory שמוגדר עם AdsLoader.Provider ועם AdViewProvider כשיוצרים את הנגן:

Kotlin

val mediaSourceFactory: MediaSource.Factory =
  DefaultMediaSourceFactory(context).setLocalAdInsertionComponents(adsLoaderProvider, playerView)
val player = ExoPlayer.Builder(context).setMediaSourceFactory(mediaSourceFactory).build()

Java

MediaSource.Factory mediaSourceFactory =
    new DefaultMediaSourceFactory(context)
        .setLocalAdInsertionComponents(adsLoaderProvider, /* adViewProvider= */ playerView);
ExoPlayer player =
    new ExoPlayer.Builder(context).setMediaSourceFactory(mediaSourceFactory).build();

באופן פנימי, התג DefaultMediaSourceFactory יעטוף את מקור המדיה של התוכן בתג AdsMediaSource. ה-AdsMediaSource יקבל AdsLoader מה-AdsLoader.Provider וישתמש בו כדי להוסיף מודעות בהתאם להגדרות בתג המודעה של פריט המדיה.

‫ExoPlayer PlayerView מטמיע את AdViewProvider. ספריית ExoPlayer IMA מספקת AdsLoader שקל להשתמש בו, כפי שמתואר בהמשך.

פלייליסטים עם מודעות

כשמפעילים פלייליסט עם כמה פריטי מדיה, התנהגות ברירת המחדל היא לשלוח בקשה לתג המודעה ולאחסן את מצב הפעלת המודעה פעם אחת לכל שילוב של מזהה מדיה, URI של תוכן ו-URI של תג מודעה. כלומר, המשתמשים יראו מודעות לכל פריט מדיה עם מודעות שיש לו מזהה מדיה או URI תוכן ייחודיים, גם אם כתובות ה-URI של תגי המודעות זהות. אם פריט מדיה חוזר על עצמו, המשתמש יראה את המודעות המתאימות רק פעם אחת (מצב ההפעלה של המודעה שומר אם המודעות הופעלו, כך שהן מדולגות אחרי המופע הראשון שלהן).

אפשר להתאים אישית את ההתנהגות הזו על ידי העברת מזהה מודעות אטום שאליו מקושר מצב ההפעלה של מודעה עבור פריט מדיה נתון, על סמך שוויון אובייקטים. בדוגמה הבאה, מצב ההפעלה של המודעה מקושר רק ל-URI של תג המודעה, ולא לשילוב של מזהה המדיה וה-URI של תג המודעה. זאת נעשה על ידי העברת ה-URI של תג המודעה כמזהה המודעות. המשמעות היא שהמודעות ייטענו רק פעם אחת, והמשתמש לא יראה מודעות בפריט השני כשהוא יפעיל את הפלייליסט מההתחלה ועד הסוף.

Kotlin

// Build the media items, passing the same ads identifier for both items,
// which means they share ad playback state so ads play only once.
val firstItem =
  MediaItem.Builder()
    .setUri(firstVideoUri)
    .setAdsConfiguration(MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build())
    .build()
val secondItem =
  MediaItem.Builder()
    .setUri(secondVideoUri)
    .setAdsConfiguration(MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build())
    .build()
player.addMediaItem(firstItem)
player.addMediaItem(secondItem)

Java

// Build the media items, passing the same ads identifier for both items,
// which means they share ad playback state so ads play only once.
MediaItem firstItem =
    new MediaItem.Builder()
        .setUri(firstVideoUri)
        .setAdsConfiguration(
            new MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build())
        .build();
MediaItem secondItem =
    new MediaItem.Builder()
        .setUri(secondVideoUri)
        .setAdsConfiguration(
            new MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build())
        .build();
player.addMediaItem(firstItem);
player.addMediaItem(secondItem);

הוספת מודעות בצד הלקוח בהנחיית השרת

‫ExoPlayer מגיע עם HlsInterstitialsAdsLoader שתומך בהוספה אוטומטית של מודעות שמוגדרות בפלייליסט HLS בצד הלקוח. אפשר לעיין בקטע בנושא HlsInterstitialsAdsLoader בדף בנושא HLS.

ספריית ExoPlayer IMA

ספריית ExoPlayer IMA מספקת ImaAdsLoader, וכך מאפשרת לשלב בקלות הצגת מודעות בצד הלקוח באפליקציה. היא עוטפת את הפונקציונליות של IMA SDK בצד הלקוח כדי לתמוך בהצגת מודעות VAST/VMAP. הוראות לשימוש בספרייה, כולל איך לטפל בהעברה לרקע ובהמשכת ההפעלה, מופיעות בקובץ README.

אפליקציית ההדגמה משתמשת בספריית IMA וכוללת כמה תגי מודעות לדוגמה של VAST/VMAP ברשימת הדוגמאות.

שיקולים לגבי ממשק המשתמש

אפליקציית PlayerView מסתירה את אמצעי השליטה בהעברה שלה במהלך הפעלת מודעות כברירת מחדל, אבל אפליקציות יכולות להפעיל או להשבית את ההתנהגות הזו על ידי קריאה ל-setControllerHideDuringAds. ‫IMA SDK יציג תצוגות נוספות מעל הנגן בזמן הפעלת מודעה (לדוגמה, קישור למידע נוסף ולחצן דילוג, אם רלוונטי).

יכול להיות ש-IMA SDK ידווח אם מודעות מוסתרות על ידי תצוגות שסופקו על ידי האפליקציה, שמוצגות מעל הנגן. אפליקציות שצריכות להציג שכבות-על של תצוגות שחיוניות לשליטה בהפעלה, צריכות לרשום אותן ב-IMA SDK כדי שאפשר יהיה להשמיט אותן מחישובי הניראות. כשמשתמשים ב-PlayerView בתור AdViewProvider, שכבות העל של אמצעי הבקרה שלו נרשמות אוטומטית. אפליקציות שמשתמשות בממשק משתמש מותאם אישית של נגן צריכות לרשום תצוגות שכבת-על על ידי החזרתן מ-AdViewProvider.getAdOverlayInfos.

מידע נוסף על תצוגות שכבת-על זמין במאמר Open Measurement ב-IMA SDK.

מודעות נלוות

חלק מתגי המודעות מכילים מודעות נלוות נוספות שיכולות להופיע ב 'משבצות' בממשק משתמש של אפליקציה. אפשר להעביר את המשבצות האלה באמצעות ImaAdsLoader.Builder.setCompanionAdSlots(slots). מידע נוסף זמין במאמר בנושא הוספת מודעות משלימות.

מודעות עצמאיות

‫IMA SDK מיועד להוספת מודעות לתוכן מדיה, ולא להצגת מודעות עצמאיות. לכן, אין תמיכה בהפעלה של מודעות עצמאיות בספריית IMA. במקרה השימוש הזה, מומלץ להשתמש ב-Google Mobile Ads SDK.

שימוש ב-SDK של צד שלישי להצגת מודעות

אם אתם צריכים לטעון מודעות באמצעות SDK של מודעות מצד שלישי, כדאי לבדוק אם הוא כבר מספק שילוב של ExoPlayer. אם לא, הגישה המומלצת היא להטמיע AdsLoader בהתאמה אישית שעוטפת את ה-SDK של מודעות צד שלישי, כי היא מספקת את היתרונות של AdsMediaSource שמתוארים למעלה. ‫ImaAdsLoader משמש כדוגמה להטמעה.

לחלופין, אפשר להשתמש בתמיכה בפלייליסטים של ExoPlayer כדי ליצור רצף של מודעות וקליפים של תוכן:

Kotlin

// A pre-roll ad.
val preRollAd = MediaItem.fromUri(preRollAdUri)
// The start of the content.
val contentStart =
  MediaItem.Builder()
    .setUri(contentUri)
    .setClippingConfiguration(MediaItem.ClippingConfiguration.Builder().setEndPositionMs(120000).build())
    .build()
// A mid-roll ad.
val midRollAd = MediaItem.fromUri(midRollAdUri)
// The rest of the content
val contentEnd =
  MediaItem.Builder()
    .setUri(contentUri)
    .setClippingConfiguration(MediaItem.ClippingConfiguration.Builder().setStartPositionMs(120000).build())
    .build()

// Build the playlist.
player.addMediaItem(preRollAd)
player.addMediaItem(contentStart)
player.addMediaItem(midRollAd)
player.addMediaItem(contentEnd)

Java

// A pre-roll ad.
MediaItem preRollAd = MediaItem.fromUri(preRollAdUri);
// The start of the content.
MediaItem contentStart =
    new MediaItem.Builder()
        .setUri(contentUri)
        .setClippingConfiguration(
            new MediaItem.ClippingConfiguration.Builder().setEndPositionMs(120_000).build())
        .build();
// A mid-roll ad.
MediaItem midRollAd = MediaItem.fromUri(midRollAdUri);
// The rest of the content
MediaItem contentEnd =
    new MediaItem.Builder()
        .setUri(contentUri)
        .setClippingConfiguration(
            new MediaItem.ClippingConfiguration.Builder().setStartPositionMs(120_000).build())
        .build();

// Build the playlist.
player.addMediaItem(preRollAd);
player.addMediaItem(contentStart);
player.addMediaItem(midRollAd);
player.addMediaItem(contentEnd);

הוספת מודעות בצד השרת

בהטמעת מודעות בצד השרת (שנקראת גם הטמעת מודעות דינמיות, או DAI), זרם המדיה מכיל גם מודעות וגם תוכן. קובץ מניפסט של DASH עשוי להפנות גם לפלחי תוכן וגם לפלחי מודעות, יכול להיות בתקופות נפרדות. במקרה של HLS, אפשר לעיין במסמכי התיעוד של Apple בנושא שילוב מודעות בפלייליסט.

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

‫ExoPlayer DefaultMediaSourceFactory יכול להעביר את כל המשימות האלה להוספת מודעות בצד השרת MediaSource עבור כתובות URI באמצעות סכימת ssai://:

Kotlin

val player =
  ExoPlayer.Builder(context)
    .setMediaSourceFactory(
      DefaultMediaSourceFactory(context).setServerSideAdInsertionMediaSourceFactory(ssaiFactory)
    )
    .build()

Java

Player player =
    new ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            new DefaultMediaSourceFactory(context)
                .setServerSideAdInsertionMediaSourceFactory(ssaiFactory))
        .build();

ספריית ExoPlayer IMA

ספריית ExoPlayer IMA מספקת ImaServerSideAdInsertionMediaSource, מה שמקל על השילוב עם זרמי מודעות שמוכנסים בצד השרת של IMA באפליקציה. היא עוטפת את הפונקציונליות של IMA DAI SDK ל-Android ומשלבת באופן מלא את המטא-נתונים של המודעות שסופקו בנגן. לדוגמה, כך אפשר להשתמש בשיטות כמו Player.isPlayingAd(), להאזין למעברים בין תוכן למודעות ולאפשר לנגן לטפל בלוגיקה של הפעלת מודעות, כמו דילוג על מודעות שכבר הוצגו.

כדי להשתמש בכיתה הזו, צריך להגדיר את ImaServerSideAdInsertionMediaSource.AdsLoader ואת ImaServerSideAdInsertionMediaSource.Factory ולקשר אותם לנגן:

Kotlin

// MediaSource.Factory to load the actual media stream.
val defaultMediaSourceFactory = DefaultMediaSourceFactory(context)
// AdsLoader that can be reused for multiple playbacks.
val adsLoader =
  ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(context, adViewProvider).build()
// MediaSource.Factory to create the ad sources for the current player.
val adsMediaSourceFactory =
  ImaServerSideAdInsertionMediaSource.Factory(adsLoader, defaultMediaSourceFactory)
// Configure DefaultMediaSourceFactory to create both IMA DAI sources and
// regular media sources. If you just play IMA DAI streams, you can also use
// adsMediaSourceFactory directly.
defaultMediaSourceFactory.setServerSideAdInsertionMediaSourceFactory(adsMediaSourceFactory)
// Set the MediaSource.Factory on the Player.
val player = ExoPlayer.Builder(context).setMediaSourceFactory(defaultMediaSourceFactory).build()
// Set the player on the AdsLoader
adsLoader.setPlayer(player)

Java

// MediaSource.Factory to load the actual media stream.
DefaultMediaSourceFactory defaultMediaSourceFactory = new DefaultMediaSourceFactory(context);
// AdsLoader that can be reused for multiple playbacks.
ImaServerSideAdInsertionMediaSource.AdsLoader adsLoader =
    new ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(context, adViewProvider).build();
// MediaSource.Factory to create the ad sources for the current player.
ImaServerSideAdInsertionMediaSource.Factory adsMediaSourceFactory =
    new ImaServerSideAdInsertionMediaSource.Factory(adsLoader, defaultMediaSourceFactory);
// Configure DefaultMediaSourceFactory to create both IMA DAI sources and
// regular media sources. If you just play IMA DAI streams, you can also use
// adsMediaSourceFactory directly.
defaultMediaSourceFactory.setServerSideAdInsertionMediaSourceFactory(adsMediaSourceFactory);
// Set the MediaSource.Factory on the Player.
Player player =
    new ExoPlayer.Builder(context).setMediaSourceFactory(defaultMediaSourceFactory).build();
// Set the player on the AdsLoader
adsLoader.setPlayer(player);

כדי לטעון את מפתח הנכס של IMA, או את מזהה מקור התוכן ומזהה הסרטון, צריך ליצור כתובת URL עם ImaServerSideAdInsertionUriBuilder:

Kotlin

val ssaiUri =
  ImaServerSideAdInsertionUriBuilder()
    .setAssetKey(assetKey)
    .setFormat(C.CONTENT_TYPE_HLS)
    .build()
player.setMediaItem(MediaItem.fromUri(ssaiUri))

Java

Uri ssaiUri =
    new ImaServerSideAdInsertionUriBuilder()
        .setAssetKey(assetKey)
        .setFormat(C.CONTENT_TYPE_HLS)
        .build();
player.setMediaItem(MediaItem.fromUri(ssaiUri));

לבסוף, משחררים את הכלי לטעינת מודעות כשמפסיקים להשתמש בו:

Kotlin

adsLoader.release()

Java

adsLoader.release();

שיקולים לגבי ממשק המשתמש

שיקולי הממשק המשתמש שרלוונטיים להוספת מודעות בצד הלקוח רלוונטיים גם להוספת מודעות בצד השרת.

מודעות נלוות

חלק מתגי המודעות מכילים מודעות נלוות נוספות שיכולות להופיע ב 'משבצות' בממשק משתמש של אפליקציה. אפשר להעביר את המשבצות האלה באמצעות ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setCompanionAdSlots(slots). מידע נוסף זמין במאמר בנושא הוספת מודעות משלימות.

שימוש ב-SDK של צד שלישי להצגת מודעות

אם אתם צריכים לטעון מודעות באמצעות SDK של מודעות מצד שלישי, כדאי לבדוק אם הוא כבר מספק שילוב של ExoPlayer. אם לא, מומלץ לספק MediaSource מותאם אישית שמקבל מזהי URI עם סכימת ssai:// בדומה ל-ImaServerSideAdInsertionMediaSource.

הלוגיקה בפועל של יצירת מבנה המודעה יכולה להיות מוקצית ל-ServerSideAdInsertionMediaSource למטרה כללית, שעוטף זרם MediaSource ומאפשר למשתמש להגדיר ולעדכן את AdPlaybackState שמייצג את המטא-נתונים של המודעה.

לרוב, זרמי מודעות שמוכנסים בצד השרת מכילים אירועים מתוזמנים כדי להודיע לצופה על מטא-נתונים של המודעות. במאמר פורמטים נתמכים מפורט מידע על פורמטים של מטא-נתונים עם חותמות זמן שנתמכים על ידי ExoPlayer. הטמעות של SDK מותאם אישית להצגת מודעות MediaSource יכולות להאזין לאירועים של מטא-נתונים מתוזמנים מהנגן באמצעות Player.Listener.onMetadata.