Используйте 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.5
      }
    

    для ТВ

    
      dependencies {
        implementation 'com.google.android.engage:engage-tv:1.0.2
      }
    
  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(movie)
  .addEntity(tvShow)
  .setTitle("Popular Movies")
  .build()

// cluster for top searches
val recommendationCluster2 = RecommendationCluster
  .Builder()
  .addEntity(movie)
  .addEntity(tvShow)
  .setTitle("Top Searches")
  .build()

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

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

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

  1. ID учетной записи: уникальный идентификатор, представляющий учетную запись пользователя в вашем приложении. Это может быть фактический ID учетной записи или его соответствующим образом замаскированная версия.
  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

Описание

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

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 Entertainment Space . Изображения высотой менее 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

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

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

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