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

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

Ön çalışma

Başlangıç kılavuzundaki Ön hazırlık talimatlarını tamamlayın.

Entegrasyon

Varlık oluşturma

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

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

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. Bu nedenle, kullanıcı her platformda izlemeye devam ettiğinde uygulama, video içeriğini oynatmak için hedeflenmiş 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 özellikle Google'ın Entertainment Space'inde "İzlemeye Devam Et" öğesinin doğru şekilde gösterilmesi için tüm resimlerin 16:9 en boy oranını ve minimum 200 piksel yüksekliği koruduğ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, gerekli tüm alanları içeren bir MovieEntity öğesinin nasıl oluşturulacağı gösterilmektedir:

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)
   .setCallToActionText("Resume")
   .addTag("Action")
   .build()

Türler ve içerik derecelendirmeleri gibi ayrıntılar sağladığınızda Google TV, içeriğinizi daha dinamik şekillerde sergileyebilir ve doğru izleyicilerle buluşturabilir.

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 öğeler 60 gün boyunca otomatik olarak kullanılabilir durumda kalır. Yalnızca öğenin bu varsayılan süreden önce kaldırılması gerekiyorsa özel bir geçerlilik bitiş tarihi ayarlayın.

// 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 nasıl oluşturulacağı gösterilmektedir:

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")
    .setCallToActionText("Resume")
    .addTag("Comedy")
    .build()

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

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

İzleyicilerin Google TV'de içeriğinizi bulma olasılığını en üst düzeye çıkarmak için türler, içerik derecelendirmeleri ve stok durumu zaman aralıkları gibi ek veriler sağlamayı düşünebilirsiniz. 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, gerekli tüm 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")
    .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)
    .setCallToActionText("Resume")
    .addTag("Vlog")
    .build()

İsteğe bağlı olarak oluşturucu, oluşturucu resmi, oluşturulma zamanı (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")
    .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)
    .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.

Devamlılık kümesi verileri sağlama

Devamlılık kümesinin yayınlanmasından AppEngagePublishClient sorumludur. publishContinuationCluste yöntemini kullanarak bir ContinuationCluster nesnesi yayınlarsınız.

İstemciyi başlattığınızdan ve Başlangıç Kılavuzu'nda açıklandığı şekilde hizmetin 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 işlemler gerçekleşir:

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

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

Yayınlama API'leri, ekleme/güncelleme API'leridir ve mevcut içeriğin yerini alır. Devamlılık kümesinde belirli bir öğeyi güncellemeniz gerekiyorsa tüm öğeleri tekrar yayınlamanız gerekir.

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

Cihazlar arası senkronizasyon

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

Değerler:

  • true: Sorunsuz bir izleme deneyimi için devamlılık kümesi verileri, kullanıcının tüm cihazlarında paylaşılır. Cihazlar arası en iyi deneyim için bu seçeneği kullanmanızı önemle tavsiye ederiz.
  • false: Devamlılık kümesi verileri, mevcut cihazla sınırlıdır.

Ayrıca, içeriklerin 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 saklayıp publishContinuationCluster içinde 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ı izni aldığını doğrulayın ve SyncAcrossDevices seçeneğini true olarak ayarlayın. Bu sayede içerik, cihazlar arasında sorunsuz bir şekilde senkronize edilebilir. Bu da daha iyi bir kullanıcı deneyimi ve daha fazla etkileşim sağlar. Örneğin, bu özelliği uygulayan bir iş ortağı, içeriği 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. Hizmet, isteği aldıktan sonra hesap profili veya hesabın tamamı için mevcut tüm Engage verilerini siler.

DeleteReason numaralandırması, veri silme nedenini tanımlar. Aşağıdaki kod, oturum kapatıldığında "İzlemeye devam et" 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())
        .setReason(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 aşağıdaki işlemleri test edin:
    • Oturum açın.
    • Profiller arasında geçiş yapın(varsa).
    • Bir videoyu başlatıp duraklatın veya ana sayfaya dönün.
    • Video oynatılırken uygulamayı kapatın.
    • "İzlemeye Devam Et" satırından bir öğeyi kaldırma (destekleniyorsa)
  • Her işlemden sonra uygulamanızın publishContinuationClusters API'sini çağırdığını ve verilerin doğrulama uygulamasında doğru şekilde gösterildiğini onaylayın.
  • Doğrulama uygulaması, doğru şekilde uygulanmış öğeler için yeşil bir "Her Şey Tamam" onay işareti gösterir.

    Doğrulama Uygulaması Başarı Ekran Görüntüsü
    Şekil 1. Verification App Success
  • Doğrulama uygulaması, sorunlu varlıkları işaretler.

    Doğrulama Uygulaması Hatası Ekran Görüntüsü
    Şekil 2. Doğrulama Uygulaması Hatası
  • Hata içeren öğelerle ilgili sorunları gidermek için TV kumandanızı kullanarak doğrulama uygulamasında öğeyi seçip tıklayın. Belirli sorunlar, incelemeniz için kırmızı renkte 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ı