Engage SDK Watch: инструкции по технической интеграции сторонних разработчиков

Повысьте вовлеченность пользователей в приложение, взаимодействуя с ними там, где они находятся. Интегрируйте Engage SDK, чтобы предоставлять пользователям контент с функцией «Продолжить просмотр» и персонализированные рекомендации непосредственно на различных платформах устройства: «Коллекции» , «Развлекательное пространство » и Play Store. Интеграция добавляет менее 50 КБ (в сжатом виде) к среднему размеру APK-файла и занимает у большинства приложений около недели на разработку. Узнайте больше на нашем корпоративном сайте .

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

Детали интеграции

Терминология

Данная интеграция включает в себя следующие три типа кластеров: Рекомендации , Продолжение и Рекомендуемые .

  • Кластеры рекомендаций отображают персонализированные предложения по контенту для просмотра от конкретного разработчика-партнера.

    Ваши рекомендации имеют следующую структуру:

    • Кластер рекомендаций: элемент пользовательского интерфейса, содержащий группу рекомендаций от одного и того же партнера-разработчика.

      Рисунок 1. Пользовательский интерфейс Entertainment Space, демонстрирующий кластер рекомендаций от одного партнера.
    • Сущность: Объект, представляющий отдельный элемент в кластере. Сущностью может быть фильм, телешоу, сериал, видео в прямом эфире и многое другое. Список поддерживаемых типов сущностей см. в разделе «Предоставление данных сущности» .

      Рисунок 2. Пользовательский интерфейс Entertainment Space, отображающий отдельную сущность в кластере рекомендаций одного партнера.
  • В разделе «Продолжение» отображаются незавершенные видеоролики и актуальные новые эпизоды от нескольких партнеров-разработчиков в одном пользовательском интерфейсе. Каждому партнеру-разработчику будет разрешено транслировать максимум 10 объектов в этом разделе. Исследования показали, что персонализированные рекомендации в сочетании с персонализированным контентом раздела «Продолжение» обеспечивают наилучшее вовлечение пользователей.

    Рисунок 3. Пользовательский интерфейс Entertainment Space, демонстрирующий кластер «Продолжение» с незавершенными рекомендациями от нескольких партнеров (в данный момент видна только одна рекомендация).
  • В разделе «Рекомендуемые» отображается подборка объектов от нескольких партнеров-разработчиков в одном интерфейсе. Будет создан единый раздел «Рекомендуемые», который будет отображаться в верхней части интерфейса с приоритетным размещением над всеми разделами «Рекомендуемые». Каждому партнеру-разработчику будет разрешено транслировать до 10 объектов в разделе «Рекомендуемые».

    Рисунок 4. Пользовательский интерфейс Entertainment Space, отображающий группу рекомендуемых товаров с предложениями от нескольких партнеров (в данный момент видна только одна рекомендация).

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

Минимальный уровень API: 19

Добавьте библиотеку com.google.android.engage:engage-core в ваше приложение:

dependencies {
    // Make sure you also include that repository in your project's build.gradle file.
    implementation 'com.google.android.engage:engage-core:1.5.12'
}

Для получения дополнительной информации см. раздел «Видимость пакетов в Android 11» .

Краткое содержание

Данная архитектура основана на реализации привязанного сервиса .

Для различных типов кластеров объем данных, которые может публиковать клиент, ограничен следующими лимитами:

Тип кластера Границы кластера Максимальное количество объектов в кластере.
Кластер(ы) рекомендаций Максимум 7 Максимум 50
Кластер продолжения Не более 1 Максимум 20
Выделенный кластер Не более 1 Максимум 20

Шаг 0: Переход от существующей интеграции Media Home SDK

Сопоставление моделей данных из существующей интеграции

Если вы переходите с существующей интеграции Media Home, в следующей таблице описано, как сопоставить модели данных в существующих SDK с новым SDK Engage:

Аналог интеграции MediaHomeVideoContract Аналог интеграции Engage SDK
com.google.android.mediahome.video.PreviewChannel com.google.android.engage.common.datamodel.RecommendationCluster
com.google.android.mediahome.video.PreviewChannel.Builder com.google.android.engage.common.datamodel.RecommendationCluster.Builder
com.google.android.mediahome.video.PreviewChannelHelper com.google.android.engage.video.service.AppEngageVideoClient
com.google.android.mediahome.video.PreviewProgram Разделено на отдельные классы: EventVideo , LiveStreamingVideo , Movie , TvEpisode , TvSeason , TvShow , VideoClipEntity
com.google.android.mediahome.video.PreviewProgram.Builder Разделено на конструкторы в отдельных классах: EventVideo , LiveStreamingVideo , Movie , TvEpisode , TvSeason , TvShow , VideoClipEntity
com.google.android.mediahome.video.VideoContract Больше не требуется.
com.google.android.mediahome.video.WatchNextProgram Разделено на атрибуты в отдельных классах: EventVideoEntity , LiveStreamingVideoEntity , MovieEntity , TvEpisodeEntity , TvSeasonEntity , TvShowEntity , VideoClipEntity
com.google.android.mediahome.video.WatchNextProgram.Builder Разделено на атрибуты в отдельных классах: EventVideoEntity , LiveStreamingVideoEntity , MovieEntity , TvEpisodeEntity , TvSeasonEntity , TvShowEntity , VideoClipEntity

Кластеры публикации в Media Home SDK и Engage SDK

В Media Home SDK кластеры и сущности публиковались через отдельные API:

// 1. Fetch existing channels
List<PreviewChannel> channels = PreviewChannelHelper.getAllChannels();

// 2. If there are no channels, publish new channels
long channelId = PreviewChannelHelper.publishChannel(builder.build());

