ادغام کردن «ادامه تماشا» در Android TV

این راهنما نحوه ادغام کردن «ادامه تماشا» را در برنامه Android TV بااستفاده از Engage SDK پوشش می‌دهد.

پیش‌کار

دستورالعمل‌های پیش‌کار را در راهنمای «شروع به کار» تکمیل کنید.

یکپارچه‌سازی

ایجاد نهادها

کیت توسعه نرم‌افزار نهادهای مختلفی را برای نمایش هر نوع مورد تعریف کرده است. خوشه ادامه از نهادهای زیر پشتیبانی می‌کند:

  1. MovieEntity
  2. TvEpisodeEntity
  3. LiveStreamingVideoEntity
  4. VideoClipEntity

شناسه‌های منبع یکسان مختص پلاتفرم و تصاویر پوستر را برای این نهادها مشخص کنید.

همچنین، اگر قبلاً این کار را نکرده‌اید، برای هر پلاتفرم (مانند 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 و ابعاد پیکسل (ارتفاع و عرض) نیاز دارند. با ارائه چندین تصویر پوستر، عوامل شکل مختلف را هدف قرار دهید، اما بررسی کنید که همه تصاویر نسبت ابعادی ۱۶:۹ و حداقل ارتفاع ۲۰۰ پیکسل را حفظ کنند تا موجودیت «ادامه تماشا» به‌درستی نمایش داده شود، به‌ویژه در فضای سرگرمی Google. تصاویر با ارتفاع کمتر از ۲۰۰ پیکسل ممکن است نشان داده نشوند.

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

این مثال نشان می‌دهد که چگونه می‌توان یک MovieEntity با تمام فیلدهای الزامی ایجاد کرد:

val movieEntity = MovieEntity.Builder()
   .setWatchNextType(WatchNextType.TYPE_CONTINUE)
   .setName("Movie name")
   .addPlatformSpecificPlaybackUris(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
   .setDurationMillis(72000000)
   // Suppose last playback offset is 1 hour, 36000000 in milliseconds
   .setLastPlayBackPositionTimeMillis(36000000)
   .setCallToActionText("Resume")
   .addTag("Action")
   .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)
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

این مثال نشان می‌دهد که چگونه می‌توان یک TvEpisodeEntity با تمام فیلدهای لازم ایجاد کرد:

val tvEpisodeEntity = TvEpisodeEntity.Builder()
    .setWatchNextType(WatchNextType.TYPE_CONTINUE)
    .setName("Episode name")
    .addPlatformSpecificPlaybackUris(platformSpecificPlaybackUris)
    .addPosterImages(images)
    // Timestamp in millis for sample last engagement time 12/1/2023 00:00:00
    .setLastEngagementTimeMillis(1701388800000)
    .setDurationMillis(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")
    .setCallToActionText("Resume")
    .addTag("Comedy")
    .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 با همه فیلدهای الزامی آورده شده است.

VideoClipEntity نشان‌دهنده کلیپ تولیدشده توسط کاربر مانند ویدیو YouTube است.

val videoClipEntity = VideoClipEntity.Builder()
    .setPlayBackUri(Uri.parse("https://www.example.com/uri_for_current_platform"))
    .setWatchNextType(WatchNextType.TYPE_CONTINUE)
    .setName("Video clip name")
    .addPlatformSpecificPlaybackUris(platformSpecificPlaybackUris)
    .addPosterImages(images)
    // Timestamp in millis for sample last engagement time 12/1/2023 00:00:00
    .setLastEngagementTimeMillis(1701388800000)
    .setDurationMillis(600000) //10 minutes in milliseconds
    .setLastPlayBackPositionTimeMillis(300000) //5 minutes in milliseconds
    .setCallToActionText("Resume")
    .addTag("Vlog")
    .build()

می‌توانید به‌طور اختیاری سازنده، تصویر سازنده، زمان ایجاد به میلی‌ثانیه، یا پنجره زمانی دردسترس بودن را تنظیم کنید .

LiveStreamingVideoEntity

در اینجا نمونه‌ای از ایجاد LiveStreamingVideoEntity با همه فیلدهای الزامی آورده شده است.

val liveStreamingVideoEntity = LiveStreamingVideoEntity.Builder()
    .setPlayBackUri(Uri.parse("https://www.example.com/uri_for_current_platform"))
    .setWatchNextType(WatchNextType.TYPE_CONTINUE)
    .setName("Live streaming name")
    .addPlatformSpecificPlaybackUris(platformSpecificPlaybackUris)
    .addPosterImages(images)
    // Timestamp in millis for sample last engagement time 12/1/2023 00:00:00
    .setLastEngagementTimeMillis(1701388800000)
    .setLastPlayBackPositionTimeMillis(36000000) //1 hour in milliseconds
    .addContentRating(contentRating)
    .setCallToActionText("Resume")
    .addTag("Live")
    .build()

اختیاراً می‌توانید زمان شروع، پخش‌کننده، نماد پخش‌کننده، یا پنجره زمانی دردسترس بودن را برای نهاد جاری‌سازی زنده تنظیم کنید.

برای اطلاعات دقیق درباره مشخصه‌ها و الزامات، به مرجع میانای برنامه‌سازی کاربردی مراجعه کنید.

ارائه داده‌های خوشه «ادامه»

‫AppEngagePublishClient مسئول انتشار خوشه «ادامه» است. از روش publishContinuationCluster برای انتشار شیء ContinuationCluster استفاده می‌کنید.

مطمئن شوید که کارخواه را مقداردهی اولیه کرده‌اید و دردسترس بودن سرویس را همان‌طور که در راهنمای شروع به کار شرح داده شده است بررسی کنید.

client.publishContinuationCluster(
    PublishContinuationClusterRequest
        .Builder()
        .setContinuationCluster(
            ContinuationCluster.Builder()
                .setAccountProfile(accountProfile)
                .addEntity(movieEntity1)
                .addEntity(movieEntity2)
                .addEntity(tvEpisodeEntity1)
                .addEntity(tvEpisodeEntity2)
                .setSyncAcrossDevices(true)
                .build()
        )
        .build()
)

وقتی سرویس درخواست را دریافت می‌کند، کنش‌های زیر در یک تراکنش انجام می‌شود:

  • داده‌های ContinuationCluster موجود از شریک توسعه‌دهنده برداشته می‌شود.
  • داده‌های درخواست تجزیه می‌شود و در ContinuationCluster به‌روزشده ذخیره می‌شود.

درصورت بروز خطا، کل درخواست رد می‌شود و وضعیت موجود حفظ می‌شود.

میاناهای برنامه‌سازی کاربردی انتشار از نوع میاناهای برنامه‌سازی کاربردی «درج یا به‌روزرسانی» هستند؛ این میاناهای برنامه‌سازی کاربردی محتوای موجود را جایگزین می‌کنند. اگر لازم است نهاد خاصی را در خوشه ادامه‌دار به‌روز کنید، باید همه نهادها را دوباره منتشر کنید.

داده‌های خوشه ادامه فقط باید برای حساب‌های بزرگسالان ارائه شود. فقط زمانی منتشر کنید که نمایه حساب متعلق به یک بزرگسال باشد.

همگام‌سازی بین‌دستگاهی

setSyncAcrossDevices کنترل می‌کند که آیا داده‌های ContinuationCluster کاربر در دستگاه‌هایی مانند تلویزیون، تلفن، رایانه لوحی، و غیره همگام‌سازی شود یا نه. همگام‌سازی بین‌دستگاهی به‌طور پیش‌فرض غیرفعال است.

مقادیر:

  • ‫true: داده‌های خوشه ادامه در همه دستگاه‌های کاربر هم‌رسانی می‌شود تا تجربه تماشای یکپارچه‌ای داشته باشد. این گزینه را برای بهترین تجربه بین‌دستگاهی اکیداً توصیه می‌کنیم.
  • false: داده‌های خوشه ادامه به دستگاه فعلی محدود است.

علاوه‌براین، باید AccountProfile را با شناسه حساب ارائه دهید تا محتوا بین دستگاه‌ها همگام‌سازی شود. به ایجاد نمایه حساب مراجعه کنید.

برنامه رسانه باید تنظیمات واضحی برای فعال یا غیرفعال کردن همگام‌سازی بین‌دستگاهی ارائه دهد. مزایا را برای کاربر توضیح دهید و اولویت کاربر را یک‌بار ذخیره کنید و آن را به‌طور مقتضی در publishContinuationCluster اعمال کنید.

// Example to allow cross device syncing.
client.publishContinuationCluster(
    PublishContinuationClusterRequest
        .Builder()
        .setContinuationCluster(
            ContinuationCluster.Builder()
                .setAccountProfile(accountProfile)
                .setSyncAcrossDevices(true)
                .build()
        )
        .build()
)

برای بهره‌مندی حداکثری از ویژگی بین‌دستگاهی ما، مطمئن شوید که برنامه رضایت کاربر را دریافت می‌کند و SyncAcrossDevices را به true فعال کنید. این کار باعث می‌شود محتوا به‌طور یکپارچه در دستگاه‌ها همگام‌سازی شود و درنتیجه تجربه کاربری بهتر و تعامل بیشتری ایجاد شود. برای مثال، شریکی که این ویژگی را پیاده‌سازی کرد، شاهد افزایش ۴۰ درصدی در کلیک‌های «ادامه تماشا» بود، زیرا محتوای او در چندین دستگاه نمایش داده می‌شد.

حذف داده‌های Engage

برای حذف دستی داده‌های کاربر از سرور Google TV قبل‌از دوره نگهداری استاندارد ۶۰ روزه، از روش deleteClusters استفاده کنید. پس‌از دریافت درخواست، سرویس همه داده‌های Engage موجود برای نمایه حساب یا کل حساب را حذف خواهد کرد.

DeleteReason enum دلیل حذف داده‌ها را تعریف می‌کند. کد زیر داده‌های ادامه تماشا را هنگام خروج از سیستم حذف می‌کند.


// 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)
        .setDeleteReason(DeleteReason.DELETE_REASON_USER_LOG_OUT)
        .setSyncAcrossDevices(true)
        .build()
)

آزمایش

از برنامه درستی‌سنجی استفاده کنید تا مطمئن شوید ادغام Engage SDK به‌درستی کار می‌کند.

پس‌از فراخوانی Publish API، با بررسی برنامه درستی‌سنجی مطمئن شوید که داده‌هایتان به‌درستی منتشر می‌شود. خوشه تداوم شما باید به‌عنوان ردیفی متمایز در میانجی برنامه نمایش داده شود.

  • این کنش‌ها را در برنامه‌تان آزمایش کنید:
    • به سیستم وارد شوید.
    • بین نمایه‌ها جابه‌جا شوید(درصورت وجود).
    • ویدیویی را شروع کنید، سپس آن را موقتاً متوقف کنید، یا به صفحه اصلی برگردید.
    • برنامه را درحین بازپخش ویدیو ببندید.
    • موردی را از ردیف «ادامه تماشا» بردارید (درصورت پشتیبانی).
  • پس‌از هر کنش، تأیید کنید که برنامه‌تان publishContinuationClusters API را فراخوانی کرده است و داده‌ها به‌درستی در برنامه درستی‌سنجی نمایش داده می‌شود.
  • برنامه درستی‌سنجی برای نهادهایی که به‌درستی پیاده‌سازی شده‌اند، علامت تیک سبز «همه چیز خوب است» را نشان می‌دهد.

    نماگرفت موفقیت برنامه درستی‌سنجی
    شکل ۱. برنامه درستی‌سنجی با موفقیت انجام شد
  • برنامه درستی‌سنجی هر نهاد مشکل‌داری را پرچم‌گذاری خواهد کرد.

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

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