На главном экране Android TV отображается пользовательский интерфейс, показывающий рекомендуемый контент в виде таблицы каналов и программ . Каждая строка соответствует каналу. Канал содержит карточки для каждой программы, доступной на этом канале:

В этом документе показано, как добавлять каналы и программы на главный экран, обновлять контент, обрабатывать действия пользователей и обеспечивать наилучшее взаимодействие с пользователями. (Если вы хотите глубже изучить API, попробуйте выполнить практическое задание по настройке главного экрана и посмотрите сессию Android TV на конференции I/O 2017 ).
Пользовательский интерфейс главного экрана
Приложения могут создавать новые каналы, добавлять, удалять и обновлять программы в канале, а также управлять порядком программ в канале. Например, приложение может создать канал под названием «Что нового» и отображать карточки с новыми доступными программами.
Приложения не могут управлять порядком отображения каналов на главном экране. Когда ваше приложение создает новый канал, главный экран добавляет его в конец списка каналов. Пользователь может изменять порядок каналов, скрывать и отображать их.
Канал Watch Next
Канал «Смотреть дальше» — это второй ряд на главном экране, после ряда приложений. Система создает и поддерживает этот канал. Ваше приложение может добавлять программы в канал «Смотреть дальше». Для получения дополнительной информации см. раздел «Добавление программ в канал «Смотреть дальше»» .
Каналы приложений
Все создаваемые вашим приложением каналы следуют этому жизненному циклу:
- Пользователь обнаруживает канал в вашем приложении и запрашивает добавление его на главный экран.
- Приложение создает канал и добавляет его в
TvProvider(на этом этапе канал не виден). - Приложение запрашивает у системы отображение канала.
- Система запрашивает у пользователя подтверждение на создание нового канала.
- Новый канал появляется в последней строке главного экрана.
Канал по умолчанию
Ваше приложение может предлагать пользователю любое количество каналов для добавления на главный экран. Обычно пользователю необходимо выбрать и подтвердить каждый канал, прежде чем он появится на главном экране. Каждое приложение имеет возможность создать один канал по умолчанию . Канал по умолчанию особенный, потому что он автоматически появляется на главном экране; пользователю не нужно явно запрашивать его.
Предварительные требования
Главный экран Android TV использует API TvProvider Android для управления каналами и программами, создаваемыми вашим приложением. Для доступа к данным поставщика добавьте следующее разрешение в манифест вашего приложения:
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
Библиотека поддержки TvProvider упрощает использование провайдера. Добавьте её в зависимости в файле build.gradle :
Классный
implementation 'androidx.tvprovider:tvprovider:1.0.0'
Котлин
implementation("androidx.tvprovider:tvprovider:1.0.0")
Для работы с каналами и программами обязательно включите в свою программу следующие импорты из библиотеки поддержки:
Котлин
import android.support.media.tv.Channel
import android.support.media.tv.TvContractCompat
import android.support.media.tv.ChannelLogoUtils
import android.support.media.tv.PreviewProgram
import android.support.media.tv.WatchNextProgram
Java
import android.support.media.tv.Channel;
import android.support.media.tv.TvContractCompat;
import android.support.media.tv.ChannelLogoUtils;
import android.support.media.tv.PreviewProgram;
import android.support.media.tv.WatchNextProgram;
Каналы
Первый созданный вашим приложением канал становится каналом по умолчанию. Канал по умолчанию автоматически отображается на главном экране. Все остальные создаваемые вами каналы должны быть выбраны и приняты пользователем, прежде чем они смогут отобразиться на главном экране.
Создание канала
Ваше приложение должно запрашивать у системы отображение недавно добавленных каналов только тогда, когда оно работает в фоновом режиме. Это предотвратит отображение диалогового окна с запросом на подтверждение добавления канала, когда пользователь запускает другое приложение. Если вы попытаетесь добавить канал, работая в фоновом режиме, метод onActivityResult() активности вернет код состояния RESULT_CANCELED .
Для создания канала выполните следующие шаги:
Создайте конструктор каналов и задайте его атрибуты. Обратите внимание, что тип канала должен быть
TYPE_PREVIEW. Добавьте дополнительные атрибуты по мере необходимости.Котлин
val builder = Channel.Builder() // Every channel you create must have the type `TYPE_PREVIEW` builder.setType(TvContractCompat.Channels.TYPE_PREVIEW) .setDisplayName("Channel Name") .setAppLinkIntentUri(uri)Java
Channel.Builder builder = new Channel.Builder(); // Every channel you create must have the type `TYPE_PREVIEW` builder.setType(TvContractCompat.Channels.TYPE_PREVIEW) .setDisplayName("Channel Name") .setAppLinkIntentUri(uri);Вставьте канал в настройки провайдера:
Котлин
var channelUri = context.contentResolver.insert( TvContractCompat.Channels.CONTENT_URI, builder.build().toContentValues())Java
Uri channelUri = context.getContentResolver().insert( TvContractCompat.Channels.CONTENT_URI, builder.build().toContentValues());Для добавления программ в канал в дальнейшем необходимо сохранить идентификатор канала. Извлеките идентификатор канала из возвращенного URI:
Котлин
var channelId = ContentUris.parseId(channelUri)Java
long channelId = ContentUris.parseId(channelUri);Необходимо добавить логотип для вашего канала. Используйте
UriилиBitmap. Значок логотипа должен быть размером 80dp x 80dp и должен быть непрозрачным. Он отображается под круглой маской:
Котлин
// Choose one or the other storeChannelLogo(context: Context, channelId: Long, logoUri: Uri) // also works if logoUri is a URL storeChannelLogo(context: Context, channelId: Long, logo: Bitmap)Java
// Choose one or the other storeChannelLogo(Context context, long channelId, Uri logoUri); // also works if logoUri is a URL storeChannelLogo(Context context, long channelId, Bitmap logo);Создайте канал по умолчанию (необязательно): Когда ваше приложение создаст свой первый канал, вы можете сделать его каналом по умолчанию , чтобы он сразу отображался на главном экране без каких-либо действий со стороны пользователя. Любые другие созданные вами каналы не будут видны, пока пользователь явно не выберет их.
Котлин
TvContractCompat.requestChannelBrowsable(context, channelId)Java
TvContractCompat.requestChannelBrowsable(context, channelId);Сделайте так, чтобы ваш основной канал отображался до открытия приложения. Для этого добавьте
BroadcastReceiver, который будет отслеживать действиеandroid.media.tv.action.INITIALIZE_PROGRAMS, отправляемое главным экраном после установки приложения:<receiver android:name=".RunOnInstallReceiver" android:exported="true"> <intent-filter> <action android:name="android.media.tv.action.INITIALIZE_PROGRAMS" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </receiver>При загрузке приложения в процессе разработки вы можете протестировать этот шаг, запустив Intent через adb, где your.package.name / .YourReceiverName — это
BroadcastReceiverвашего приложения:adb shell am broadcast -a android.media.tv.action.INITIALIZE_PROGRAMS -n \ your.package.name/.YourReceiverNameВ редких случаях ваше приложение может получать широковещательное сообщение одновременно с запуском приложения пользователем. Убедитесь, что ваш код не пытается добавить канал по умолчанию более одного раза.
Обновление канала
Обновление каналов очень похоже на их создание.
Используйте другой Channel.Builder для установки атрибутов, которые необходимо изменить.
Используйте ContentResolver для обновления канала. Используйте идентификатор канала, который вы сохранили при его первоначальном добавлении:
Котлин
context.contentResolver.update(
TvContractCompat.buildChannelUri(channelId),
builder.build().toContentValues(),
null,
null
)
Java
context.getContentResolver().update(TvContractCompat.buildChannelUri(channelId),
builder.build().toContentValues(), null, null);
Для обновления логотипа канала используйте storeChannelLogo() .
Удаление канала
Котлин
context.contentResolver.delete(TvContractCompat.buildChannelUri(channelId), null, null)
Java
context.getContentResolver().delete(TvContractCompat.buildChannelUri(channelId), null, null);
Программы
Программы — это отдельные карточки контента, отображаемые в рамках канала. Вы можете публиковать программы как в пользовательские каналы вашего приложения, так и в управляемый системой канал «Смотреть дальше».
Добавление программ в канал приложения
Создайте объект PreviewProgram.Builder и задайте его атрибуты:
Котлин
val builder = PreviewProgram.Builder()
builder.setChannelId(channelId)
.setType(TvContractCompat.PreviewPrograms.TYPE_CLIP)
.setTitle("Title")
.setDescription("Program description")
.setPosterArtUri(uri)
.setIntentUri(uri)
.setInternalProviderId(appProgramId)
Java
PreviewProgram.Builder builder = new PreviewProgram.Builder();
builder.setChannelId(channelId)
.setType(TvContractCompat.PreviewPrograms.TYPE_CLIP)
.setTitle("Title")
.setDescription("Program description")
.setPosterArtUri(uri)
.setIntentUri(uri)
.setInternalProviderId(appProgramId);
Добавьте дополнительные атрибуты в зависимости от типа программы. (Чтобы увидеть доступные атрибуты для каждого типа программы, обратитесь к таблицам ниже.)
Вставьте программу в провайдер:
Котлин
var programUri = context.contentResolver.insert(TvContractCompat.PreviewPrograms.CONTENT_URI,
builder.build().toContentValues())
Java
Uri programUri = context.getContentResolver().insert(TvContractCompat.PreviewPrograms.CONTENT_URI,
builder.build().toContentValues());
Для дальнейшего использования получите идентификатор программы:
Котлин
val programId = ContentUris.parseId(programUri)
Java
long programId = ContentUris.parseId(programUri);
Добавление программ в канал «Смотреть дальше»
Чтобы добавить программы в канал «Смотреть дальше», см. раздел «Добавление программ в канал «Смотреть дальше»» .
Обновление программы
Вы можете изменить информацию о программе. Например, вы можете обновить стоимость аренды фильма или индикатор выполнения, показывающий, сколько времени пользователь уже просмотрел.
Используйте PreviewProgram.Builder для установки необходимых атрибутов, затем вызовите getContentResolver().update для обновления программы. Укажите идентификатор программы, который вы сохранили при ее первоначальном добавлении:
Котлин
context.contentResolver.update(
TvContractCompat.buildPreviewProgramUri(programId),
builder.build().toContentValues(), null, null
)
Java
context.getContentResolver().update(TvContractCompat.buildPreviewProgramUri(programId),
builder.build().toContentValues(), null, null);
Удаление программы
Котлин
context.contentResolver
.delete(TvContractCompat.buildPreviewProgramUri(programId), null, null)
Java
context.getContentResolver().delete(TvContractCompat.buildPreviewProgramUri(programId), null, null);
Обработка действий пользователя
Ваше приложение может помочь пользователям находить контент, предоставляя пользовательский интерфейс для отображения и добавления каналов. Ваше приложение также должно обрабатывать взаимодействие с вашими каналами после того, как они появятся на главном экране.
Обнаружение и добавление каналов
В вашем приложении может быть элемент пользовательского интерфейса, позволяющий пользователю выбирать и добавлять каналы (например, кнопка, предлагающая добавить канал).
После того, как пользователь запросит определенный канал, выполните следующий код, чтобы получить разрешение пользователя на добавление его на главный экран:
Котлин
val intent = Intent(TvContractCompat.ACTION_REQUEST_CHANNEL_BROWSABLE)
intent.putExtra(TvContractCompat.EXTRA_CHANNEL_ID, channelId)
try {
activity.startActivityForResult(intent, 0)
} catch (e: ActivityNotFoundException) {
// handle error
}
Java
Intent intent = new Intent(TvContractCompat.ACTION_REQUEST_CHANNEL_BROWSABLE);
intent.putExtra(TvContractCompat.EXTRA_CHANNEL_ID, channelId);
try {
activity.startActivityForResult(intent, 0);
} catch (ActivityNotFoundException e) {
// handle error
}
Система отображает диалоговое окно с запросом на подтверждение канала пользователем. Обработайте результат запроса в методе onActivityResult вашей активности ( Activity.RESULT_CANCELED или Activity.RESULT_OK ).
События на главном экране Android TV
Когда пользователь взаимодействует с программами и каналами, публикуемыми приложением, главный экран отправляет в приложение намерения:
- Главный экран отправляет
Uriхранящийся в атрибуте APP_LINK_INTENT_URI канала, в приложение, когда пользователь выбирает логотип канала. Приложение должно просто запустить свой основной пользовательский интерфейс или представление, связанное с выбранным каналом. - Главный экран отправляет
Uriхранящийся в атрибуте INTENT_URI программы, в приложение, когда пользователь выбирает программу. Приложение должно воспроизвести выбранный контент. - Пользователь может указать, что программа ему больше не интересна и он хочет, чтобы она была удалена из пользовательского интерфейса главного экрана. Система удаляет программу из интерфейса и отправляет приложению, которому она принадлежит, намерение (android.media.tv.ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED или android.media.tv.ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED) с идентификатором программы. Приложение должно удалить программу у поставщика и НЕ должно добавлять её повторно.
Обязательно создайте фильтры намерений для всех Uris , которые главный экран отправляет для взаимодействия с пользователем; например:
<receiver
android:name=".WatchNextProgramRemoved"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.media.tv.ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED" />
</intent-filter>
</receiver>
Дополнительные соображения
- Многие ТВ-приложения требуют авторизации пользователей. В этом случае
BroadcastReceiver, который отслеживает событиеandroid.media.tv.action.INITIALIZE_PROGRAMS, должен предлагать контент каналов для неавторизованных пользователей. Например, ваше приложение может сначала показывать лучший или популярный контент. После авторизации пользователя оно может показывать персонализированный контент. Это отличная возможность для приложений предложить пользователям дополнительные услуги до авторизации. - Когда ваше приложение не находится на переднем плане и вам необходимо обновить канал или программу, используйте
JobSchedulerдля планирования работы (см.JobSchedulerиJobService). - Система может отозвать разрешения вашего приложения у поставщика данных, если приложение работает некорректно (например, постоянно отправляет поставщику данные). Убедитесь, что код, обращающийся к поставщику данных, обернут в блоки try-catch для обработки исключений безопасности.
Перед обновлением программ и каналов запросите у поставщика необходимые данные и выполните сверку данных. Например, нет необходимости обновлять программу, которую пользователь хочет удалить из пользовательского интерфейса. Используйте фоновое задание, которое вставляет или обновляет ваши данные в поставщика после запроса существующих данных и запроса подтверждения для ваших каналов. Вы можете запускать это задание при запуске приложения и всякий раз, когда приложению необходимо обновить свои данные.
Котлин
context.contentResolver
.query(
TvContractCompat.buildChannelUri(channelId),
null, null, null, null).use({
cursor-> if (cursor != null and cursor.moveToNext()) {
val channel = Channel.fromCursor(cursor)
if (channel.isBrowsable()) {
//update channel's programs
}
}
})
Java
try (Cursor cursor = context.getContentResolver()
.query(
TvContractCompat.buildChannelUri(channelId),
null,
null,
null,
null)) {
if (cursor != null && cursor.moveToNext()) {
Channel channel = Channel.fromCursor(cursor);
if (channel.isBrowsable()) {
//update channel's programs
}
}
}
Используйте уникальные URI для всех изображений (логотипов, значков, изображений контента). Обязательно используйте разные URI при обновлении изображения. Все изображения кэшируются. Если вы не измените URI при изменении изображения, будет отображаться старое изображение.
Помните, что использование операторов WHERE недопустимо, и вызовы к поставщикам услуг с использованием операторов WHERE приведут к возникновению исключения безопасности.
Атрибуты
В этом разделе атрибуты канала и программы описываются отдельно.
Атрибуты канала
Для каждого канала необходимо указать следующие атрибуты:
| Атрибут | Примечания |
|---|---|
| ТИП | установить значение TYPE_PREVIEW . |
| ОТОБРАЖАЕМОЕ ИМЯ | установить название канала. |
| APP_LINK_INTENT_URI | Когда пользователь выбирает логотип канала, система отправляет Intent для запуска действия, которое отображает контент, относящийся к каналу. Установите для этого атрибута URI, используемый в фильтре Intent для этого действия. |
Кроме того, канал также имеет шесть полей, зарезервированных для внутреннего использования приложением. Эти поля могут использоваться для хранения ключей или других значений, которые помогут приложению сопоставить канал со своей внутренней структурой данных:
- ВНУТРЕННИЙ_ИД_ПОСТАВЩИКА
- ВНУТРЕННИЕ ДАННЫЕ ПОСТАВЩИКА
- INTERNAL_PROVIDER_FLAG1
- ВНУТРЕННИЙ_ФЛАГ_ПОСТАВЩИКА2
- ВНУТРЕННИЙ_ФЛАГ_ПОСТАВЩИКА
- ВНУТРЕННИЙ_ФЛАГ_ПОСТАВЩИКА4
Атрибуты программы
Подробную информацию об атрибутах каждого типа программы смотрите на отдельных страницах:
- Атрибуты видеопрограммы
- Атрибуты аудиопрограммы
- Атрибуты игровой программы
- Смотрите следующую программу. Атрибуты программы.
Пример кода
Чтобы узнать больше о создании приложений, взаимодействующих с главным экраном и добавляющих каналы и программы на главный экран Android TV, ознакомьтесь с нашим руководством по созданию приложений для работы с главным экраном.