// 3. If there are existing channels, decide whether to update channel contents
PreviewChannelHelper.updatePreviewChannel(channelId, builder.build());

// 4. Delete all programs in the channel
PreviewChannelHelper.deleteAllPreviewProgramsByChannelId(channelId);

// 5. publish new programs in the channel
PreviewChannelHelper.publishPreviewProgram(builder.build());

В Engage SDK публикация кластеров и сущностей объединена в один вызов API. Все сущности, принадлежащие кластеру, публикуются вместе с этим кластером:

Котлин

RecommendationCluster.Builder()
            .addEntity(MOVIE_ENTITY)
            .addEntity(MOVIE_ENTITY)
            .addEntity(MOVIE_ENTITY)
            .setTitle("Top Picks For You")
            .build()

Java

new RecommendationCluster.Builder()
                        .addEntity(MOVIE_ENTITY)
                        .addEntity(MOVIE_ENTITY)
                        .addEntity(MOVIE_ENTITY)
                        .setTitle("Top Picks For You")
                        .build();

Шаг 1: Предоставьте данные сущности.

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

  1. MovieEntity
  2. TvShowEntity
  3. TvSeasonEntity
  4. TvEpisodeEntity
  5. LiveStreamingVideoEntity
  6. VideoClipEntity

В следующей таблице представлены характеристики и требования для каждого типа.

MovieEntity

Атрибут Требование Примечания
Имя Необходимый
Изображения для плакатов Необходимый Необходимо предоставить как минимум одно изображение с указанием соотношения сторон. (Предпочтительно альбомная ориентация, но рекомендуется предоставить как портретное, так и альбомное изображение для разных сценариев.)

См. раздел «Технические характеристики изображения» для получения дополнительной информации.

URI воспроизведения Необходимый

Прямая ссылка на приложение поставщика услуг для начала воспроизведения фильма.

Примечание: Для указания источника можно использовать прямые ссылки. См. этот раздел часто задаваемых вопросов.

Информационная страница URI Необязательный

Прямая ссылка на приложение поставщика услуг для отображения подробной информации о фильме.

Примечание: Для указания источника можно использовать прямые ссылки. См. этот раздел часто задаваемых вопросов.

Дата выпуска Необязательный В миллисекундах эпохи.
Доступность Необходимый

ДОСТУПНО: Контент доступен пользователю без каких-либо дополнительных действий.

БЕСПЛАТНО_С_ПОДПИСКОЙ: Контент становится доступен после приобретения пользователем подписки.

ПЛАТНЫЙ КОНТЕНТ: Для доступа к контенту пользователю необходимо приобрести или взять его в аренду.

ПРИОБРЕТЕНО: Пользователь приобрел или взял напрокат данный контент.

Предложенная цена Необязательный Свободный текст
Продолжительность Необходимый В миллисекундах.
Жанр Необходимый Свободный текст
Возрастные рейтинги Необязательный Свободный текст, соответствующий отраслевым стандартам. ( Пример )
Текст призыва к действию Необязательный Свободный текст для отображения в качестве призыва к действию.
Теги Необязательный Список тегов, связанных с сущностью.
Смотрите следующий тип Условно обязательно

Этот параметр должен быть предоставлен, если элемент находится в кластере "Продолжение" и должен относиться к одному из следующих четырех типов:

ПРОДОЛЖИТЬ: Пользователь уже просмотрел более 1 минуты этого контента.

НОВОЕ: Пользователь просмотрел все доступные эпизоды какого-либо сериала, но появился новый эпизод, и остался ровно один непросмотренный эпизод. Это работает для телешоу, записанных футбольных матчей в сериале и так далее.

ДАЛЕЕ: Пользователь посмотрел один или несколько полных эпизодов какого-либо сериала, но осталось либо более одного эпизода, либо ровно один эпизод, последний из которых не является «НОВЫМ» и был выпущен до того, как пользователь начал смотреть сериал.

СПИСОК ПРОСМОТРА: Пользователь явно выбрал добавление фильма, события или сериала в список просмотра, чтобы вручную отбирать то, что он хочет посмотреть дальше.

Последнее время помолвки Условно обязательно Необходимо указать, когда элемент находится в кластере продолжения. В миллисекундах эпохи.
Время последней позиции воспроизведения Условно обязательно Этот параметр необходимо указать, если элемент находится в кластере Continuation и WatchNextType имеет значение CONTINUE. Значение указывается в миллисекундах с начала эпохи.

TvShowEntity

Атрибут Требование Примечания
Имя Необходимый
Изображения для плакатов Необходимый Необходимо предоставить как минимум одно изображение с указанием соотношения сторон. (Предпочтительно альбомная ориентация, но рекомендуется предоставить как портретное, так и альбомное изображение для разных сценариев.)

См. раздел «Технические характеристики изображения» для получения дополнительной информации.

Информационная страница URI Необходимый

Прямая ссылка на приложение поставщика услуг для отображения подробной информации о телешоу.

Примечание: Для указания источника можно использовать прямые ссылки. См. этот раздел часто задаваемых вопросов.

URI воспроизведения Необязательный

Прямая ссылка на приложение поставщика услуг для начала воспроизведения телешоу.

Примечание: Для указания источника можно использовать прямые ссылки. См. этот раздел часто задаваемых вопросов.

Дата выхода первого эпизода в эфир Необязательный В миллисекундах эпохи.
Дата выхода последней серии Необязательный В миллисекундах эпохи.
Доступность Необходимый

ДОСТУПНО: Контент доступен пользователю без каких-либо дополнительных действий.

БЕСПЛАТНО_С_ПОДПИСКОЙ: Контент становится доступен после приобретения пользователем подписки.

ПЛАТНЫЙ КОНТЕНТ: Для доступа к контенту пользователю необходимо приобрести или взять его в аренду.

