Mengintegrasikan Lanjutkan Menonton di Android TV

Panduan ini membahas cara mengintegrasikan fitur Lanjutkan Menonton ke aplikasi Android TV Anda menggunakan Engage SDK.

Persiapan

Selesaikan petunjuk Pra-pekerjaan di panduan Memulai.

Integrasi

Membuat entity

SDK telah menentukan entity yang berbeda untuk mewakili setiap jenis item. Cluster kelanjutan mendukung entity berikut:

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

Tentukan URI dan gambar poster khusus platform untuk entitas ini.

Selain itu, buat URI pemutaran untuk setiap platform—seperti Android TV, Android, atau iOS—jika Anda belum melakukannya. Jadi, saat pengguna melanjutkan menonton di setiap platform, aplikasi akan menggunakan URI pemutaran yang ditargetkan untuk memutar konten video.

// 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)

Gambar poster memerlukan URI dan dimensi piksel (tinggi dan lebar). Targetkan berbagai faktor bentuk dengan menyediakan beberapa gambar poster, tetapi pastikan semua gambar mempertahankan rasio aspek 16:9 dan tinggi minimum 200 piksel untuk tampilan entitas "Lanjutkan Menonton" yang benar, terutama dalam Entertainment Space Google. Gambar dengan tinggi kurang dari 200 piksel mungkin tidak ditampilkan.

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

Contoh ini menunjukkan cara membuat MovieEntity dengan semua kolom yang diperlukan:

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()

Dengan memberikan detail seperti genre dan rating konten, Google TV dapat menampilkan konten Anda dengan cara yang lebih dinamis dan menghubungkannya dengan penonton yang tepat.

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()

Entity akan otomatis tetap tersedia selama 60 hari, kecuali jika Anda menentukan waktu habis masa berlaku yang lebih singkat. Hanya tetapkan masa berlaku kustom jika Anda ingin entity dihapus sebelum periode default ini.

// 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

Contoh ini menunjukkan cara membuat TvEpisodeEntity dengan semua kolom yang diperlukan:

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()

String nomor episode (seperti "2"), dan string nomor season (seperti "1") akan diperluas ke bentuk yang tepat sebelum ditampilkan di kartu lanjutkan menonton. Perhatikan bahwa nilai ini harus berupa string numerik, jangan masukkan "e2", atau "episode 2", atau "s1" atau "season 1".

Jika acara TV tertentu memiliki satu season, tetapkan nomor season sebagai 1.

Untuk memaksimalkan peluang penonton menemukan konten Anda di Google TV, pertimbangkan untuk memberikan data tambahan seperti genre, rating konten, dan periode waktu ketersediaan, karena detail ini dapat meningkatkan opsi tampilan dan pemfilteran.

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

Berikut contoh pembuatan VideoClipEntity dengan semua kolom wajib diisi.

VideoClipEntity mewakili klip buatan pengguna seperti video 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()

Anda dapat menetapkan pembuat, gambar pembuat, waktu pembuatan dalam milidetik, atau periode waktu ketersediaan .

LiveStreamingVideoEntity

Berikut adalah contoh pembuatan LiveStreamingVideoEntity dengan semua kolom wajib diisi.

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()

Jika ingin, Anda dapat menetapkan waktu mulai, penyiar, ikon penyiar, atau periode waktu ketersediaan untuk entitas live streaming.

Untuk mengetahui informasi mendetail tentang atribut dan persyaratan, lihat referensi API.

Menyediakan data cluster Lanjutan

AppEngagePublishClient bertanggung jawab untuk memublikasikan cluster Lanjutan. Anda menggunakan metode publishContinuationCluster untuk memublikasikan objek ContinuationCluster.

Pastikan untuk melakukan inisialisasi klien dan memeriksa ketersediaan layanan seperti yang dijelaskan dalam Panduan Memulai.

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

Saat layanan menerima permintaan tersebut, tindakan berikut akan terjadi dalam satu transaksi:

  • Data ContinuationCluster yang ada dari partner developer akan dihapus.
  • Data dari permintaan akan diuraikan dan disimpan di ContinuationCluster yang diperbarui.

