يحتوي هذا الدليل على تعليمات للمطوّرين لدمج محتوى الفيديو المقترَح باستخدام Engage SDK، وذلك لملء تجارب الاقتراحات على جميع مساحات عرض Google، مثل التلفزيون والأجهزة الجوّالة والأجهزة اللوحية.
تستفيد ميزة الاقتراحات من مجموعة الاقتراحات لعرض الأفلام والبرامج التلفزيونية من تطبيقات متعددة في مجموعة واحدة ضمن واجهة المستخدم. يمكن لكل شريك مطوّر بث 25 عنصرًا كحد أقصى في كل مجموعة اقتراحات، ويمكن أن يكون هناك 7 مجموعات اقتراحات كحد أقصى لكل طلب.
العمل التحضيري
قبل البدء، أكمِل الخطوات التالية. 1. تأكَّد من أنّ تطبيقك يستهدف المستوى 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>For tv apk
<meta-data android:name="com.google.android.engage.service.ENV" android:value="PRODUCTION"> </meta-data>تنفيذ عملية النشر على خدمة تعمل في المقدّمة
نشر بيانات "الاقتراحات" مرة واحدة يوميًا كحدّ أقصى، ويتم ذلك عند استيفاء أحد الشرطين التاليين:
- أول تسجيل دخول للمستخدم في اليوم (أو)
- عندما يبدأ المستخدم التفاعل مع التطبيق
التكامل
تنشر AppEngagePublishClient مجموعة الاقتراحات. استخدِم طريقة publishRecommendationClusters لنشر عنصر اقتراحات.
استخدِم 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 وإتاحتها على جميع أجهزته، مثل التلفزيون والهاتف والأجهزة اللوحية. لكي يعمل الاقتراح، يجب ضبطه على "صحيح".
الحصول على الموافقة
يجب أن يوفّر تطبيق الوسائط إعدادًا واضحًا لتفعيل المزامنة على الأجهزة أو إيقافها. اشرح للمستخدم المزايا التي سيحصل عليها، واحفظ خياره المفضّل مرة واحدة وطبِّقه في publishRecommendations Request وفقًا لذلك. للاستفادة إلى أقصى حدّ من ميزة "العمل على عدة أجهزة"، عليك التأكّد من أنّ التطبيق يحصل على موافقة المستخدم ويسمح SyncAcrossDevices true.
حذف بيانات "الفيديوهات المقترَحة"
لحذف بيانات المستخدم يدويًا من خادم Google TV قبل فترة الاحتفاظ العادية البالغة 60 يومًا، استخدِم طريقة client.deleteClusters(). عند تلقّي الطلب، تحذف الخدمة جميع بيانات اكتشاف الفيديوهات الحالية الخاصة بملف الحساب أو الحساب بأكمله.
يحدّد تعداد 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) للتشغيل متطابقة على جميع المنصات، كرِّرها لكل منصة.
// 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، ما يعزّز إمكانية عثور المستخدمين على المحتوى وتفاعلهم معه، ويوفّر تجربة مشاهدة متسقة ومخصّصة للمستخدمين على جميع أجهزتهم.