ПРИОБРЕТЕНО: Пользователь приобрел или взял напрокат данный контент.

Предложенная цена Необязательный Свободный текст
Количество сезонов Необходимый Положительное целое число
Жанр Необходимый Свободный текст
Возрастные рейтинги Необязательный Свободный текст, соответствующий отраслевым стандартам. ( Пример )
Текст призыва к действию Необязательный Свободный текст для отображения в качестве призыва к действию.
Теги Необязательный Список тегов, связанных с сущностью.
Смотрите следующий тип Условно обязательно

Этот параметр должен быть предоставлен, если элемент находится в кластере "Продолжение" и должен относиться к одному из следующих четырех типов:

ПРОДОЛЖИТЬ: Пользователь уже просмотрел более 1 минуты этого контента.

НОВОЕ: Пользователь просмотрел все доступные эпизоды какого-либо сериала, но появился новый эпизод, и остался ровно один непросмотренный эпизод. Это работает для телешоу, записанных футбольных матчей в сериале и так далее.

ДАЛЕЕ: Пользователь посмотрел один или несколько полных эпизодов какого-либо сериала, но осталось либо более одного эпизода, либо ровно один эпизод, последний из которых не является «НОВЫМ» и был выпущен до того, как пользователь начал смотреть сериал.

СПИСОК ПРОСМОТРА: Пользователь явно выбрал добавление фильма, события или сериала в список просмотра, чтобы вручную отбирать то, что он хочет посмотреть дальше.

Последнее время помолвки Условно обязательно Необходимо указать, когда элемент находится в кластере продолжения. В миллисекундах эпохи.
Время последней позиции воспроизведения Условно обязательно Этот параметр необходимо указать, если элемент находится в кластере Continuation и WatchNextType имеет значение CONTINUE. Значение указывается в миллисекундах с начала эпохи.

TvSeasonEntity

Атрибут Требование Примечания
Имя Необходимый
Изображения для плакатов Необходимый Необходимо предоставить как минимум одно изображение с указанием соотношения сторон. (Предпочтительно альбомная ориентация, но рекомендуется предоставить как портретное, так и альбомное изображение для разных сценариев.)

См. раздел «Технические характеристики изображения» для получения дополнительной информации.

Информационная страница URI Необходимый

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

Примечание: Для указания источника можно использовать прямые ссылки. См. этот раздел часто задаваемых вопросов.

URI воспроизведения Необязательный

Прямая ссылка на приложение провайдера для начала воспроизведения сезона телешоу.

Примечание: Для указания источника можно использовать прямые ссылки. См. этот раздел часто задаваемых вопросов.

Показать номер сезона

Необязательный

Доступно в версии 1.3.1

Нить
Дата выхода первого эпизода в эфир Необязательный В миллисекундах эпохи.
Дата выхода последней серии Необязательный В миллисекундах эпохи.
Доступность Необходимый

ДОСТУПНО: Контент доступен пользователю без каких-либо дополнительных действий.

БЕСПЛАТНО_С_ПОДПИСКОЙ: Контент становится доступен после приобретения пользователем подписки.

ПЛАТНЫЙ КОНТЕНТ: Для доступа к контенту пользователю необходимо приобрести или взять его в аренду.

ПРИОБРЕТЕНО: Пользователь приобрел или взял напрокат данный контент.

Предложенная цена Необязательный Свободный текст
Количество эпизодов Необходимый Положительное целое число
Жанр Необходимый Свободный текст
Возрастные рейтинги Необязательный Свободный текст, соответствующий отраслевым стандартам. ( Пример )
Текст призыва к действию Необязательный Свободный текст для отображения в качестве призыва к действию.
Теги Необязательный Список тегов, связанных с сущностью.
Смотрите следующий тип Условно обязательно

Этот параметр должен быть предоставлен, если элемент находится в кластере "Продолжение" и должен относиться к одному из следующих четырех типов:

ПРОДОЛЖИТЬ: Пользователь уже просмотрел более 1 минуты этого контента.

НОВОЕ: Пользователь просмотрел все доступные эпизоды какого-либо сериала, но появился новый эпизод, и остался ровно один непросмотренный эпизод. Это работает для телешоу, записанных футбольных матчей в сериале и так далее.

ДАЛЕЕ: Пользователь посмотрел один или несколько полных эпизодов какого-либо сериала, но осталось либо более одного эпизода, либо ровно один эпизод, последний из которых не является «НОВЫМ» и был выпущен до того, как пользователь начал смотреть сериал.

СПИСОК ПРОСМОТРА: Пользователь явно выбрал добавление фильма, события или сериала в список просмотра, чтобы вручную отбирать то, что он хочет посмотреть дальше.

Последнее время помолвки Условно обязательно Необходимо указать, когда элемент находится в кластере продолжения. В миллисекундах эпохи.
Время последней позиции воспроизведения Условно обязательно Этот параметр необходимо указывать, если элемент находится в кластере Continuation и WatchNextType имеет значение CONTINUE. Значение указывается в миллисекундах с начала эпохи.

TvEpisodeEntity

Атрибут Требование Примечания
Имя Необходимый
Изображения для плакатов Необходимый Необходимо предоставить как минимум одно изображение с указанием соотношения сторон. (Предпочтительно альбомная ориентация, но рекомендуется предоставить как портретное, так и альбомное изображение для разных сценариев.)

См. раздел «Технические характеристики изображения» для получения дополнительной информации.

URI воспроизведения Необходимый

Прямая ссылка на приложение поставщика услуг для начала воспроизведения эпизода.

Примечание: Для указания источника можно использовать прямые ссылки. См. этот раздел часто задаваемых вопросов.

Информационная страница URI Необязательный

