Используйте SDK для рекомендаций видео

В этом руководстве содержатся инструкции для разработчиков по интеграции рекомендуемого ими видеоконтента с помощью Engage SDK для распространения рекомендаций на всех устройствах Google, таких как телевизоры, мобильные телефоны и планшеты.

Рекомендации используют кластер рекомендаций для показа фильмов и сериалов из нескольких приложений в одной группе пользовательского интерфейса. Каждый партнёр-разработчик может транслировать до 25 сущностей в каждом кластере рекомендаций, и в одном запросе может быть не более 7 кластеров рекомендаций.

Предварительная работа

Прежде чем начать, выполните следующие шаги. 1. Убедитесь, что ваше приложение поддерживает API уровня 19 или выше для этой интеграции.

  1. Добавьте библиотеку com.google.android.engage в свое приложение.

    Для интеграции используются отдельные SDK: один для мобильных приложений и один для телевизионных приложений.

    Для мобильных устройств

    
      dependencies {
        implementation 'com.google.android.engage:engage-core:1.5.9
      }
    

    для ТВ

    
      dependencies {
        implementation 'com.google.android.engage:engage-tv:1.0.5
      }
    
  2. Настройте среду службы Engage на работу в файле AndroidManifest.xml .

    Для мобильного APK

    
    <meta-data
          android:name="com.google.android.engage.service.ENV"
          android:value="PRODUCTION">
    </meta-data>
    

    Для ТВ apk

    
    <meta-data
        android:name="com.google.android.engage.service.ENV"
        android:value="PRODUCTION">
    </meta-data>
    
  3. Выполнить публикацию на приоритетной службе.

  4. Публиковать данные рекомендаций не чаще одного раза в день по одному из следующих событий:

    1. Первый вход пользователя в систему за день. ( или )
    2. Когда пользователь начинает интерактивное взаимодействие с приложением.

Интеграция

AppEngagePublishClient публикует кластер рекомендаций. Для публикации объекта рекомендаций используйте метод publishRecommendationClusters .

Используйте isServiceAvailable() 2 , чтобы проверить, доступна ли служба для интеграции.

val client = AppEngagePublishClient(context)

client.isServiceAvailable().addOnCompleteListener { task ->
  if (task.isSuccessful) {
  // Handle IPC call success
    if(task.result) {
      // Service is available on the device, proceed with content publish
      // calls.
      client.publishRecommendationClusters(recommendationRequest)
    } else {
      // Service is not available
    }
  } else {
    // The IPC call itself fails, proceed with error handling logic here,
    // such as retry.
  }
}

Кластеры рекомендаций и запрос на публикацию

Кластеры — это логическая группировка сущностей. В следующих примерах кода объясняется, как создать кластеры на основе ваших предпочтений и как создать запрос на публикацию для всех кластеров.

// cluster for popular movies
val recommendationCluster1 = RecommendationCluster
  .Builder()
  .addEntity(movie1)
  .addEntity(movie2)
  .addEntity(movie3)
  .addEntity(movie4)
  .addEntity(tvShow)
  // This cluster is meant to be used as an individual provider row
  .setRecommendationClusterType(TYPE_PROVIDER_ROW)
  .setTitle("Popular Movies")
  .build()

// cluster for live TV programs
val recommendationCluster2 = RecommendationCluster
  .Builder()
  .addEntity(liveTvProgramEntity1)
  .addEntity(liveTvProgramEntity2)
  .addEntity(liveTvProgramEntity3)
  .addEntity(liveTvProgramEntity4)
  .addEntity(liveTvProgramEntity5)
 // This cluster is meant to be used as an individual provider row
  .setRecommendationClusterType(TYPE_PROVIDER_ROW)
  .setTitle("Popular Live TV Programs")
  .build()

// creating a publishing request
val recommendationRequest = PublishRecommendationClustersRequest
  .Builder()
  .setSyncAcrossDevices(true)
  .setAccountProfile(accountProfile)
  .addRecommendationCluster(recommendationCluster1)
  .addRecommendationCluster(recommendationCluster2)
  .build()

Создать профиль учетной записи

Чтобы настроить персонализированный подход к использованию Google TV, предоставьте данные учётной записи и профиля. Используйте AccountProfile , чтобы предоставить:

  1. Идентификатор учётной записи: уникальный идентификатор, представляющий учётную запись пользователя в вашем приложении. Это может быть фактический идентификатор учётной записи или его соответствующим образом замаскированная версия.
  2. Идентификатор профиля (необязательно): если ваше приложение поддерживает несколько профилей в рамках одной учетной записи, укажите уникальный идентификатор для конкретного профиля пользователя.
  3. Locale (необязательно): вы можете указать предпочитаемый пользователем язык. Это поле полезно, если вы отправляете MediaActionFeedEntity в RecommendationRequest .
