Android Auto и Android Automotive OS (AAOS) обращаются к службе медиабраузера вашего приложения, чтобы определить доступный контент. Для этого необходимо реализовать эти два метода в службе медиабраузера.
Реализовать onGetRoot
Метод onGetRoot
вашего сервиса возвращает информацию о корневом узле иерархии контента. Android Auto и AAOS используют этот корневой узел для запроса остального контента с помощью метода onLoadChildren
. Этот фрагмент кода демонстрирует реализацию метода onGetRoot
:
Котлин
override fun onGetRoot(
clientPackageName: String,
clientUid: Int,
rootHints: Bundle?
): BrowserRoot? =
// Verify that the specified package is allowed to access your
// content. You'll need to write your own logic to do this.
if (!isValid(clientPackageName, clientUid)) {
// If the request comes from an untrusted package, return null.
// No further calls will be made to other media browsing methods.
null
} else MediaBrowserServiceCompat.BrowserRoot(MY_MEDIA_ROOT_ID, null)
Ява
@Override
public BrowserRoot onGetRoot(String clientPackageName, int clientUid,
Bundle rootHints) {
// Verify that the specified package is allowed to access your
// content. You'll need to write your own logic to do this.
if (!isValid(clientPackageName, clientUid)) {
// If the request comes from an untrusted package, return null.
// No further calls will be made to other media browsing methods.
return null;
}
return new MediaBrowserServiceCompat.BrowserRoot(MY_MEDIA_ROOT_ID, null);
}
Подробный пример этого метода см onGetRoot
в примере приложения Universal Android Music Player на GitHub.
Добавить проверку пакета
При вызове метода onGetRoot
вашего сервиса вызывающий пакет передаёт идентификационную информацию вашему сервису. Ваш сервис может использовать эту информацию, чтобы определить, может ли этот пакет получить доступ к вашему контенту.
Например, вы можете ограничить доступ к содержимому вашего приложения списком одобренных пакетов:
- Сравните
clientPackageName
с вашим списком разрешенных пакетов. - Проверьте сертификат, используемый для подписи APK-файла пакета.
Если пакет не может быть проверен, верните null
, чтобы запретить доступ к вашему контенту.
Чтобы предоставить системным приложениям, таким как Android Auto и AAOS, доступ к вашему контенту, ваша служба должна возвращать ненулевой BrowserRoot
, когда эти системные приложения вызывают метод onGetRoot
.
Подпись системного приложения AAOS различается в зависимости от марки и модели автомобиля. Для поддержки AAOS обязательно разрешите подключения всех системных приложений.
В этом фрагменте кода показано, как ваша служба может проверить, является ли вызывающий пакет системным приложением:
fun isKnownCaller(
callingPackage: String,
callingUid: Int
): Boolean {
...
val isCallerKnown = when {
// If the system is making the call, allow it.
callingUid == Process.SYSTEM_UID -> true
// If the app was signed by the same certificate as the platform
// itself, also allow it.
callerSignature == platformSignature -> true
// ... more cases
}
return isCallerKnown
}
Этот фрагмент кода — фрагмент класса PackageValidator
из примера приложения Universal Android Music Player на GitHub. Более подробный пример реализации валидации пакетов для метода onGetRoot
вашего сервиса можно найти в этом классе.
Помимо разрешения системных приложений, необходимо разрешить Google Assistant подключаться к MediaBrowserService
. Google Assistant использует отдельные имена пакетов для телефона, включая Android Auto и Android AAOS.
Реализовать onLoadChildren
Получив объект корневого узла, Android Auto и AAOS создают меню верхнего уровня, вызывая метод onLoadChildren
для объекта корневого узла, чтобы получить его потомков. Клиентские приложения создают подменю, вызывая этот же метод с использованием объектов потомков.
Каждый узел в иерархии контента представлен объектом MediaBrowserCompat.MediaItem
. Каждый из этих медиаэлементов идентифицируется уникальной строкой идентификатора. Клиентские приложения обрабатывают эти строки идентификатора как непрозрачные токены.
Когда клиентское приложение хочет перейти в подменю или воспроизвести медиафайл, оно передаёт токен. Ваше приложение отвечает за привязку токена к соответствующему медиафайлу.
Этот фрагмент кода демонстрирует реализацию onLoadChildren
Котлин
override fun onLoadChildren(
parentMediaId: String,
result: Result<List<MediaBrowserCompat.MediaItem>>
) {
// Assume for example that the music catalog is already loaded/cached.
val mediaItems: MutableList<MediaBrowserCompat.MediaItem> = mutableListOf()
// Check if this is the root menu:
if (MY_MEDIA_ROOT_ID == parentMediaId) {
// Build the MediaItem objects for the top level
// and put them in the mediaItems list.
} else {
// Examine the passed parentMediaId to see which submenu we're at
// and put the descendants of that menu in the mediaItems list.
}
result.sendResult(mediaItems)
}
Ява
@Override
public void onLoadChildren(final String parentMediaId,
final Result<List<MediaBrowserCompat.MediaItem>> result) {
// Assume for example that the music catalog is already loaded/cached.
List<MediaBrowserCompat.MediaItem> mediaItems = new ArrayList<>();
// Check if this is the root menu:
if (MY_MEDIA_ROOT_ID.equals(parentMediaId)) {
// Build the MediaItem objects for the top level
// and put them in the mediaItems list.
} else {
// Examine the passed parentMediaId to see which submenu we're at
// and put the descendants of that menu in the mediaItems list.
}
result.sendResult(mediaItems);
}
Чтобы просмотреть пример этого метода, см. onLoadChildren
в примере приложения Universal Android Music Player на GitHub.
Структура корневого меню
В Android Auto и Android Automotive OS существуют определённые ограничения на структуру корневого меню. Они передаются службе MediaBrowserService
через корневые подсказки, которые можно прочитать через аргумент Bundle, передаваемый в onGetRoot()
. При соблюдении этих подсказок система отображает содержимое корневого меню в виде навигационных вкладок. Несоблюдение этих подсказок может привести к потере части содержимого корневого меню или сделать его менее заметным для системы.
Рисунок 1. Корневой контент отображается в виде навигационных вкладок.
Применяя эти подсказки, система отображает корневой контент в виде навигационных вкладок. Если не применять эти подсказки, часть корневого контента может быть потеряна или стать менее заметной. Эти подсказки передаются:
Ограничение на количество корневых дочерних элементов : в большинстве случаев следует ожидать, что их будет четыре, что означает, что могут быть отображены только четыре (или меньше) вкладки.
Поддерживаемые флаги для корневых дочерних элементов : Ожидается, что это значение будет
MediaItem#FLAG_BROWSABLE
, что означает, что в качестве вкладок могут отображаться только просматриваемые элементы (но не воспроизводимые).Ограничение на количество пользовательских действий просмотра : проверьте, сколько пользовательских действий просмотра поддерживается.
Котлин
import androidx.media.utils.MediaConstants
override fun onGetRoot(
clientPackageName: String,
clientUid: Int,
rootHints: Bundle
): BrowserRoot {
val maximumRootChildLimit = rootHints.getInt(
MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT,
/* defaultValue= */ 4)
val supportedRootChildFlags = rootHints.getInt(
MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_SUPPORTED_FLAGS,
/* defaultValue= */ MediaItem.FLAG_BROWSABLE)
// Rest of method...
}
Ява
import androidx.media.utils.MediaConstants;
// Later, in your MediaBrowserServiceCompat.
@Override
public BrowserRoot onGetRoot(
String clientPackageName, int clientUid, Bundle rootHints) {
int maximumRootChildLimit = rootHints.getInt(
MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT,
/* defaultValue= */ 4);
int supportedRootChildFlags = rootHints.getInt(
MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_SUPPORTED_FLAGS,
/* defaultValue= */ MediaItem.FLAG_BROWSABLE);
// Rest of method...
}
Вы можете выбрать разветвление логики структуры иерархии вашего контента на основе значений этих подсказок, особенно если ваша иерархия различается в разных интеграциях MediaBrowser
за пределами Android Auto и AAOS.
Например, если вы обычно отображаете корневой воспроизводимый элемент, вы можете захотеть вложить его под корневой просматриваемый элемент из-за значения подсказки поддерживаемых флагов.
Помимо корневых ссылок, для оптимальной визуализации вкладок используйте следующие рекомендации:
Монохромные (желательно белые) значки для каждого элемента вкладки
Короткие и содержательные подписи для каждого элемента вкладки (короткие подписи снижают вероятность того, что подписи могут быть обрезаны)