Прямая ссылка на приложение поставщика услуг для отображения подробной информации об эпизоде ​​телешоу.

Примечание: Для указания источника можно использовать прямые ссылки. См. этот раздел часто задаваемых вопросов.

Показать номер эпизода

Необязательный

Доступно в версии 1.3.1

Нить
Дата выхода в эфир Необходимый В миллисекундах эпохи.
Доступность Необходимый

ДОСТУПНО: Контент доступен пользователю без каких-либо дополнительных действий.

БЕСПЛАТНО_С_ПОДПИСКОЙ: Контент становится доступен после приобретения пользователем подписки.

ПЛАТНЫЙ КОНТЕНТ: Для доступа к контенту пользователю необходимо приобрести или взять его в аренду.

ПРИОБРЕТЕНО: Пользователь приобрел или взял напрокат данный контент.

Предложенная цена Необязательный Свободный текст
Продолжительность Необходимый Должно быть положительное значение в миллисекундах.
Жанр Необходимый Свободный текст
Возрастные рейтинги Необязательный Свободный текст, соответствующий отраслевым стандартам. ( Пример )
Текст призыва к действию Необязательный Свободный текст для отображения в качестве призыва к действию.
Теги Необязательный Список тегов, связанных с сущностью.
Смотрите следующий тип Условно обязательно

Этот параметр должен быть предоставлен, если элемент находится в кластере "Продолжение" и должен относиться к одному из следующих четырех типов:

ПРОДОЛЖИТЬ: Пользователь уже просмотрел более 1 минуты этого контента.

НОВОЕ: Пользователь просмотрел все доступные эпизоды какого-либо сериала, но появился новый эпизод, и остался ровно один непросмотренный эпизод. Это работает для телешоу, записанных футбольных матчей в сериале и так далее.

ДАЛЕЕ: Пользователь посмотрел один или несколько полных эпизодов какого-либо сериала, но осталось либо более одного эпизода, либо ровно один эпизод, последний из которых не является «НОВЫМ» и был выпущен до того, как пользователь начал смотреть сериал.

СПИСОК ПРОСМОТРА: Пользователь явно выбрал добавление фильма, события или сериала в список просмотра, чтобы вручную отбирать то, что он хочет посмотреть дальше.

Последнее время помолвки Условно обязательно Необходимо указать, когда элемент находится в кластере продолжения. В миллисекундах эпохи.
Время последней позиции воспроизведения Условно обязательно Этот параметр необходимо указывать, если элемент находится в кластере Continuation и WatchNextType имеет значение CONTINUE. Значение указывается в миллисекундах с начала эпохи.

LiveStreamingVideoEntity

Атрибут Требование Примечания
Имя Необходимый
Изображения для плакатов Необходимый Необходимо предоставить как минимум одно изображение с указанием соотношения сторон. (Предпочтительно альбомная ориентация, но рекомендуется предоставить как портретное, так и альбомное изображение для разных сценариев.)

См. раздел «Технические характеристики изображения» для получения дополнительной информации.

URI воспроизведения Необходимый

Прямая ссылка на приложение поставщика услуг для начала воспроизведения видео.

Примечание: Для указания источника можно использовать прямые ссылки. См. этот раздел часто задаваемых вопросов.

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

Этот параметр должен быть предоставлен, если элемент находится в кластере "Продолжение" и должен относиться к одному из следующих четырех типов:

ПРОДОЛЖИТЬ: Пользователь уже просмотрел более 1 минуты этого контента.

НОВОЕ: Пользователь просмотрел все доступные эпизоды какого-либо сериала, но появился новый эпизод, и остался ровно один непросмотренный эпизод. Это работает для телешоу, записанных футбольных матчей в сериале и так далее.

ДАЛЕЕ: Пользователь посмотрел один или несколько полных эпизодов какого-либо сериала, но осталось либо более одного эпизода, либо ровно один эпизод, последний из которых не является «НОВЫМ» и был выпущен до того, как пользователь начал смотреть сериал.

СПИСОК ПРОСМОТРА: Пользователь явно выбрал добавление фильма, события или сериала в список просмотра, чтобы вручную отбирать то, что он хочет посмотреть дальше.

Последнее время помолвки Условно обязательно Необходимо указать, когда элемент находится в кластере продолжения. В миллисекундах эпохи.
Время последней позиции воспроизведения Условно обязательно Этот параметр необходимо указывать, если элемент находится в кластере Continuation и WatchNextType имеет значение CONTINUE. Значение указывается в миллисекундах с начала эпохи.

VideoClipEntity

Объект VideoClipEntity представляет собой видеоконтент, полученный из социальных сетей, таких как TikTok или YouTube.

Атрибут Требование Примечания
Имя Необходимый
Изображения для плакатов Необходимый Необходимо предоставить как минимум одно изображение с указанием соотношения сторон. (Предпочтительно альбомная ориентация, но рекомендуется предоставить как портретное, так и альбомное изображение для разных сценариев.)

См. раздел «Технические характеристики изображения» для получения дополнительной информации.

URI воспроизведения Необходимый

Прямая ссылка на приложение поставщика услуг для начала воспроизведения видео.

Примечание: Для указания источника можно использовать прямые ссылки. См. этот раздел часто задаваемых вопросов.

Время создания Необходимый В миллисекундах эпохи.
Продолжительность Необходимый Должно быть положительное значение в миллисекундах.
Создатель Необходимый Свободный текст
Изображение создателя Необязательный Изображение аватара Творца
Количество просмотров Необязательный Свободный текст, должен быть локализован.
Текст призыва к действию Необязательный Свободный текст для отображения в качестве призыва к действию.
Теги Необязательный Список тегов, связанных с сущностью.
Смотрите следующий тип Условно обязательно

