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 Media Browser-Dienst.

onGetRoot implementieren

Die Methode onGetRoot Ihres Dienstes gibt Informationen zum Stammknoten Ihrer Inhaltshierarchie zurück. Android Auto und AAOS verwenden diesen Stamm knoten, um den Rest Ihrer Inhalte mit der onLoadChildren Methode anzufordern. Dieser 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 unter onGetRoot in der Universal Android Music Player Beispiel-App auf GitHub.

Paketvalidierung hinzufügen

Wenn ein Aufruf an die Methode onGetRoot Ihres Dienstes erfolgt, übergibt das aufrufende Paket Identifikationsinformationen an Ihren Dienst. Ihr Dienst kann anhand dieser Informationen entscheiden, ob dieses 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 clientPackageName mit Ihrer Zulassungsliste.
  • Prüfen Sie das Zertifikat, mit dem die APK für das Paket signiert wurde.

Wenn das Paket nicht verifiziert werden kann, geben Sie null zurück, um den Zugriff auf Ihre Inhalte zu verweigern.

Damit System-Apps wie Android Auto und AAOS auf Ihre Inhalte zugreifen können, muss Ihr Dienst ein BrowserRoot zurückgeben, das nicht null ist, wenn diese System-Apps die Methode onGetRoot aufrufen.

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

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

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

Neben System-Apps müssen Sie auch Google Assistant erlauben, eine Verbindung zu Ihrem MediaBrowserService herzustellen. Google Assistant verwendet unterschiedliche Paketnamen für seine mobilen Apps und AAOS-Apps.

onLoadChildren implementieren

Nachdem Android Auto und AAOS Ihr Stammknotenobjekt erhalten haben, erstellen sie ein Menü der obersten Ebene, indem sie onLoadChildren für das Stammknotenobjekt aufrufen, um seine Nachfolger abzurufen. Client-Apps erstellen Untermenüs, indem sie dieselbe Methode mit Nachfolgerknotenobjekten aufrufen.

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

Wenn eine Client-App zu einem Untermenü wechseln oder ein MediaItem abspielen möchte, übergibt sie das Token. Ihre App ist dafür verantwortlich, das Token dem entsprechenden MediaItem zuzuordnen.

Dieser 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 unter onLoadChildren in der Beispiel-App Universal Android Music Player auf GitHub.

Struktur des Stammmenüs

Android Auto und Android Automotive OS haben bestimmte Einschränkungen hinsichtlich der Struktur des Stammmenüs. Diese werden dem MediaBrowserService über Stammhinweise mitgeteilt, die über das Bundle-Argument gelesen werden können, das an onGetRoot() übergeben wird. Wenn diese Hinweise befolgt werden, kann das System die Stamm-Inhalte als Navigationstabs anzeigen. Wenn Sie diese Hinweise nicht befolgen, werden einige Stamm-Inhalte möglicherweise vom System entfernt oder weniger auffindbar gemacht.

Root-Inhalte als Navigationstabs

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

Wenn Sie diese Hinweise anwenden, zeigt das System die Stamm-Inhalte als Navigationstabs an. Wenn Sie diese Hinweise nicht anwenden, werden einige Stamm-Inhalte möglicherweise entfernt oder weniger auffindbar gemacht. 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 anzeigen, sollten Sie es aufgrund des Werts des Hinweises zu den unterstützten Flags stattdessen unter einem durchsuchbaren Stamm-Element verschachteln.

Neben Stammhinweisen können Sie diese Richtlinien verwenden, um Tabs optimal zu rendern:

  • Monochrome (vorzugsweise weiße) Symbole für jedes Tab-Element

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