Android TV'de "İzlemeye Devam Et" özelliğini entegre etme

Bu kılavuzda, Engage SDK'yı kullanarak İzlemeye Devam Edin özelliğini Android TV uygulamanıza nasıl entegre edeceğiniz açıklanmaktadır.

Ön çalışma

Başlangıç kılavuzundaki Ön çalışma talimatlarını tamamlayın.

Entegrasyon

Varlık oluşturma

SDK, her öğe türünü temsil etmek için farklı varlıklar tanımlamıştır. Devam kümesi aşağıdaki öğeleri destekler:

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

Bu varlıklar için platforma özel URI'leri ve poster resimlerini belirtin.

Ayrıca, henüz yapmadıysanız her platform (ör. Android TV, Android veya iOS) için oynatma URI'leri oluşturun. Böylece kullanıcı her platformda izlemeye devam ettiğinde uygulama, video içeriğini oynatmak için hedeflenen bir oynatma URI'si kullanır.

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

Poster resimleri için URI ve piksel boyutları (yükseklik ve genişlik) gerekir. Birden fazla poster resmi sağlayarak farklı form faktörlerini hedefleyin ancak "İzlemeye Devam Et" öğesinin özellikle Google'ın Entertainment Space'inde doğru şekilde gösterilmesi için tüm resimlerin 16:9 en boy oranına ve en az 200 piksel yüksekliğe sahip olduğunu doğrulayın. Yüksekliği 200 pikselden az olan resimler gösterilmeyebilir.

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

Bu örnekte, tüm zorunlu alanları içeren bir MovieEntity öğesinin nasıl oluşturulacağı gösterilmektedir:

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

Tür ve içerik derecelendirmeleri gibi ayrıntıları sağlamak, Google TV'ye içeriğinizi daha dinamik şekillerde sergileme ve doğru izleyicilerle buluşturma gücü verir.

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

Daha kısa bir geçerlilik süresi belirtmediğiniz sürece varlıklar otomatik olarak 60 gün boyunca kullanılabilir durumda kalır. Özel bir geçerlilik bitiş tarihi ayarlamanız, yalnızca öğenin bu varsayılan süreden önce kaldırılması gerekiyorsa zorunludur.

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

Bu örnekte, gerekli tüm alanları içeren bir TvEpisodeEntity öğesinin nasıl oluşturulacağı gösterilmektedir:

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

Bölüm numarası dizesi (ör. "2") ve sezon numarası dizesi (ör. "1"), izlemeye devam et kartında gösterilmeden önce uygun biçime genişletilir. Bunların sayısal bir dize olması gerektiğini unutmayın. "e2", "bölüm 2", "s1" veya "sezon 1" yazmayın.

Belirli bir TV programının tek bir sezonu varsa sezon numarasını 1 olarak ayarlayın.

İzleyicilerin içeriklerinizi Google TV'de bulma olasılığını artırmak için türler, içerik derecelendirmeleri ve kullanılabilirlik zaman aralıkları gibi ek veriler sağlayabilirsiniz. Bu ayrıntılar, görüntüleme ve filtreleme seçeneklerini iyileştirebilir.

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

Aşağıda, tüm zorunlu alanları içeren bir VideoClipEntity oluşturma örneği verilmiştir.

VideoClipEntity, YouTube videosu gibi kullanıcı tarafından oluşturulan bir klibi temsil eder.

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

İsteğe bağlı olarak içerik üreticiyi, içerik üretici resmini, oluşturulma zamanını milisaniye cinsinden veya kullanılabilirlik zaman aralığını ayarlayabilirsiniz .

LiveStreamingVideoEntity

Aşağıda, tüm zorunlu alanları içeren bir LiveStreamingVideoEntity oluşturma örneği verilmiştir.

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

İsteğe bağlı olarak, canlı yayın öğesi için başlangıç zamanını, yayıncıyı, yayıncı simgesini veya kullanılabilirlik zaman aralığını ayarlayabilirsiniz.

Özellikler ve şartlar hakkında ayrıntılı bilgi için API referansına bakın.

Devam kümesi verilerini sağlama

Devam kümesini yayınlamaktan AppEngagePublishClient sorumludur. ContinuationCluster nesnesini yayınlamak için publishContinuationCluster yöntemini kullanırsınız.

Başlangıç kılavuzunda açıklandığı şekilde istemciyi başlattığınızdan ve hizmet kullanılabilirliğini kontrol ettiğinizden emin olun.

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

Hizmet isteği aldığında tek bir işlemde aşağıdaki eylemler gerçekleşir:

  • Geliştirici iş ortağından alınan mevcut ContinuationCluster verileri kaldırılır.
  • İstekten alınan veriler ayrıştırılır ve güncellenen ContinuationCluster içinde depolanır.