Этот параметр должен быть предоставлен, если элемент находится в кластере "Продолжение" и должен относиться к одному из следующих четырех типов:

ПРОДОЛЖИТЬ: Пользователь уже просмотрел более 1 минуты этого контента.

НОВОЕ: Пользователь просмотрел все доступные эпизоды какого-либо сериала, но появился новый эпизод, и остался ровно один непросмотренный эпизод. Это работает для телешоу, записанных футбольных матчей в сериале и так далее.

ДАЛЕЕ: Пользователь посмотрел один или несколько полных эпизодов какого-либо сериала, но осталось либо более одного эпизода, либо ровно один эпизод, последний из которых не является «НОВЫМ» и был выпущен до того, как пользователь начал смотреть сериал.

СПИСОК ПРОСМОТРА: Пользователь явно выбрал добавление фильма, события или сериала в список просмотра, чтобы вручную отбирать то, что он хочет посмотреть дальше.

Последнее время помолвки Условно обязательно Необходимо указать, когда элемент находится в кластере продолжения. В миллисекундах эпохи.
Время последней позиции воспроизведения Условно обязательно Этот параметр необходимо указывать, если элемент находится в кластере Continuation и WatchNextType имеет значение CONTINUE. Значение указывается в миллисекундах с начала эпохи.

Технические характеристики изображения

В следующем разделе перечислены необходимые спецификации для графических ресурсов:

Форматы файлов

PNG, JPG, статический GIF, WebP

Максимальный размер файла

5120 КБ

Дополнительные рекомендации

  • Безопасная зона изображения: разместите важный контент в центральных 80% изображения.

Пример

Котлин

var movie = MovieEntity.Builder()
    .setName("Avengers")
    .addPosterImage(Image.Builder()
                          .setImageUri(Uri.parse("http://www.x.com/image.png"))
                          .setImageHeightInPixel(960)
                          .setImageWidthInPixel(408)
                          .build())
    .setPlayBackUri(Uri.parse("http://tv.com/playback/1"))
    .setReleaseDateEpochMillis(1633032895L)
    .setAvailability(ContentAvailability.AVAILABILITY_AVAILABLE)
    .setDurationMillis(12345678L)
    .addGenre("action")
    .addContentRating("R")
    .setWatchNextType(WatchNextType.TYPE_NEW)
    .setLastEngagementTimeMillis(1664568895L)
    .setCallToActionText("Watch Now")
    .addTag("Action")
    .build()

Java

MovieEntity movie = new MovieEntity.Builder()
                  .setName("Avengers")
                  .addPosterImage(
                      new Image.Builder()
                          .setImageUri(Uri.parse("http://www.x.com/image.png"))
                          .setImageHeightInPixel(960)
                          .setImageWidthInPixel(408)
                          .build())
                  .setPlayBackUri(Uri.parse("http://tv.com/playback/1"))
                  .setReleaseDateEpochMillis(1633032895L)
                  .setAvailability(ContentAvailability.AVAILABILITY_AVAILABLE)
                  .setDurationMillis(12345678L)
                  .addGenre("action")
                  .addContentRating("R")
                  .setWatchNextType(WatchNextType.TYPE_NEW)
                  .setLastEngagementTimeMillis(1664568895L)
                  .setCallToActionText("Watch Now")
                  .addTag("Action")
                  .build();

Шаг 2: Предоставьте данные кластера.

Рекомендуется запускать задачу публикации контента в фоновом режиме (например, с помощью WorkManager ) и планировать ее выполнение на регулярной основе или по событию (например, каждый раз, когда пользователь открывает приложение или добавляет товар в корзину).

AppEngagePublishClient отвечает за публикацию кластеров. В клиенте доступны следующие API:

  • isServiceAvailable
  • publishRecommendationClusters
  • publishFeaturedCluster
  • publishContinuationCluster
  • publishUserAccountManagementRequest
  • updatePublishStatus
  • deleteRecommendationsClusters
  • deleteFeaturedCluster
  • deleteContinuationCluster
  • deleteUserManagementCluster
  • deleteClusters

isServiceAvailable

Этот API используется для проверки доступности сервиса для интеграции и возможности отображения контента на устройстве.

Котлин

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.
        } else {
          // Service is not available, no further action is needed.
        }
    } else {
      // The IPC call itself fails, proceed with error handling logic here,
      // such as retry.
    }
}

Java

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

publishRecommendationClusters

Этот API используется для публикации списка объектов RecommendationCluster .

Котлин

client.publishRecommendationClusters(
      PublishRecommendationClustersRequest.Builder()
        .addRecommendationCluster(
          RecommendationCluster.Builder()
            .addEntity(entity1)
            .addEntity(entity2)
            .setTitle("Top Picks For You")
            .build()
        )
        .build()
    )

Java

client.publishRecommendationClusters(
            new PublishRecommendationClustersRequest.Builder()
                .addRecommendationCluster(
                    new RecommendationCluster.Builder()
                        .addEntity(entity1)
                        .addEntity(entity2)
                        .setTitle("Top Picks For You")
                        .build())
                .build());

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

  • Существующие данные RecommendationCluster от партнера-разработчика удалены.
  • Данные из запроса анализируются и сохраняются в обновленном кластере рекомендаций.

В случае ошибки весь запрос отклоняется, и сохраняется текущее состояние.

publishFeaturedCluster

Этот API используется для публикации списка объектов FeaturedCluster .

Котлин

client.publishFeaturedCluster(
    PublishFeaturedClusterRequest.Builder()
      .setFeaturedCluster(
        FeaturedCluster.Builder()
          .addEntity(entity1)
          .addEntity(entity2)
          .build())
      .build())

Java

