אפשר להשתמש ב-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 וישתמש בו כדי להוסיף מודעות, כפי שמוגדר בתג המודעה של קובץ המדיה.
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);
הוספת מודעות בצד הלקוח בהנחיית השרת
ExoPlayer כולל HlsInterstitialsAdsLoader שתומך בהוספה אוטומטית של מודעות שמוגדרות בפלייליסט של HLS בצד הלקוח. מידע נוסף זמין בקטע על HlsInterstitialsAdsLoader בדף HLS.
ספריית IMA של ExoPlayer
ספריית 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 להצגת מודעות או לשרת מודעות.
ה-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
ספריית 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.