Inhaltshierarchie erstellen

Android Auto und Android Automotive OS (AAOS) rufen den Media-Browser-Dienst Ihrer App auf, um herauszufinden, welche Inhalte verfügbar sind. Dazu implementieren Sie diese beiden Methoden in Ihrem Mediabrowserdienst.

„onGetRoot“ implementieren

Die onGetRoot-Methode Ihres Dienstes gibt Informationen zum Stammknoten Ihrer Inhaltshierarchie zurück. Android Auto und AAOS verwenden diesen Stammknoten, um den Rest Ihrer Inhalte mit der Methode onLoadChildren anzufordern. Dieses Code-Snippet zeigt eine Implementierung der Methode onGetRoot:

Kotlin

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)

Java

@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);
}

Ein detailliertes Beispiel für diese Methode finden Sie in der Universal Android Music Player-Beispiel-App auf GitHub unter onGetRoot.

Paketvalidierung hinzufügen

Wenn ein Aufruf an die onGetRoot-Methode Ihres Dienstes erfolgt, übergibt das aufrufende Paket Identifikationsinformationen an Ihren Dienst. Ihr Dienst kann anhand dieser Informationen entscheiden, ob das Paket auf Ihre Inhalte zugreifen darf.

Sie können beispielsweise den Zugriff auf die Inhalte Ihrer App auf eine Liste genehmigter Pakete beschränken:

  • Vergleichen Sie die clientPackageName mit Ihrer Zulassungsliste.
  • Prüfen Sie das Zertifikat, mit dem das APK für das Paket signiert wurde.

Wenn das Paket nicht bestätigt werden kann, sende null zurück, um den Zugriff auf deine Inhalte zu verweigern.

Damit System-Apps wie Android Auto und AAOS auf Ihre Inhalte zugreifen können, muss Ihr Dienst einen Wert ungleich null für BrowserRoot zurückgeben, wenn diese System-Apps die Methode onGetRoot aufrufen.

Die Signatur der AAOS-System-App variiert je nach Marke und Modell eines Autos. Lassen Sie Verbindungen von allen System-Apps zu, um AAOS zu unterstützen.

Dieses Code-Snippet zeigt, wie Ihr Dienst prüfen kann, ob das aufrufende Paket eine System-App ist:

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
}

Dieses Code-Snippet ist ein Auszug aus der Klasse PackageValidator in der Universal Android Music Player-Beispiel-App auf GitHub. In dieser Klasse finden Sie ein detaillierteres Beispiel für die Implementierung der Paketvalidierung für die onGetRoot-Methode Ihres Dienstes.

Sie müssen nicht nur System-Apps zulassen, sondern auch Google Assistant erlauben, sich mit Ihrem MediaBrowserService zu verbinden. Google Assistant verwendet separate Paketnamen für das Smartphone, einschließlich Android Auto und Android AAOS.

onLoadChildren implementieren

Nachdem Android Auto und AAOS das Stammknotenobjekt erhalten haben, wird ein Menü der obersten Ebene erstellt, indem onLoadChildren für das Stammknotenobjekt aufgerufen wird, um die untergeordneten Elemente abzurufen. Client-Apps erstellen Untermenüs, indem sie dieselbe Methode mit untergeordneten Knotenobjekten aufrufen.

Jeder Knoten in Ihrer Inhaltshierarchie wird durch ein MediaBrowserCompat.MediaItem-Objekt dargestellt. Jedes dieser Media-Elemente wird durch einen eindeutigen ID-String identifiziert. Client-Apps behandeln diese ID-Strings als nicht transparente Tokens.

Wenn eine Client-App ein Untermenü aufrufen oder ein Media-Element abspielen möchte, übergibt sie das Token. Ihre App ist dafür verantwortlich, das Token dem entsprechenden Media-Element zuzuordnen.

Dieses Code-Snippet zeigt eine Implementierung von onLoadChildren.

Kotlin

override fun onLoadChildren(
    parentMediaId: String,
    result: Result<List<MediaBrowserCompat.MediaItem>>
) {
    // Assume for example that the music catalog is already loaded/cached.

    val mediaItems: MutableList&lt;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)
}

Java

@Override
public void onLoadChildren(final String parentMediaId,
    final Result&lt;List&lt;MediaBrowserCompat.MediaItem>> result) {

    // Assume for example that the music catalog is already loaded/cached.

    List&lt;MediaBrowserCompat.MediaItem> mediaItems = new ArrayList&lt;>();

    // 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);
}

Ein Beispiel für diese Methode finden Sie in der onLoadChildren in der Universal Android Music Player-Beispiel-App auf GitHub.

Strukturieren des Stammmenüs

Für Android Auto und Android Automotive OS gelten bestimmte Einschränkungen hinsichtlich der Struktur des Stammmenüs. Diese werden über Root-Hinweise an MediaBrowserService übermittelt, die über das Bundle-Argument gelesen werden können, das an onGetRoot() übergeben wird. Wenn diese Hinweise befolgt werden, kann das System den Root-Inhalt als Navigationstabs anzeigen. Wenn Sie diese Hinweise nicht beachten, werden einige Root-Inhalte möglicherweise vom System entfernt oder sind weniger auffindbar.

Root-Inhalte als Navigationstabs

Abbildung 1: Root-Inhalte, die als Navigationstabs angezeigt werden.

Wenn Sie diese Hinweise anwenden, werden die Root-Inhalte als Navigationstabs angezeigt. Wenn Sie diese Hinweise nicht berücksichtigen, werden einige Root-Inhalte möglicherweise nicht mehr angezeigt oder sind weniger auffindbar. Diese Hinweise werden übertragen:

Kotlin

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...
}

Java

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...
}

Sie können die Logik für die Struktur Ihrer Inhaltshierarchie basierend auf den Werten dieser Hinweise verzweigen, insbesondere wenn sich Ihre Hierarchie zwischen MediaBrowser-Integrationen außerhalb von Android Auto und AAOS unterscheidet.

Wenn Sie beispielsweise normalerweise ein abspielbares Stamm-Element präsentieren, möchten Sie es möglicherweise aufgrund des Hinweises zum Wert der unterstützten Flags stattdessen unter einem durchsuchbaren Stamm-Element einbetten.

Neben den Root-Hinweisen sollten Sie die folgenden Richtlinien beachten, um Tabs optimal zu rendern:

  • Einfarbige (vorzugsweise weiße) Symbole für die einzelnen Tab-Elemente

  • Kurze und aussagekräftige Labels für jedes Tab-Element (kurze Labels verringern die Wahrscheinlichkeit, dass sie abgeschnitten werden)