Jika terjadi error, seluruh permintaan akan ditolak dan status yang ada dipertahankan.

API publikasi adalah API upsert; API ini menggantikan konten yang sudah ada. Jika perlu memperbarui entity tertentu dalam cluster lanjutan, Anda harus memublikasikan semua entity lagi.

Data cluster kelanjutan hanya boleh diberikan untuk akun dewasa. Publikasikan hanya jika profil akun milik orang dewasa.

Sinkronisasi lintas perangkat

setSyncAcrossDevices mengontrol apakah data ContinuationCluster pengguna disinkronkan di seluruh perangkat seperti TV, ponsel, tablet, dll. Sinkronisasi lintas perangkat dinonaktifkan secara default.

Nilai:

  • true: Data cluster lanjutan dibagikan di semua perangkat pengguna untuk pengalaman menonton yang lancar. Kami sangat merekomendasikan opsi ini untuk pengalaman lintas perangkat terbaik.
  • false: Data cluster kelanjutan dibatasi untuk perangkat saat ini.

Selain itu, Anda harus memberikan AccountProfile dengan ID akun agar konten dapat disinkronkan antarperangkat. Lihat Membuat profil akun.

Aplikasi media harus menyediakan setelan yang jelas untuk mengaktifkan atau menonaktifkan sinkronisasi lintas perangkat. Jelaskan manfaatnya kepada pengguna dan simpan preferensi pengguna sekali, lalu terapkan di publishContinuationCluster sebagaimana mestinya.

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

Untuk mendapatkan hasil maksimal dari fitur lintas perangkat kami, pastikan aplikasi mendapatkan izin pengguna dan aktifkan SyncAcrossDevices ke true. Hal ini memungkinkan konten disinkronkan dengan lancar di seluruh perangkat, sehingga menghasilkan pengalaman pengguna yang lebih baik dan meningkatkan engagement. Misalnya, partner yang menerapkan hal ini mengalami peningkatan klik "lanjutkan menonton" sebesar 40% karena kontennya ditampilkan di beberapa perangkat.

Menghapus data Engage

Untuk menghapus data pengguna secara manual dari server Google TV sebelum periode retensi standar 60 hari, gunakan metode deleteClusters. Setelah menerima permintaan, layanan akan menghapus semua data Engage yang ada untuk profil akun, atau untuk seluruh akun.

Enum DeleteReason menentukan alasan penghapusan data. Kode berikut menghapus data lanjutkan menonton saat logout.


// 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()
)

Pengujian

Gunakan aplikasi verifikasi untuk memverifikasi bahwa integrasi Engage SDK berfungsi dengan benar.

Setelah memanggil API publikasi, pastikan data Anda dipublikasikan dengan benar dengan memeriksa aplikasi verifikasi. Cluster kelanjutan Anda akan ditampilkan sebagai baris yang berbeda dalam antarmuka aplikasi.

  • Uji tindakan ini di aplikasi Anda:
    • Login.
    • Beralih antar-profil(jika ada).
    • Mulai, lalu jeda video, atau kembali ke halaman beranda.
    • Tutup aplikasi selama pemutaran video.
    • Menghapus item dari baris "Lanjutkan Menonton" (jika didukung).
  • Setelah setiap tindakan, pastikan aplikasi Anda memanggil publishContinuationClusters API dan data ditampilkan dengan benar di aplikasi verifikasi.
  • Aplikasi verifikasi menampilkan tanda centang hijau "Semua Baik" untuk entitas yang diterapkan dengan benar.

    Screenshot Keberhasilan Aplikasi Verifikasi
    Gambar 1. Aplikasi Verifikasi Berhasil
  • Aplikasi verifikasi akan menandai entitas yang bermasalah.

    Screenshot Error Aplikasi Verifikasi
    Gambar 2. Error Aplikasi Verifikasi
  • Untuk memecahkan masalah entitas yang mengalami error, gunakan remote TV untuk memilih dan mengklik entitas di aplikasi verifikasi. Masalah spesifik akan ditampilkan dan ditandai dengan warna merah untuk Anda tinjau (lihat contoh di bawah).

    Detail error Aplikasi Verifikasi
    Gambar 3. Detail Error Aplikasi Verifikasi