client.publishFeaturedCluster(
            new PublishFeaturedClustersRequest.Builder()
                .addFeaturedCluster(
                    new FeaturedCluster.Builder()
                        .addEntity(entity1)
                        .addEntity(entity2)
                        .build())
                .build());

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

  • Существующие данные FeaturedCluster от партнера-разработчика удаляются.
  • Данные из запроса анализируются и сохраняются в обновленном кластере избранных элементов.

В случае ошибки весь запрос отклоняется, и сохраняется текущее состояние.

publishContinuationCluster

Этот API используется для публикации объекта ContinuationCluster .

Котлин

client.publishContinuationCluster(
    PublishContinuationClusterRequest.Builder()
      .setContinuationCluster(
        ContinuationCluster.Builder()
          .addEntity(entity1)
          .addEntity(entity2)
          .build())
      .build())

Java

client.publishContinuationCluster(
            new PublishContinuationClusterRequest.Builder()
                .setContinuationCluster(
                    new ContinuationCluster.Builder()
                        .addEntity(entity1)
                        .addEntity(entity2)
                        .build())
                .build());

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

  • Существующие данные ContinuationCluster от партнера-разработчика удаляются.
  • Данные из запроса анализируются и сохраняются в обновленном кластере продолжения работы.

В случае ошибки весь запрос отклоняется, и сохраняется текущее состояние.

publishUserAccountManagementRequest

Этот API используется для публикации карточки входа. Действие входа перенаправляет пользователей на страницу авторизации приложения, чтобы приложение могло опубликовать контент (или предоставить более персонализированный контент).

Следующие метаданные являются частью карточки входа в систему:

Атрибут Требование Описание
Action Uri Необходимый Глубокая ссылка на действие (т.е. переход на страницу входа в приложение)
Изображение Необязательно — если не указано, необходимо указать заголовок.

Изображение, показанное на карте

Изображения с соотношением сторон 16x9 и разрешением 1264x712.

Заголовок Изображение необязательно — если не указано, его необходимо предоставить. Название на карточке
Текст действия Необязательный Текст, отображаемый в призыве к действию (например, при входе в систему)
Субтитры Необязательный Дополнительный подзаголовок на карточке (по желанию)

Котлин

var SIGN_IN_CARD_ENTITY =
      SignInCardEntity.Builder()
          .addPosterImage(
              Image.Builder()
                  .setImageUri(Uri.parse("http://www.x.com/image.png"))
                  .setImageHeightInPixel(500)
                  .setImageWidthInPixel(500)
                  .build())
          .setActionText("Sign In")
          .setActionUri(Uri.parse("http://xx.com/signin"))
          .build()

client.publishUserAccountManagementRequest(
            PublishUserAccountManagementRequest.Builder()
                .setSignInCardEntity(SIGN_IN_CARD_ENTITY)
                .build());

Java

SignInCardEntity SIGN_IN_CARD_ENTITY =
      new SignInCardEntity.Builder()
          .addPosterImage(
              new Image.Builder()
                  .setImageUri(Uri.parse("http://www.x.com/image.png"))
                  .setImageHeightInPixel(500)
                  .setImageWidthInPixel(500)
                  .build())
          .setActionText("Sign In")
          .setActionUri(Uri.parse("http://xx.com/signin"))
          .build();

client.publishUserAccountManagementRequest(
            new PublishUserAccountManagementRequest.Builder()
                .setSignInCardEntity(SIGN_IN_CARD_ENTITY)
                .build());

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

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

В случае ошибки весь запрос отклоняется, и сохраняется текущее состояние.

updatePublishStatus

Если по каким-либо внутренним причинам ни один из кластеров не опубликован, мы настоятельно рекомендуем обновить статус публикации с помощью API updatePublishStatus . Это важно, потому что:

  • Указание статуса во всех сценариях, даже когда контент опубликован (STATUS == PUBLISHED), имеет решающее значение для заполнения панелей мониторинга, которые используют этот явный статус для отображения состояния и других показателей вашей интеграции.
  • Если контент не опубликован, но статус интеграции не нарушен (STATUS == NOT_PUBLISHED), Google может избежать срабатывания оповещений на панелях мониторинга состояния приложения. Это подтверждает, что контент не опубликован из-за ожидаемой ситуации с точки зрения поставщика.
  • Это помогает разработчикам получать информацию о том, когда данные публикуются, а когда нет.
  • Google может использовать коды состояния, чтобы подтолкнуть пользователя к выполнению определенных действий в приложении, чтобы он мог увидеть контент приложения или обойти его ограничения.

Список допустимых кодов статуса публикации:

// Content is published
AppEngagePublishStatusCode.PUBLISHED,

// Content is not published as user is not signed in
AppEngagePublishStatusCode.NOT_PUBLISHED_REQUIRES_SIGN_IN,

// Content is not published as user is not subscribed
AppEngagePublishStatusCode.NOT_PUBLISHED_REQUIRES_SUBSCRIPTION,

// Content is not published as user location is ineligible
AppEngagePublishStatusCode.NOT_PUBLISHED_INELIGIBLE_LOCATION,

// Content is not published as there is no eligible content
AppEngagePublishStatusCode.NOT_PUBLISHED_NO_ELIGIBLE_CONTENT,

// Content is not published as the feature is disabled by the client
// Available in v1.3.1
AppEngagePublishStatusCode.NOT_PUBLISHED_FEATURE_DISABLED_BY_CLIENT,

// Content is not published as the feature due to a client error
// Available in v1.3.1
AppEngagePublishStatusCode.NOT_PUBLISHED_CLIENT_ERROR,

// Content is not published as the feature due to a service error
// Available in v1.3.1
AppEngagePublishStatusCode.NOT_PUBLISHED_SERVICE_ERROR,