// If app only supports account
val accountProfile = AccountProfile.Builder()
  .setAccountId("account_id")
  .build();

// If app supports both account and profile
val accountProfile = AccountProfile.Builder()
  .setAccountId("account_id")
  .setProfileId("profile_id")
  .build();

// set Locale
val accountProfile = AccountProfile.Builder()
  .setAccountId("account_id")
  .setProfileId("profile_id")
  .setLocale("en-US")
  .build();

При получении запроса службой в рамках одной транзакции происходят следующие действия:

  • Существующие данные RecommendationsCluster от партнера-разработчика удаляются.
  • Данные из запроса анализируются и сохраняются в обновлённом классе RecommendationsCluster . В случае ошибки весь запрос отклоняется, а текущее состояние сохраняется.

Синхронизация между устройствами

Флаг SyncAcrossDevices определяет, будут ли данные кластера рекомендаций пользователя передаваться в Google TV и будут ли они доступны на всех его устройствах, таких как телевизоры, телефоны и планшеты. Для работы рекомендации необходимо установить значение true.

Медиаприложение должно предоставлять чёткие настройки для включения и отключения синхронизации между устройствами. Объясните пользователю преимущества этой функции, сохраните настройки пользователя и соответствующим образом примените их в запросе publishRecommendations . Чтобы максимально эффективно использовать функцию синхронизации между устройствами, убедитесь, что приложение получает согласие пользователя и устанавливает для SyncAcrossDevices значение true .

Удалить данные обнаружения видео

Чтобы вручную удалить данные пользователя с сервера Google TV до истечения стандартного 60-дневного срока хранения, используйте метод client.deleteClusters() . После получения запроса сервис удаляет все существующие данные обнаружения видео для профиля учётной записи или для всей учётной записи.

Перечисление DeleteReason определяет причину удаления данных. Следующий код удаляет рекомендации при выходе из системы.

// If the user logs out from your media app, you must make the following call
// to remove recommendations data from the current google TV device,
// otherwise, the recommendations data persists on the current
// google TV device until 60 days later.
client.deleteClusters(
  new DeleteClustersRequest.Builder()
    .setAccountProfile(AccountProfile())
    .setReason(DeleteReason.DELETE_REASON_USER_LOG_OUT)
    .build()
)

// If the user revokes the consent to share data with Google TV,
// you must make the following call to remove recommendations data from
// all current google TV devices. Otherwise, the recommendations data persists
// until 60 days later.
client.deleteClusters(
  new DeleteClustersRequest.Builder()
    .setAccountProfile(AccountProfile())
    .setReason(DeleteReason.DELETE_REASON_LOSS_OF_CONSENT)
    .build()
)

Создавать сущности

В SDK определены различные сущности для представления каждого типа элементов. Для кластера рекомендаций поддерживаются следующие сущности:

  1. MediaActionFeedEntity
  2. MovieEntity
  3. TvShowEntity
  4. LiveTvChannelEntity
  5. LiveTvProgramEntity

Описание

Введите краткое описание для каждой сущности; это описание будет отображаться при наведении курсора на сущность, предоставляя пользователям дополнительные сведения.

URI воспроизведения, специфичные для платформы

Создайте URI воспроизведения для каждой поддерживаемой платформы: Android TV, Android или iOS. Это позволит системе выбрать подходящий URI для воспроизведения видео на соответствующей платформе.

В редком случае, когда URI воспроизведения идентичны для всех платформ, повторите их для каждой платформы.

// Required. Set this when you want recommended 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()

// Optional. Set this when you want recommended entities to show up on
// Google TV Android app
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 recommended 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)

// Provide appropriate rating for the system.
val contentRating = new RatingSystem
  .Builder()
  .setAgencyName("MPAA")
  .setRating("PG-13")
  .build()

Изображения постеров

Для постеров требуется URI и размеры в пикселях (высота и ширина). Для разных форм-факторов предоставьте несколько постеров, но убедитесь, что все изображения имеют соотношение сторон 16:9 и высоту не менее 200 пикселей для корректного отображения объекта «Рекомендации», особенно в разделе «Развлечения » Google. Изображения высотой менее 200 пикселей могут не отображаться.