Hata durumunda isteğin tamamı reddedilir ve mevcut durum korunur.

Yayınlama API'leri, upsert API'leridir ve mevcut içeriği değiştirir. Devam kümesindeki belirli bir öğeyi güncellemeniz gerekiyorsa tüm öğeleri tekrar yayınlamanız gerekir.

Devam kümesi verileri yalnızca yetişkin hesapları için sağlanmalıdır. Yalnızca hesap profili bir yetişkine aitse yayınlayın.

Cihazlar arası senkronizasyon

setSyncAcrossDevices, kullanıcının ContinuationCluster verilerinin TV, telefon, tablet vb. cihazlar arasında senkronize edilip edilmeyeceğini kontrol eder. Cihazlar arası senkronizasyon varsayılan olarak devre dışıdır.

Değerler:

  • true: Devam kümesi verileri, sorunsuz bir izleme deneyimi için kullanıcının tüm cihazlarında paylaşılır. Cihazlar arası en iyi deneyim için bu seçeneği kullanmanızı kesinlikle öneririz.
  • false: Devam kümesi verileri mevcut cihazla kısıtlıdır.

Ayrıca, içeriğin cihazlar arasında senkronize edilebilmesi için hesap kimliği içeren bir AccountProfile sağlamanız gerekir. Hesap profili oluşturma başlıklı makaleyi inceleyin.

Medya uygulaması, cihazlar arası senkronizasyonu etkinleştirmek veya devre dışı bırakmak için net bir ayar sunmalıdır. Kullanıcıya avantajları açıklayın ve kullanıcının tercihini bir kez kaydedip publishContinuationCluster uygulamasında buna göre uygulayın.

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

Cihazlar arası özelliğimizden en iyi şekilde yararlanmak için uygulamanın kullanıcı rızası aldığından emin olun ve SyncAcrossDevices ile true arasında bağlantıyı etkinleştirin. Bu sayede içerikler cihazlar arasında sorunsuz bir şekilde senkronize edilir. Böylece kullanıcı deneyimi iyileşir ve etkileşim artar. Örneğin, bu özelliği uygulayan bir iş ortağı, içerikleri birden fazla cihazda gösterildiği için "izlemeye devam et" tıklamalarında %40 artış elde etti.

Etkileşim verilerini silme

Bir kullanıcının verilerini, standart 60 günlük saklama süresinden önce Google TV sunucusundan manuel olarak silmek için deleteClusters yöntemini kullanın. İstek alındıktan sonra hizmet, hesap profili veya hesabın tamamı için mevcut tüm Engage verilerini siler.

DeleteReason enum'u, veri silme nedenini tanımlar. Aşağıdaki kod, çıkış yapıldığında izlemeye devam etme verilerini kaldırır.


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

Test

Engage SDK entegrasyonunun doğru şekilde çalıştığını doğrulamak için doğrulama uygulamasını kullanın.

Yayınlama API'sini çağırdıktan sonra doğrulama uygulamasını kontrol ederek verilerinizin doğru şekilde yayınlandığını onaylayın. Devamlılık kümeniz, uygulamanın arayüzünde ayrı bir satır olarak gösterilmelidir.

  • Uygulamanızda şu işlemleri test edin:
    • Oturum açın.
    • Profiller arasında geçiş yapma(varsa)
    • Bir videoyu başlatıp duraklatın veya ana sayfaya dönün.
    • Video oynatılırken uygulamayı kapatın.
    • "İzlemeye Devam Edin" satırından bir öğeyi kaldırma (destekleniyorsa)
  • Her işlemden sonra uygulamanızın publishContinuationClusters API'yi çağırdığını ve verilerin doğrulama uygulamasında doğru şekilde gösterildiğini onaylayın.
  • Doğrulama uygulaması, doğru şekilde uygulanan varlıklar için yeşil renkli bir "Sorun Yok" onay işareti gösterir.

    Doğrulama Uygulaması Başarı Ekran Görüntüsü
    Şekil 1. Doğrulama Uygulaması Başarısı
  • Doğrulama uygulaması, sorunlu tüzel kişileri işaretler.

    Doğrulama Uygulaması Hatası Ekran Görüntüsü
    Şekil 2. Doğrulama Uygulaması Hatası
  • Hatalı öğelerle ilgili sorunları gidermek için TV uzaktan kumandanızı kullanarak doğrulama uygulamasındaki öğeyi seçip tıklayın. Belirli sorunlar, incelemeniz için kırmızı renkle vurgulanarak gösterilir (aşağıdaki örneğe bakın).

    Doğrulama uygulaması hata ayrıntıları
    Şekil 3. Doğrulama Uygulaması Hatası Ayrıntıları