// Content is not published due to some other reason
// Reach out to engage-developers@ before using this enum.
AppEngagePublishStatusCode.NOT_PUBLISHED_OTHER

Если контент не публикуется из-за того, что пользователь не авторизован, Google рекомендует опубликовать карточку входа. Если по какой-либо причине поставщики не могут опубликовать карточку входа, мы рекомендуем вызвать API updatePublishStatus со статусом NOT_PUBLISHED_REQUIRES_SIGN_IN.

Котлин

client.updatePublishStatus(
   PublishStatusRequest.Builder()
     .setStatusCode(AppEngagePublishStatusCode.NOT_PUBLISHED_REQUIRES_SIGN_IN)
     .build())

Java

client.updatePublishStatus(
    new PublishStatusRequest.Builder()
        .setStatusCode(AppEngagePublishStatusCode.NOT_PUBLISHED_REQUIRES_SIGN_IN)
        .build());

deleteRecommendationClusters

Этот API используется для удаления содержимого кластеров рекомендаций.

Котлин

client.deleteRecommendationClusters()

Java

client.deleteRecommendationClusters();

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

deleteFeaturedCluster

Этот API используется для удаления содержимого раздела "Рекомендуемые кластеры".

Котлин

client.deleteFeaturedCluster()

Java

client.deleteFeaturedCluster();

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

deleteContinuationCluster

Этот API используется для удаления содержимого кластера продолжения.

Котлин

client.deleteContinuationCluster()

Java

client.deleteContinuationCluster();

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

deleteUserManagementCluster

Этот API используется для удаления содержимого кластера UserAccountManagement.

Котлин

client.deleteUserManagementCluster()

Java

client.deleteUserManagementCluster();

Когда служба получает запрос, она удаляет существующие данные из кластера UserAccountManagement. В случае ошибки весь запрос отклоняется, и сохраняется существующее состояние.

deleteClusters

Этот API используется для удаления содержимого кластера определенного типа.

Котлин

client.deleteClusters(
    DeleteClustersRequest.Builder()
      .addClusterType(ClusterType.TYPE_CONTINUATION)
      .addClusterType(ClusterType.TYPE_FEATURED)
      .addClusterType(ClusterType.TYPE_RECOMMENDATION)
      .build())

Java

client.deleteClusters(
            new DeleteClustersRequest.Builder()
                .addClusterType(ClusterType.TYPE_CONTINUATION)
                .addClusterType(ClusterType.TYPE_FEATURED)
                .addClusterType(ClusterType.TYPE_RECOMMENDATION)
                .build());

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

Обработка ошибок

Настоятельно рекомендуется отслеживать результаты выполнения задачи через API публикации, чтобы иметь возможность предпринять дальнейшие действия для восстановления и повторной отправки успешно выполненной задачи.

Котлин

client.publishRecommendationClusters(
        PublishRecommendationClustersRequest.Builder()
          .addRecommendationCluster(..)
          .build())
      .addOnCompleteListener { task ->
        if (task.isSuccessful) {
          // do something
        } else {
          val exception = task.exception
          if (exception is AppEngageException) {
            @AppEngageErrorCode val errorCode = exception.errorCode
            if (errorCode == AppEngageErrorCode.SERVICE_NOT_FOUND) {
              // do something
            }
          }
        }
      }

Java

client.publishRecommendationClusters(
              new PublishRecommendationClustersRequest.Builder()
                  .addRecommendationCluster(...)
                  .build())
          .addOnCompleteListener(
              task -> {
                if (task.isSuccessful()) {
                  // do something
                } else {
                  Exception exception = task.getException();
                  if (exception instanceof AppEngageException) {
                    @AppEngageErrorCode
                    int errorCode = ((AppEngageException) exception).getErrorCode();
                    if (errorCode == AppEngageErrorCode.SERVICE_NOT_FOUND) {
                      // do something
                    }
                  }
                }
              });

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

Код ошибки Название ошибки Примечание
1 SERVICE_NOT_FOUND Данная услуга недоступна на указанном устройстве.
2 SERVICE_NOT_AVAILABLE Услуга доступна на данном устройстве, но недоступна в момент звонка (например, она явно отключена).
3 SERVICE_CALL_EXECUTION_FAILURE Выполнение задачи завершилось с ошибкой из-за проблем с многопоточностью. В этом случае можно повторить попытку.
4 SERVICE_CALL_PERMISSION_DENIED Звонившему не разрешается вызывать специалиста для оказания услуги.
5 SERVICE_CALL_INVALID_ARGUMENT Запрос содержит недопустимые данные (например, большее количество кластеров, чем разрешено).
6 SERVICE_CALL_INTERNAL На стороне сервиса произошла ошибка.
7 SERVICE_CALL_RESOURCE_EXHAUSTED Вызов сервисной службы происходит слишком часто.

Шаг 3: Обработка широковещательных намерений

Помимо выполнения вызовов API для публикации контента через задание, также необходимо настроить BroadcastReceiver для приема запросов на публикацию контента.

Основная цель широковещательных интентов — повторная активация приложения и принудительная синхронизация данных. Широковещательные интенты не предназначены для частой отправки. Они срабатывают только тогда, когда служба Engage определяет, что контент может быть устаревшим (например, недельной давности). Таким образом, обеспечивается большая уверенность в том, что пользователь получит актуальный контент, даже если приложение долгое время не запускалось.

Для настройки BroadcastReceiver необходимо использовать два следующих способа:

  • Динамически зарегистрируйте экземпляр класса BroadcastReceiver с помощью Context.registerReceiver() . Это позволит осуществлять связь с приложениями, которые всё ещё находятся в оперативной памяти.

Котлин

