مسیر_کتاب: /distribute/other-docs/_book.yaml مسیر_پروژه: /distribute/other-docs/_project.yaml
این راهنما نحوه ادغام قابلیت Continue Watching را در برنامه Android TV شما با استفاده از Engage SDK پوشش میدهد.
پیش کار
دستورالعملهای پیش از کار را در راهنمای شروع به کار تکمیل کنید.
ادغام
ایجاد موجودیتها
SDK برای نمایش هر نوع آیتم، موجودیتهای مختلفی تعریف کرده است. کلاستر Continuation از موجودیتهای زیر پشتیبانی میکند:
URI های مخصوص پلتفرم و تصاویر پوستر را برای این موجودیتها مشخص کنید.
همچنین، اگر قبلاً URI های پخش را برای هر پلتفرم - مانند Android TV، Android یا iOS - ایجاد نکردهاید، این کار را انجام دهید. بنابراین وقتی کاربر به تماشای خود در هر پلتفرم ادامه میدهد، برنامه از یک URI پخش هدفمند برای پخش محتوای ویدیو استفاده میکند.
// Required. Set this when you want continue watching 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()
// Required. Set this when you want continue watching entities to show up on
// Google TV Android app, Entertainment Space, Playstore Widget
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 continue watching 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)
تصاویر پوستر به یک URI و ابعاد پیکسلی (ارتفاع و عرض) نیاز دارند. با ارائه چندین تصویر پوستر، فاکتورهای فرم مختلف را هدف قرار دهید، اما تأیید کنید که همه تصاویر نسبت ابعاد ۱۶:۹ و حداقل ارتفاع ۲۰۰ پیکسل را برای نمایش صحیح موجودیت «ادامه تماشا» حفظ میکنند، به خصوص در فضای سرگرمی گوگل. تصاویری با ارتفاع کمتر از ۲۰۰ پیکسل ممکن است نمایش داده نشوند.
val images = Arrays.asList(
Image.Builder()
.setImageUri(Uri.parse("http://www.example.com/entity_image1.png"))
.setImageHeightInPixel(300)
.setImageWidthInPixel(169)
.build(),
Image.Builder()
.setImageUri(Uri.parse("http://www.example.com/entity_image2.png"))
.setImageHeightInPixel(640)
.setImageWidthInPixel(360)
.build()
// Consider adding other images for different form factors
)
نهاد فیلم
این مثال نحوه ایجاد یک MovieEntity با تمام فیلدهای مورد نیاز را نشان میدهد:
val movieEntity = MovieEntity.Builder()
.setWatchNextType(WatchNextType.TYPE_CONTINUE)
.setName("Movie name")
.addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
.addPosterImages(images)
// Timestamp in millis for sample last engagement time 12/1/2023 00:00:00
.setLastEngagementTimeMillis(1701388800000)
// Suppose the duration is 2 hours, it is 72000000 in milliseconds
.setDurationMills(72000000)
// Suppose last playback offset is 1 hour, 36000000 in milliseconds
.setLastPlayBackPositionTimeMillis(36000000)
.build()
ارائه جزئیاتی مانند ژانرها و رتبهبندی محتوا به گوگل تیوی این قدرت را میدهد که محتوای شما را به روشهای پویاتری نمایش دهد و آن را با بینندگان مناسب مرتبط کند.
val genres = Arrays.asList("Action", "Science fiction")
val rating1 = RatingSystem.Builder().setAgencyName("MPAA").setRating("PG-13").build()
val contentRatings = Arrays.asList(rating1)
val movieEntity = MovieEntity.Builder()
...
.addGenres(genres)
.addContentRatings(contentRatings)
.build()
موجودیتها بهطور خودکار به مدت ۶۰ روز در دسترس باقی میمانند، مگر اینکه زمان انقضای کوتاهتری را تعیین کنید. فقط در صورتی که نیاز دارید موجودیت قبل از این دوره پیشفرض حذف شود، یک انقضای سفارشی تنظیم کنید.
// Set the expiration time to be now plus 30 days in milliseconds
val expirationTime = DisplayTimeWindow.Builder()
.setEndTimestampMillis(now().toMillis()+2592000000).build()
val movieEntity = MovieEntity.Builder()
...
.addAvailabilityTimeWindow(expirationTime)
.build()
نهاد اپیزود تلویزیونی
این مثال نحوه ایجاد یک TvEpisodeEntity با تمام فیلدهای مورد نیاز را نشان میدهد:
val tvEpisodeEntity = TvEpisodeEntity.Builder()
.setWatchNextType(WatchNextType.TYPE_CONTINUE)
.setName("Episode name")
.addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
.addPosterImages(images)
// Timestamp in millis for sample last engagement time 12/1/2023 00:00:00
.setLastEngagementTimeMillis(1701388800000)
.setDurationMills(72000000) // 2 hours in milliseconds
// 45 minutes and 15 seconds in milliseconds is 2715000
.setLastPlayBackPositionTimeMillis(2715000)
.setEpisodeNumber("2")
.setSeasonNumber("1")
.setShowTitle("Title of the show")
.build()
رشته شماره قسمت (مانند "2" ) و رشته شماره فصل (مانند "1" ) قبل از نمایش در کارت ادامه تماشا، به شکل مناسب بسط داده میشوند. توجه داشته باشید که آنها باید یک رشته عددی باشند، "e2" یا "episode 2" یا "s1" یا "season 1" را قرار ندهید.
اگر یک برنامه تلویزیونی خاص فقط یک فصل دارد، شماره فصل را ۱ تنظیم کنید.
برای به حداکثر رساندن شانس بینندگان برای یافتن محتوای شما در Google TV، ارائه دادههای اضافی مانند ژانرها، رتبهبندی محتوا و بازههای زمانی در دسترس بودن را در نظر بگیرید، زیرا این جزئیات میتوانند گزینههای نمایش و فیلتر را بهبود بخشند.
val genres = Arrays.asList("Action", "Science fiction")
val rating1 = RatingSystem.Builder().setAgencyName("MPAA").setRating("PG-13").build()
val contentRatings = Arrays.asList(rating1)
val tvEpisodeEntity = TvEpisodeEntity.Builder()
...
.addGenres(genres)
.addContentRatings(contentRatings)
.setSeasonTitle("Season Title")
.setShowTitle("Show Title")
.build()
نهاد ویدئوکلیپ
در اینجا مثالی از ایجاد یک VideoClipEntity با تمام فیلدهای مورد نیاز آورده شده است.
VideoClipEntity یک کلیپ تولید شده توسط کاربر مانند یک ویدیوی یوتیوب را نشان میدهد.
val videoClipEntity = VideoClipEntity.Builder()
.setPlaybackUri(Uri.parse("https://www.example.com/uri_for_current_platform"))
.setWatchNextType(WatchNextType.TYPE_CONTINUE)
.setName("Video clip name")
.addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
.addPosterImages(images)
// Timestamp in millis for sample last engagement time 12/1/2023 00:00:00
.setLastEngagementTimeMillis(1701388800000)
.setDurationMills(600000) //10 minutes in milliseconds
.setLastPlayBackPositionTimeMillis(300000) //5 minutes in milliseconds
.addContentRating(contentRating)
.build()
شما میتوانید به صورت اختیاری خالق، تصویر خالق، زمان ایجاد شده بر حسب میلیثانیه یا بازه زمانی در دسترس بودن را تنظیم کنید.
نهاد پخش زنده ویدیویی
در اینجا مثالی از ایجاد یک LiveStreamingVideoEntity با تمام فیلدهای مورد نیاز آورده شده است.
val liveStreamingVideoEntity = LiveStreamingVideoEntity.Builder()
.setPlaybackUri(Uri.parse("https://www.example.com/uri_for_current_platform"))
.setWatchNextType(WatchNextType.TYPE_CONTINUE)
.setName("Live streaming name")
.addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
.addPosterImages(images)
// Timestamp in millis for sample last engagement time 12/1/2023 00:00:00
.setLastEngagementTimeMillis(1701388800000)
.setDurationMills(72000000) //2 hours in milliseconds
.setLastPlayBackPositionTimeMillis(36000000) //1 hour in milliseconds
.addContentRating(contentRating)
.build()
به صورت اختیاری، میتوانید زمان شروع، پخشکننده، نماد پخشکننده یا بازه زمانی در دسترس بودن را برای موجودیت پخش زنده تنظیم کنید.
برای اطلاعات دقیق در مورد ویژگیها و الزامات، به مرجع API مراجعه کنید.
ارائه دادههای خوشهبندی ادامهدار
AppEngagePublishClient مسئول انتشار کلاستر Continuation است. شما از متد publishContinuationCluste برای انتشار یک شیء ContinuationCluster استفاده میکنید.
حتماً کلاینت را راهاندازی اولیه کنید و همانطور که در راهنمای شروع به کار توضیح داده شده است، در دسترس بودن سرویس را بررسی کنید.
client.publishContinuationCluster(
PublishContinuationClusterRequest
.Builder()
.setContinuationCluster(
ContinuationCluster.Builder()
.setAccountProfile(accountProfile)
.addEntity(movieEntity1)
.addEntity(movieEntity2)
.addEntity(tvEpisodeEntity1)
.addEntity(tvEpisodeEntity2)
.setSyncAcrossDevices(true)
.build()
)
.build()
)
وقتی سرویس درخواست را دریافت میکند، اقدامات زیر در یک تراکنش انجام میشود:
- دادههای
ContinuationClusterموجود از شریک توسعهدهنده حذف میشوند. - دادههای حاصل از درخواست تجزیه و تحلیل شده و در
ContinuationClusterبهروزرسانیشده ذخیره میشوند.
در صورت بروز خطا، کل درخواست رد میشود و وضعیت موجود حفظ میشود.
APIهای انتشار، APIهای درجشده هستند؛ این APIها جایگزین محتوای موجود میشوند. اگر نیاز به بهروزرسانی یک موجودیت خاص در خوشه تداوم داشته باشید، باید دوباره همه موجودیتها را منتشر کنید.
دادههای خوشهبندی ادامه فقط باید برای حسابهای کاربری بزرگسالان ارائه شود. فقط زمانی منتشر شود که نمایه حساب کاربری متعلق به یک بزرگسال باشد.
همگامسازی بین دستگاهی
پرچم SyncAcrossDevices کنترل میکند که آیا دادههای ContinuationCluster کاربر در دستگاههایی مانند تلویزیون، تلفن، تبلت و غیره همگامسازی شود یا خیر. همگامسازی بین دستگاهها به طور پیشفرض غیرفعال است.
ارزشها:
-
true: دادههای خوشهبندی پیوسته برای یک تجربه مشاهده یکپارچه در تمام دستگاههای کاربر به اشتراک گذاشته میشوند. ما اکیداً این گزینه را برای بهترین تجربه بین دستگاهی توصیه میکنیم. -
false: دادههای خوشه ادامهدار به دستگاه فعلی محدود شده است.
اخذ رضایت
برنامه رسانهای باید تنظیمات واضحی برای فعال یا غیرفعال کردن همگامسازی بین دستگاهها ارائه دهد. مزایای آن را برای کاربر توضیح دهید و تنظیمات کاربر را یک بار ذخیره کرده و بر اساس آن در publishContinuationCluster اعمال کنید.
// Example to allow cross device syncing.
client.publishContinuationCluster(
PublishContinuationClusterRequest
.Builder()
.setContinuationCluster(
ContinuationCluster.Builder()
.setAccountProfile(accountProfile)
.setSyncAcrossDevices(true)
.build()
)
.build()
)
برای بهرهمندی هرچه بیشتر از ویژگی چند دستگاهی ما، تأیید کنید که برنامه رضایت کاربر را دریافت میکند و SyncAcrossDevices روی true فعال کنید. این امر به محتوا اجازه میدهد تا به طور یکپارچه بین دستگاهها همگامسازی شود و منجر به تجربه کاربری بهتر و افزایش تعامل شود. به عنوان مثال، یکی از شرکای ما که این قابلیت را پیادهسازی کرده بود، شاهد افزایش ۴۰ درصدی کلیکهای «ادامه تماشا» بود زیرا محتوای آنها در چندین دستگاه نمایش داده میشد.
دادههای کشف ویدیو را حذف کنید
برای حذف دستی دادههای کاربر از سرور Google TV قبل از دوره نگهداری استاندارد ۶۰ روزه، از متد deleteClusters استفاده کنید. پس از دریافت درخواست، سرویس تمام دادههای کشف ویدیوی موجود را برای نمایه حساب یا برای کل حساب حذف میکند.
تابع شمارشی DeleteReason دلیل حذف دادهها را تعریف میکند. کد زیر ادامهی نظارت بر دادهها را پس از خروج از سیستم حذف میکند.
// If the user logs out from your media app, you must make the following call
// to remove continue watching data from the current google TV device,
// otherwise, the continue watching data will persist on the current
// google TV device until 60 days later.
client.deleteClusters(
DeleteClustersRequest.Builder()
.setAccountProfile(AccountProfile())
.setReason(DeleteReason.DELETE_REASON_USER_LOG_OUT)
.setSyncAcrossDevices(true)
.build()
)
آزمایش
از برنامه تأیید صحت استفاده کنید تا تأیید کنید که ادغام Engage SDK به درستی کار میکند.
پس از فراخوانی API انتشار، با بررسی برنامه تأیید، تأیید کنید که دادههای شما به درستی منتشر میشوند. خوشه ادامه شما باید به عنوان یک ردیف مجزا در رابط برنامه نمایش داده شود.
- این اقدامات را در برنامه خود آزمایش کنید:
- وارد سیستم شوید.
- جابجایی بین پروفایلها (در صورت وجود).
- شروع، سپس مکث ویدیو یا بازگشت به صفحه اصلی.
- هنگام پخش ویدیو، برنامه را ببندید.
- یک مورد را از ردیف «ادامه تماشا» حذف کنید (در صورت پشتیبانی).
- پس از هر اقدام، تأیید کنید که برنامه شما API مربوط به
publishContinuationClustersرا فراخوانی کرده و دادهها به درستی در برنامه تأیید نمایش داده میشوند. برنامه تأیید، علامت سبز «همه چیز خوب است» را برای موجودیتهای به درستی پیادهسازی شده نشان میدهد.

شکل ۱. موفقیت برنامه تأیید برنامه تأیید، هرگونه موجودیت مشکلساز را علامتگذاری میکند.

شکل ۲. خطای برنامه تأیید برای عیبیابی موجودیتهای دارای خطا، از کنترل تلویزیون خود برای انتخاب و کلیک روی موجودیت در برنامه تأیید استفاده کنید. مشکلات خاص نمایش داده میشوند و برای بررسی شما با رنگ قرمز برجسته میشوند (به مثال زیر مراجعه کنید).

شکل ۳. جزئیات خطای برنامه تأیید