הוספת מודעה

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

הוספת מודעות בצד הלקוח

בהוספת מודעות בצד הלקוח, הנגן עובר בין טעינת מדיה מכתובות URL שונות במהלך המעבר בין הפעלת תוכן למודעות. המידע על המודעות נטען בנפרד מהמדיה, למשל מתג מודעה מסוג VAST או VMAP בפורמט XML. המידע הזה יכול לכלול את מיקומי האותות להצגת מודעות ביחס להתחלת התוכן, את מזהי ה-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 וישתמש בו כדי להוסיף מודעות כפי שהוגדר בתג המודעות של פריט המדיה.

PlayerView של ExoPlayer מוטמע 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);

ספריית IMA של ExoPlayer

ספריית IMA של ExoPlayer מספקת את 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 במקום ב-Google Analytics 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(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(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 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 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 של מודעות או לשרת מודעות.

ה-DefaultMediaSourceFactory של ExoPlayer יכול להעניק את כל המשימות האלה להוספת מודעה בצד השרת 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();

ספריית IMA של ExoPlayer

ספריית IMA DAI ל-ExoPlayer כוללת את 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. הטמעות מותאמות אישית של MediaSource SDK להצגת מודעות יכולות להאזין לאירועי מטא-נתונים מתוזמנים מהנגן באמצעות Player.Listener.onMetadata.