class AppEngageBroadcastReceiver : BroadcastReceiver(){
  // Trigger recommendation cluster publish when PUBLISH_RECOMMENDATION broadcast
  // is received
  // Trigger featured cluster publish when PUBLISH_FEATURED broadcast is received
  // Trigger continuation cluster publish when PUBLISH_CONTINUATION broadcast is
  // received
}

fun registerBroadcastReceivers(context: Context){
  var  context = context
  context = context.applicationContext

// Register Recommendation Cluster Publish Intent
  context.registerReceiver(AppEngageBroadcastReceiver(),
                           IntentFilter(Intents.ACTION_PUBLISH_RECOMMENDATION),
                           com.google.android.engage.service.BroadcastReceiverPermissions.BROADCAST_REQUEST_DATA_PUBLISH_PERMISSION,
                           /*scheduler=*/null)

// Register Featured Cluster Publish Intent
  context.registerReceiver(AppEngageBroadcastReceiver(),
                           IntentFilter(Intents.ACTION_PUBLISH_FEATURED),
                           com.google.android.engage.service.BroadcastReceiverPermissions.BROADCAST_REQUEST_DATA_PUBLISH_PERMISSION,
                           /*scheduler=*/null)

// Register Continuation Cluster Publish Intent
  context.registerReceiver(AppEngageBroadcastReceiver(),
                           IntentFilter(Intents.ACTION_PUBLISH_CONTINUATION),
                           com.google.android.engage.service.BroadcastReceiverPermissions.BROADCAST_REQUEST_DATA_PUBLISH_PERMISSION,
                           /*scheduler=*/null)
}

Java

class AppEngageBroadcastReceiver extends BroadcastReceiver {
// Trigger recommendation cluster publish when PUBLISH_RECOMMENDATION broadcast
// is received

// Trigger featured cluster publish when PUBLISH_FEATURED broadcast is received

// Trigger continuation cluster publish when PUBLISH_CONTINUATION broadcast is
// received
}

public static void registerBroadcastReceivers(Context context) {

context = context.getApplicationContext();

// Register Recommendation Cluster Publish Intent
context.registerReceiver(new AppEngageBroadcastReceiver(),
                         new IntentFilter(com.google.android.engage.service.Intents. ACTION_PUBLISH_RECOMMENDATION),
                         com.google.android.engage.service.BroadcastReceiverPermissions.BROADCAST_REQUEST_DATA_PUBLISH_PERMISSION,
                         /*scheduler=*/null);

// Register Featured Cluster Publish Intent
context.registerReceiver(new AppEngageBroadcastReceiver(),
                         new IntentFilter(com.google.android.engage.service.Intents.ACTION_PUBLISH_FEATURED),
                         com.google.android.engage.service.BroadcastReceiverPermissions.BROADCAST_REQUEST_DATA_PUBLISH_PERMISSION,
                         /*scheduler=*/null);

// Register Continuation Cluster Publish Intent
context.registerReceiver(new AppEngageBroadcastReceiver(),
                         new IntentFilter(com.google.android.engage.service.Intents.ACTION_PUBLISH_CONTINUATION),
                         com.google.android.engage.service.BroadcastReceiverPermissions.BROADCAST_REQUEST_DATA_PUBLISH_PERMISSION,
                         /*scheduler=*/null);

}
  • В файле AndroidManifest.xml статически объявите реализацию с помощью тега <receiver> . Это позволит приложению получать широковещательные интенты, когда оно не запущено, а также позволит приложению публиковать контент.

<application>
   <receiver
      android:name=".AppEngageBroadcastReceiver"
      android:permission="com.google.android.engage.REQUEST_ENGAGE_DATA"
      android:exported="true"
      android:enabled="true">
      <intent-filter>
         <action android:name="com.google.android.engage.action.PUBLISH_RECOMMENDATION" />
      </intent-filter>
      <intent-filter>
         <action android:name="com.google.android.engage.action.PUBLISH_FEATURED" />
      </intent-filter>
      <intent-filter>
         <action android:name="com.google.android.engage.action.PUBLISH_CONTINUATION" />
      </intent-filter>
   </receiver>
</application>

Сервис отправляет следующие намерения :

  • com.google.android.engage.action.PUBLISH_RECOMMENDATION Рекомендуется инициировать вызов publishRecommendationClusters при получении этого намерения.
  • com.google.android.engage.action.PUBLISH_FEATURED Рекомендуется инициировать вызов publishFeaturedCluster при получении этого намерения.
  • com.google.android.engage.action.PUBLISH_CONTINUATION Рекомендуется инициировать вызов publishContinuationCluster при получении этого намерения.

Рабочий процесс интеграции

Пошаговое руководство по проверке интеграции после ее завершения см. в разделе «Рабочий процесс интеграции для разработчиков Engage» .

Часто задаваемые вопросы

Часто задаваемые вопросы по Engage SDK можно найти в разделе "Часто задаваемые вопросы".

Контакт

В случае возникновения вопросов в процессе интеграции обращайтесь по адресу engage-developers@google.com .

Следующие шаги

После завершения интеграции ваши дальнейшие действия будут следующими:

  • Отправьте электронное письмо на адрес engage-developers@google.com и прикрепите к нему свой интегрированный APK-файл, готовый к тестированию компанией Google.
  • Google проводит внутреннюю проверку и анализ, чтобы убедиться, что интеграция работает должным образом. Если потребуются изменения, Google свяжется с вами и предоставит всю необходимую информацию.
  • После завершения тестирования и если никаких изменений не потребуется, Google свяжется с вами, чтобы уведомить о возможности публикации обновленного и интегрированного APK-файла в Play Store.
  • После того, как Google подтвердит публикацию вашего обновленного APK-файла в Play Store, ваши разделы «Рекомендации» , «Рекомендуемые» и «Продолжение» могут быть опубликованы и видны пользователям.