במדריך הזה מוסבר למפתחים איך לשלב את תוכן הווידאו המומלץ שלהם באמצעות Engage SDK, כדי לאכלס המלצות בממשקים שונים של Google, כמו טלוויזיה, נייד וטאבלט.
התכונה 'המלצות' משתמשת באוסף ההמלצות כדי להציג סרטים ותוכניות טלוויזיה מכמה אפליקציות בקבוצה אחת בממשק המשתמש. כל שותף פיתוח יכול לשדר עד 25 ישויות בכל אשכול המלצות, ויכולים להיות עד 7 אשכולות המלצות בכל בקשה.
עבודה מקדימה
לפני שמתחילים, צריך לבצע את השלבים הבאים. 1. מוודאים שהאפליקציה מטרגטת רמת API 19 ומעלה לשילוב הזה.
להוסיף את ספריית
com.google.android.engageלאפליקציה.יש ערכות SDK נפרדות שמשמשות לאינטגרציה: אחת לאפליקציות לנייד ואחת לאפליקציות לטלוויזיה.
לנייד
dependencies { implementation 'com.google.android.engage:engage-core:1.5.9 }לטלוויזיה
dependencies { implementation 'com.google.android.engage:engage-tv:1.0.5 }מגדירים את סביבת השירות של Engage כסביבת ייצור בקובץ
AndroidManifest.xml.ל-APK לנייד
<meta-data android:name="com.google.android.engage.service.ENV" android:value="PRODUCTION"> </meta-data>ל-tv apk
<meta-data android:name="com.google.android.engage.service.ENV" android:value="PRODUCTION"> </meta-data>הפעלת פרסום בשירות שפועל בחזית.
פרסום נתוני ההמלצות מתבצע פעם ביום לכל היותר, והוא מופעל על ידי אחד מהאירועים הבאים:
- הכניסה הראשונה של המשתמש ביום. (או)
- כשהמשתמש מתחיל אינטראקציה עם האפליקציה.
שילוב
AppEngagePublishClient מפרסם את קבוצת ההמלצות. משתמשים ב-publishRecommendationClusters method כדי לפרסם אובייקט המלצות.
משתמשים ב-isServiceAvailable()2 כדי לבדוק אם השירות זמין לשילוב.
val client = AppEngagePublishClient(context)
client.isServiceAvailable().addOnCompleteListener { task ->
if (task.isSuccessful) {
// Handle IPC call success
if(task.result) {
// Service is available on the device, proceed with content publish
// calls.
client.publishRecommendationClusters(recommendationRequest)
} else {
// Service is not available
}
} else {
// The IPC call itself fails, proceed with error handling logic here,
// such as retry.
}
}
קבוצות של המלצות ובקשה לפרסום
אשכולות הם קיבוץ לוגי של הישויות. בדוגמאות הקוד הבאות מוסבר איך ליצור את האשכולות בהתאם להעדפות שלכם ואיך ליצור בקשת פרסום לכל האשכולות.
// cluster for popular movies
val recommendationCluster1 = RecommendationCluster
.Builder()
.addEntity(movie1)
.addEntity(movie2)
.addEntity(movie3)
.addEntity(movie4)
.addEntity(tvShow)
// This cluster is meant to be used as an individual provider row
.setRecommendationClusterType(TYPE_PROVIDER_ROW)
.setTitle("Popular Movies")
.build()
// cluster for live TV programs
val recommendationCluster2 = RecommendationCluster
.Builder()
.addEntity(liveTvProgramEntity1)
.addEntity(liveTvProgramEntity2)
.addEntity(liveTvProgramEntity3)
.addEntity(liveTvProgramEntity4)
.addEntity(liveTvProgramEntity5)
// This cluster is meant to be used as an individual provider row
.setRecommendationClusterType(TYPE_PROVIDER_ROW)
.setTitle("Popular Live TV Programs")
.build()
// creating a publishing request
val recommendationRequest = PublishRecommendationClustersRequest
.Builder()
.setSyncAcrossDevices(true)
.setAccountProfile(accountProfile)
.addRecommendationCluster(recommendationCluster1)
.addRecommendationCluster(recommendationCluster2)
.build()
יצירת פרופיל בחשבון
כדי לאפשר חוויה מותאמת אישית ב-Google TV, צריך לספק פרטים על החשבון והפרופיל. אפשר להשתמש ב-AccountProfile כדי לספק:
- מזהה חשבון: מזהה ייחודי שמייצג את החשבון של המשתמש באפליקציה. יכול להיות שזה מזהה החשבון בפועל או גרסה מוסתרת מתאימה.
- מזהה פרופיל (אופציונלי): אם האפליקציה תומכת בכמה פרופילים בחשבון יחיד, צריך לספק מזהה ייחודי לפרופיל המשתמש הספציפי.
- לוקאל(אופציונלי): אתם יכולים לציין את השפה המועדפת של המשתמש.
השדה הזה שימושי אם אתם שולחים
MediaActionFeedEntityבRecommendationRequest.
// If app only supports account
val accountProfile = AccountProfile.Builder()
.setAccountId("account_id")
.build();
// If app supports both account and profile
val accountProfile = AccountProfile.Builder()
.setAccountId("account_id")
.setProfileId("profile_id")
.build();
// set Locale
val accountProfile = AccountProfile.Builder()
.setAccountId("account_id")
.setProfileId("profile_id")
.setLocale("en-US")
.build();
כשהשירות מקבל את הבקשה, הפעולות הבאות מתבצעות במסגרת עסקה אחת:
- הנתונים הקיימים של
RecommendationsClusterמשותף המפתחים יוסרו. - הנתונים מהבקשה מנותחים ומאוחסנים ב-
RecommendationsClusterהמעודכן. במקרה של שגיאה, הבקשה כולה נדחית והמצב הקיים נשמר.
סנכרון בין מכשירים
הדגל SyncAcrossDevices קובע אם נתוני קבוצת ההמלצות של המשתמש ישותפו עם Google TV ויהיו זמינים במכשירים שלו, כמו טלוויזיה, טלפון וטאבלטים. כדי שההמלצה תפעל, צריך להגדיר את הערך שלה כ-true.
קבלת הסכמה
אפליקציית המדיה צריכה לספק הגדרה ברורה להפעלה או להשבתה של סנכרון בין מכשירים, להסביר למשתמש את היתרונות של ההגדרה ולאחסן את ההעדפה שלו פעם אחת, ואז להחיל אותה ב-publishRecommendations Request בהתאם. כדי להפיק את המרב מהתכונה למעקב המרות בכמה מכשירים, צריך לוודא שהאפליקציה מקבלת את הסכמת המשתמשים ומפעילה את האפשרות SyncAcrossDevices כדי true.
מחיקת נתוני הגילוי של הסרטון
כדי למחוק באופן ידני את נתוני המשתמש מהשרת של Google TV לפני תקופת השמירה הרגילה של 60 יום, משתמשים בשיטה client.deleteClusters(). כשמתקבלת הבקשה, השירות מוחק את כל הנתונים הקיימים של גילוי סרטונים בפרופיל החשבון או בכל החשבון.
ה-enum DeleteReason מגדיר את הסיבה למחיקת הנתונים.
הקוד הבא מסיר את ההמלצות אחרי התנתקות.
// If the user logs out from your media app, you must make the following call
// to remove recommendations data from the current google TV device,
// otherwise, the recommendations data persists on the current
// google TV device until 60 days later.
client.deleteClusters(
new DeleteClustersRequest.Builder()
.setAccountProfile(AccountProfile())
.setReason(DeleteReason.DELETE_REASON_USER_LOG_OUT)
.build()
)
// If the user revokes the consent to share data with Google TV,
// you must make the following call to remove recommendations data from
// all current google TV devices. Otherwise, the recommendations data persists
// until 60 days later.
client.deleteClusters(
new DeleteClustersRequest.Builder()
.setAccountProfile(AccountProfile())
.setReason(DeleteReason.DELETE_REASON_LOSS_OF_CONSENT)
.build()
)
יצירת ישויות
ב-SDK מוגדרות ישויות שונות שמייצגות כל סוג פריט. הישויות הבאות נתמכות באשכול ההמלצות:
MediaActionFeedEntityMovieEntityTvShowEntityLiveTvChannelEntityLiveTvProgramEntity
תיאור
מוסיפים תיאור קצר לכל ישות. התיאור הזה יוצג כשמשתמשים יעבירו את העכבר מעל הישות, ויספק להם פרטים נוספים.
מזהי URI להפעלה שספציפיים לפלטפורמה
יוצרים כתובות URI להפעלה לכל פלטפורמה נתמכת: Android TV, Android או iOS. כך המערכת יכולה לבחור את ה-URI המתאים להפעלת הווידאו בפלטפורמה הרלוונטית.
במקרה הנדיר שבו כתובות ה-URI של ההפעלה זהות בכל הפלטפורמות, חוזרים על הפעולה לכל פלטפורמה.
// Required. Set this when you want recommended entities to show up on
// Google TV
val playbackUriTv = PlatformSpecificUri
.Builder()
.setPlatformType(PlatformType.TYPE_ANDROID_TV)
.setActionUri(Uri.parse("https://www.example.com/entity_uri_for_tv"))
.build()
// Optional. Set this when you want recommended entities to show up on
// Google TV Android app
val playbackUriAndroid = PlatformSpecificUri
.Builder()
.setPlatformType(PlatformType.TYPE_ANDROID_MOBILE)
.setActionUri(Uri.parse("https://www.example.com/entity_uri_for_android"))
.build()
// Optional. Set this when you want recommended entities to show up on
// Google TV iOS app
val playbackUriIos = PlatformSpecificUri
.Builder()
.setPlatformType(PlatformType.TYPE_IOS)
.setActionUri(Uri.parse("https://www.example.com/entity_uri_for_ios"))
.build()
val platformSpecificPlaybackUris =
Arrays.asList(playbackUriTv, playbackUriAndroid, playbackUriIos)
// Provide appropriate rating for the system.
val contentRating = new RatingSystem
.Builder()
.setAgencyName("MPAA")
.setRating("PG-13")
.build()
תמונות פוסטר
תמונות של פוסטרים צריכות לכלול URI ומידות בפיקסלים (גובה ורוחב). כדי להתאים את התוכן למכשירים שונים, כדאי לספק כמה תמונות פוסטר. עם זאת, חשוב לוודא שלכל התמונות יש יחס גובה-רוחב של 16:9 וגובה מינימלי של 200 פיקסלים, כדי שהישות 'המלצות' תוצג בצורה נכונה, במיוחד בחבילת הבידור של Google. יכול להיות שלא יוצגו תמונות שהגובה שלהן קטן מ-200 פיקסלים.
Image image1 = new Image.Builder()
.setImageUri(Uri.parse("http://www.example.com/entity_image1.png");)
.setImageHeightInPixel(300)
.setImageWidthInPixel(169)
.build()
Image image2 = new Image.Builder()
.setImageUri(Uri.parse("http://www.example.com/entity_image2.png");)
.setImageHeightInPixel(640)
.setImageWidthInPixel(360)
.build()
// And other images for different form factors.
val images = Arrays.asList(image1, image2)
הסיבה להמלצה
אפשר גם לספק סיבה להמלצה, ש-Google TV יכולה להשתמש בה כדי להסביר למשתמש למה כדאי לו לצפות בסרט או בתוכנית טלוויזיה ספציפיים.
//Allows us to construct reason: "Because it is top 10 on your Channel"
val topOnPartner = RecommendationReasonTopOnPartner
.Builder()
.setNum(10) //any valid integer value
.build()
//Allows us to construct reason: "Because it is popular on your Channel"
val popularOnPartner = RecommendationReasonPopularOnPartner
.Builder()
.build()
//Allows us to construct reason: "New to your channel, or Just added"
val newOnPartner = RecommendationReasonNewOnPartner
.Builder()
.build()
//Allows us to construct reason: "Because you watched Star Wars"
val watchedSimilarTitles = RecommendationReasonWatchedSimilarTitles
.addSimilarWatchedTitleName("Movie or TV Show Title")
.addSimilarWatchedTitleName("Movie or TV Show Title")
.Builder()
.build()
//Allows us to construct reason: "Recommended for you by ChannelName"
val recommendedForUser = RecommendationReasonRecommendedForUser
.Builder()
.build()
val watchAgain = RecommendationReasonWatchAgain
.Builder()
.build()
val fromUserWatchList = RecommendationReasonFromUserWatchlist
.Builder()
.build()
val userLikedOnPartner = RecommendationReasonUserLikedOnPartner
.Builder()
.setTitleName("Movie or TV Show Title")
.build()
val generic = RecommendationReasonGeneric.Builder().build()
הצגת חלון זמן
אם ישות צריכה להיות זמינה רק לזמן מוגבל, צריך להגדיר זמן תפוגה מותאם אישית. אם לא מציינים זמן תפוגה מפורש, התוקף של הישויות יפוג והן יימחקו באופן אוטומטי אחרי 60 ימים. לכן, מגדירים זמן תפוגה רק אם רוצים שהישויות יפוגו מוקדם יותר. אפשר לציין כמה חלונות זמינות כאלה.
val window1 = DisplayTimeWindow
.Builder()
.setStartTimeStampMillis(now()+ 1.days.toMillis())
.setEndTimeStampMillis(now()+ 30.days.toMillis())
val window2 = DisplayTimeWindow
.Builder()
.setEndTimeStampMillis(now()+ 30.days.toMillis())
val availabilityTimeWindows: List<DisplayTimeWindow> = listof(window1,window2)
DataFeedElementId
אם שילבתם את קטלוג המדיה או את פיד פעולות המדיה עם Google TV, לא צריך ליצור ישויות נפרדות לסרט או לתוכנית טלוויזיה. במקום זאת, אפשר ליצור ישות MediaActionFeed שכוללת את השדה הנדרש DataFeedElementId. המזהה הזה צריך להיות ייחודי ולהתאים למזהה בפיד פעולות המדיה, כי הוא עוזר לזהות תוכן פיד שהועלה ולבצע חיפושים של תוכן מדיה.
val id = "dataFeedEleemntId"
MovieEntity
דוגמה ליצירת MovieEntity עם כל שדות החובה:
val movieEntity = MovieEntity.Builder()
.setName("Movie name")
.setDescription("A sentence describing movie.")
.addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
.addPosterImages(images)
// Suppose the duration is 2 hours, it is 72000000 in milliseconds
.setDurationMills(72000000)
.build()
אתם יכולים לספק נתונים נוספים כמו ז'אנרים, סיווגי תוכן, תאריך יציאה לאקרנים, סיבת המלצה וחלונות זמן של זמינות. יכול להיות ש-Google TV תשתמש בנתונים האלה כדי לשפר את התצוגה או לצורך סינון.
val genres = Arrays.asList("Action", "Science fiction");
val rating1 = RatingSystem.Builder().setAgencyName("MPAA").setRating("pg-13").build();
val contentRatings = Arrays.asList(rating1);
//Suppose release date is 11-02-2025
val releaseDate = 1739233800000L
val movieEntity = MovieEntity.Builder()
...
.addGenres(genres)
.setReleaseDateEpochMillis(releaseDate)
.addContentRatings(contentRatings)
.setRecommendationReason(topOnPartner or watchedSimilarTitles)
.addAllAvailabilityTimeWindows(availabilityTimeWindows)
.build()
TvShowEntity
דוגמה ליצירת TvShowEntity עם כל שדות החובה:
val tvShowEntity = TvShowEntity.Builder()
.setName("Show title")
.setDescription("A sentence describing TV Show.")
.addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
.addPosterImages(images)
.build();
אפשר גם לספק נתונים נוספים כמו ז'אנרים, סיווגי תוכן, סיבת ההמלצה, מחיר המבצע, מספר העונות או חלון הזמן של הזמינות. יכול להיות ש-Google TV תשתמש בנתונים האלה כדי לשפר את התצוגה או למטרות סינון.
val genres = Arrays.asList("Action", "Science fiction");
val rating1 = RatingSystem.Builder()
.setAgencyName("MPAA")
.setRating("pg-13")
.build();
val price = Price.Builder()
.setCurrentPrice("$14.99")
.setStrikethroughPrice("$16.99")
.build();
val contentRatings = Arrays.asList(rating1);
val seasonCount = 5;
val tvShowEntity = TvShowEntity.Builder()
...
.addGenres(genres)
.addContentRatings(contentRatings)
.setRecommendationReason(topOnPartner or watchedSimilarTitles)
.addAllAvailabilityTimeWindows(availabilityTimeWindows)
.setSeasonCount(seasonCount)
.setPrice(price)
.build()
MediaActionFeedEntity
דוגמה ליצירת MediaActionFeedEntity עם כל השדות הנדרשים:
val mediaActionFeedEntity = MediaActionFeedEntity.Builder()
.setDataFeedElementId(id)
.build()
אפשר לספק נתונים נוספים כמו תיאור, סיבת ההמלצה וחלון הזמן לתצוגה. יכול להיות ש-Google TV תשתמש בנתונים האלה כדי לשפר את התצוגה או למטרות סינון.
val mediaActionFeedEntity = MediaActionFeedEntity.Builder()
.setName("Movie name or TV Show name")
.setDescription("A sentence describing an entity")
.setRecommendationReason(topOnPartner or watchedSimilarTitles)
.addPosterImages(images)
.build()
LiveTvChannelEntity
הסמל הזה מייצג ערוץ טלוויזיה בשידור חי. דוגמה ליצירת תג LiveTvChannelEntity עם כל שדות החובה:
val liveTvChannelEntity = LiveTvChannelEntity.Builder()
.setName("Channel Name")
// ID of the live TV channel
.setEntityId("https://www.example.com/channel/12345")
.setDescription("A sentence describing this live TV channel.")
// channel playback uri must contain at least PlatformType.TYPE_ANDROID_TV
.addPlatformSpecificPlaybackUri(channelPlaybackUris)
.addLogoImage(logoImage)
.build()
אפשר גם לספק נתונים נוספים כמו סיווגי תוכן או סיבת ההמלצה.
val rating1 = RatingSystem.Builder()
.setAgencyName("MPAA")
.setRating("pg-13")
.build()
val contentRatings = Arrays.asList(rating1)
val liveTvChannelEntity = LiveTvChannelEntity.Builder()
...
.addContentRatings(contentRatings)
.setRecommendationReason(topOnPartner)
.build()
LiveTvProgramEntity
הכרטיס הזה מייצג תוכנית טלוויזיה בשידור חי שמשודרת או מתוכננת לשידור בערוץ טלוויזיה בשידור חי. דוגמה ליצירת LiveTvProgramEntity
עם כל שדות החובה:
val liveTvProgramEntity = LiveTvProgramEntity.Builder()
// First set the channel information
.setChannelName("Channel Name")
.setChanelId("https://www.example.com/channel/12345")
// channel playback uri must contain at least PlatformType.TYPE_ANDROID_TV
.addPlatformSpecificPlaybackUri(channelPlaybackUris)
.setChannelLogoImage(channelLogoImage)
// Then set the program or card specific information.
.setName("Program Name")
.setEntityId("https://www.example.com/schedule/123")
.setDescription("Program Desccription")
.addAvailabilityTimeWindow(
DisplayTimeWindow.Builder()
.setStartTimestampMillis(1756713600000L)// 2025-09-01T07:30:00+0000
.setEndTimestampMillis(1756715400000L))// 2025-09-01T08:00:00+0000
.addPosterImage(programImage)
.build()
אפשר לספק נתונים נוספים כמו סיווגי תוכן, ז'אנרים או סיבה להמלצה.
val rating1 = RatingSystem.Builder()
.setAgencyName("MPAA")
.setRating("pg-13")
.build()
val contentRatings = Arrays.asList(rating1)
val genres = Arrays.asList("Action", "Science fiction")
val liveTvProgramEntity = LiveTvProgramEntity.Builder()
...
.addContentRatings(contentRatings)
.addGenres(genres)
.setRecommendationReason(topOnPartner)
.build()
אם המפתחים יפעלו לפי השלבים האלה, הם יוכלו לשלב בהצלחה המלצות לתוכן וידאו ב-Google TV, לשפר את חוויית הגילוי והמעורבות של המשתמשים ולספק להם חוויית צפייה עקבית ומותאמת אישית בכל המכשירים שלהם.