Image image1 = new Image.Builder()
  .setImageUri(Uri.parse("http://www.example.com/entity_image1.png");)
  .setImageHeightInPixel(300)
  .setImageWidthInPixel(169)
  .build()

Image image2 = new Image.Builder()
  .setImageUri(Uri.parse("http://www.example.com/entity_image2.png");)
  .setImageHeightInPixel(640)
  .setImageWidthInPixel(360)
  .build()

// And other images for different form factors.
val images = Arrays.asList(image1, image2)

Причина рекомендации

При желании укажите причину рекомендации, которую Google TV может использовать для обоснования того, почему пользователю следует предложить определенный фильм или телешоу.

//Allows us to construct reason: "Because it is top 10 on your Channel"
val topOnPartner = RecommendationReasonTopOnPartner
  .Builder()
  .setNum(10) //any valid integer value
  .build()

//Allows us to construct reason: "Because it is popular on your Channel"
val popularOnPartner = RecommendationReasonPopularOnPartner
  .Builder()
  .build()

//Allows us to construct reason: "New to your channel, or Just added"
val newOnPartner = RecommendationReasonNewOnPartner
  .Builder()
  .build()

//Allows us to construct reason: "Because you watched Star Wars"
val watchedSimilarTitles = RecommendationReasonWatchedSimilarTitles
  .addSimilarWatchedTitleName("Movie or TV Show Title")
  .addSimilarWatchedTitleName("Movie or TV Show Title")
  .Builder()
  .build()

//Allows us to construct reason: "Recommended for you by ChannelName"
val recommendedForUser = RecommendationReasonRecommendedForUser
  .Builder()
  .build()

val watchAgain = RecommendationReasonWatchAgain
  .Builder()
  .build()

val fromUserWatchList = RecommendationReasonFromUserWatchlist
  .Builder()
  .build()

val userLikedOnPartner = RecommendationReasonUserLikedOnPartner
  .Builder()
  .setTitleName("Movie or TV Show Title")
  .build()

val generic = RecommendationReasonGeneric.Builder().build()

Отображение временного окна

Если сущность должна быть доступна только в течение ограниченного времени, задайте произвольное время истечения срока действия. Без явного указания срока действия сущности автоматически устаревают и удаляются через 60 дней. Поэтому задавайте время истечения срока действия только в тех случаях, когда требуется более ранний истечение срока действия сущности. Укажите несколько таких окон доступности.

val window1 = DisplayTimeWindow
  .Builder()
  .setStartTimeStampMillis(now()+ 1.days.toMillis())
  .setEndTimeStampMillis(now()+ 30.days.toMillis())

val window2 = DisplayTimeWindow
  .Builder()
  .setEndTimeStampMillis(now()+ 30.days.toMillis())

val availabilityTimeWindows: List<DisplayTimeWindow> = listof(window1,window2)

DataFeedElementId

Если вы интегрировали свой каталог медиаконтента или фид действий с Google TV, вам не нужно создавать отдельные сущности для фильмов и телепередач. Вместо этого вы можете создать сущность MediaActionFeed с обязательным полем DataFeedElementId. Этот идентификатор должен быть уникальным и совпадать с идентификатором в фиде действий с Media, поскольку он помогает идентифицировать загруженный контент фида и выполнять поиск медиаконтента.

val id = "dataFeedEleemntId"

MovieEntity

Вот пример создания MovieEntity со всеми обязательными полями:


val movieEntity = MovieEntity.Builder()
  .setName("Movie name")
  .setDescription("A sentence describing movie.")
  .addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
  .addPosterImages(images)
  // Suppose the duration is 2 hours, it is 72000000 in milliseconds
  .setDurationMills(72000000)
  .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);
//Suppose release date is 11-02-2025
val releaseDate  = 1739233800000L
val movieEntity = MovieEntity.Builder()
  ...
  .addGenres(genres)
  .setReleaseDateEpochMillis(releaseDate)
  .addContentRatings(contentRatings)
  .setRecommendationReason(topOnPartner or watchedSimilarTitles)
  .addAllAvailabilityTimeWindows(availabilityTimeWindows)
  .build()

TvShowEntity

Вот пример создания TvShowEntity со всеми необходимыми полями:

val tvShowEntity = TvShowEntity.Builder()
  .setName("Show title")
  .setDescription("A sentence describing TV Show.")
  .addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
  .addPosterImages(images)
  .build();

При желании укажите дополнительные данные, такие как жанры, рейтинги контента, причина рекомендации, цена предложения, количество сезонов или временное окно доступности, которые могут быть использованы Google TV для улучшенного отображения или фильтрации.

val genres = Arrays.asList("Action", "Science fiction");
val rating1 = RatingSystem.Builder()
  .setAgencyName("MPAA")
  .setRating("pg-13")
  .build();
val price = Price.Builder()
  .setCurrentPrice("$14.99")
  .setStrikethroughPrice("$16.99")
  .build();
val contentRatings = Arrays.asList(rating1);
val seasonCount = 5;
val tvShowEntity = TvShowEntity.Builder()
  ...
  .addGenres(genres)
  .addContentRatings(contentRatings)
  .setRecommendationReason(topOnPartner or watchedSimilarTitles)
  .addAllAvailabilityTimeWindows(availabilityTimeWindows)
  .setSeasonCount(seasonCount)
  .setPrice(price)
  .build()

MediaActionFeedEntity

Вот пример создания MediaActionFeedEntity со всеми обязательными полями:


val mediaActionFeedEntity = MediaActionFeedEntity.Builder()
  .setDataFeedElementId(id)
  .build()

При желании укажите дополнительные данные, такие как описание, причина рекомендации и временное окно отображения, которые могут быть использованы Google TV для улучшенного отображения или фильтрации.

val mediaActionFeedEntity = MediaActionFeedEntity.Builder()
  .setName("Movie name or TV Show name")
  .setDescription("A sentence describing an entity")
  .setRecommendationReason(topOnPartner or watchedSimilarTitles)
  .addPosterImages(images)
  .build()

LiveTvChannelEntity

Это представляет собой канал прямого эфира. Вот пример создания объекта LiveTvChannelEntity со всеми необходимыми полями:

val liveTvChannelEntity = LiveTvChannelEntity.Builder()
  .setName("Channel Name")
  // ID of the live TV channel
  .setEntityId("https://www.example.com/channel/12345")
  .setDescription("A sentence describing this live TV channel.")
  // channel playback uri must contain at least PlatformType.TYPE_ANDROID_TV
  .addPlatformSpecificPlaybackUri(channelPlaybackUris)
  .addLogoImage(logoImage)
  .build()

При желании укажите дополнительные данные, такие как рейтинги контента или причину рекомендации.

val rating1 = RatingSystem.Builder()
  .setAgencyName("MPAA")
  .setRating("pg-13")
  .build()
val contentRatings = Arrays.asList(rating1)

val liveTvChannelEntity = LiveTvChannelEntity.Builder()
  ...
  .addContentRatings(contentRatings)
  .setRecommendationReason(topOnPartner)
  .build()

LiveTvProgramEntity

Это карточка программы, которая транслируется в прямом эфире или запланирована к трансляции на канале в прямом эфире. Вот пример создания объекта LiveTvProgramEntity со всеми обязательными полями:

val liveTvProgramEntity = LiveTvProgramEntity.Builder()
  // First set the channel information
  .setChannelName("Channel Name")
  .setChanelId("https://www.example.com/channel/12345")
  // channel playback uri must contain at least PlatformType.TYPE_ANDROID_TV
  .addPlatformSpecificPlaybackUri(channelPlaybackUris)
  .setChannelLogoImage(channelLogoImage)
  // Then set the program or card specific information.
  .setName("Program Name")
  .setEntityId("https://www.example.com/schedule/123")
  .setDescription("Program Desccription")
  .addAvailabilityTimeWindow(
      DisplayTimeWindow.Builder()
        .setStartTimestampMillis(1756713600000L)// 2025-09-01T07:30:00+0000
        .setEndTimestampMillis(1756715400000L))// 2025-09-01T08:00:00+0000
  .addPosterImage(programImage)
  .build()

При желании укажите дополнительные данные, такие как рейтинги контента, жанры или причину рекомендации.

val rating1 = RatingSystem.Builder()
  .setAgencyName("MPAA")
  .setRating("pg-13")
  .build()
val contentRatings = Arrays.asList(rating1)
val genres = Arrays.asList("Action", "Science fiction")

val liveTvProgramEntity = LiveTvProgramEntity.Builder()
  ...
  .addContentRatings(contentRatings)
  .addGenres(genres)
  .setRecommendationReason(topOnPartner)
  .build()

Реализовав эти шаги, разработчики смогут успешно интегрировать рекомендации по видеоконтенту в Google TV, тем самым повышая уровень обнаружения и вовлеченности пользователей, обеспечивая единообразный и персонализированный просмотр для пользователей на всех их устройствах.