अपने कॉन्टेंट की हैरारकी तैयार करना

Android Auto और Android Automotive OS (AAOS), आपके ऐप्लिकेशन की मीडिया ब्राउज़र सेवा को कॉल करके यह पता लगाते हैं कि कौनसी सामग्री उपलब्ध है. इसके लिए, आपको अपनी मीडिया ब्राउज़र सेवा में ये दो तरीके लागू करने होंगे.

onGetRoot लागू करना

आपकी सेवा का onGetRoot तरीका, आपके कॉन्टेंट के क्रम के सबसे ऊपर वाले नोड के बारे में जानकारी देता है. Android Auto और AAOS, इस रूट नोड का इस्तेमाल करके, आपके बाकी कॉन्टेंट का अनुरोध करने के लिए, onLoadChildren तरीके का इस्तेमाल करते हैं. इस कोड स्निपेट में, 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);
}

इस तरीके के बारे में ज़्यादा जानकारी के लिए, GitHub पर Universal Android Music Player के सैंपल ऐप्लिकेशन में onGetRoot देखें.

पैकेज की पुष्टि करने की सुविधा जोड़ना

जब आपकी सेवा के onGetRoot तरीके को कॉल किया जाता है, तो कॉल करने वाला पैकेज, आपकी सेवा को पहचान से जुड़ी जानकारी पास करता है. आपकी सेवा, इस जानकारी का इस्तेमाल करके यह तय कर सकती है कि उस पैकेज के पास आपके कॉन्टेंट का ऐक्सेस है या नहीं.

उदाहरण के लिए, आपके पास अपने ऐप्लिकेशन के कॉन्टेंट के ऐक्सेस को मंज़ूरी वाले पैकेज की सूची तक सीमित करने का विकल्प होता है:

  • clientPackageName की तुलना, अपनी अनुमति वाली सूची से करें.
  • पैकेज के लिए APK पर हस्ताक्षर करने के लिए इस्तेमाल किए गए सर्टिफ़िकेट की पुष्टि करें.

अगर पैकेज की पुष्टि नहीं की जा सकती, तो अपने कॉन्टेंट का ऐक्सेस रोकने के लिए, null वापस करें.

सिस्टम ऐप्लिकेशन (जैसे, Android Auto और AAOS) को अपने कॉन्टेंट का ऐक्सेस देने के लिए, आपकी सेवा को onGetRoot तरीके को कॉल करने पर, BrowserRoot की कोई वैल्यू वापस करनी होगी.

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
}

यह कोड स्निपेट, GitHub पर Universal Android Music Player के सैंपल ऐप्लिकेशन में मौजूद PackageValidator क्लास का एक हिस्सा है. अपनी सेवा के onGetRoot तरीके के लिए, पैकेज की पुष्टि करने की सुविधा लागू करने के तरीके के बारे में ज़्यादा जानकारी के लिए, वह क्लास देखें.

सिस्टम ऐप्लिकेशन को अनुमति देने के अलावा, आपको Google Assistant को अपने MediaBrowserService से कनेक्ट करने की अनुमति देनी होगी. Google Assistant, अपने मोबाइल और AAOS ऐप्लिकेशन के लिए अलग-अलग पैकेज के नामों का इस्तेमाल करती है.

onLoadChildren लागू करना

रूट नोड ऑब्जेक्ट मिलने के बाद, Android Auto और AAOS सबसे ऊपर वाला मेन्यू बनाते हैं. इसके लिए, वे रूट नोड ऑब्जेक्ट पर onLoadChildren को कॉल करके, उसके डिसेंडेंट पाते हैं. क्लाइंट ऐप्लिकेशन, डिसेंडेंट नोड ऑब्जेक्ट का इस्तेमाल करके, इसी तरीके को कॉल करके सब-मेन्यू बनाते हैं.

आपके कॉन्टेंट के क्रम में मौजूद हर नोड को MediaBrowserCompat.MediaItem ऑब्जेक्ट के तौर पर दिखाया जाता है. इनमें से हर मीडिया आइटम की पहचान, यूनीक आईडी स्ट्रिंग से होती है. क्लाइंट ऐप्लिकेशन, इन आईडी स्ट्रिंग को अपारदर्शी टोकन के तौर पर मानते हैं.

जब कोई क्लाइंट ऐप्लिकेशन, किसी सब-मेन्यू को ब्राउज़ करना या कोई मीडिया आइटम चलाना चाहता है, तो वह टोकन पास करता है. आपके ऐप्लिकेशन की ज़िम्मेदारी है कि वह टोकन को सही मीडिया आइटम से जोड़े.

इस कोड स्निपेट में, 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);
}

इस तरीके का उदाहरण देखने के लिए, GitHub पर Universal Android Music Player के सैंपल ऐप्लिकेशन में onLoadChildren देखें.

रूट मेन्यू का स्ट्रक्चर बनाना

Android Auto और Android Automotive OS में, रूट मेन्यू के स्ट्रक्चर के बारे में कुछ खास पाबंदियां होती हैं. इन पाबंदियों के बारे में, MediaBrowserService को रूट हिंट के ज़रिए बताया जाता है. इन्हें onGetRoot() में पास किए गए Bundle आर्ग्युमेंट के ज़रिए पढ़ा जा सकता है. इन हिंट का पालन करने पर, सिस्टम रूट कॉन्टेंट को नेविगेशन टैब के तौर पर दिखाता है. अगर इन हिंट का पालन नहीं किया जाता है, तो हो सकता है कि सिस्टम कुछ रूट कॉन्टेंट को हटा दे या उसे कम खोजे जाने लायक बना दे.

रूट कॉन्टेंट को नेविगेशन टैब के तौर पर दिखाया गया है

पहली इमेज. रूट कॉन्टेंट, नेविगेशन टैब के तौर पर दिखता है.

इन हिंट को लागू करने पर, सिस्टम रूट कॉन्टेंट को नेविगेशन टैब के तौर पर दिखाता है. इन हिंट को लागू न करने पर, हो सकता है कि सिस्टम कुछ रूट कॉन्टेंट को हटा दे या उसे कम खोजे जाने लायक बना दे. ये हिंट ट्रांसमिट किए जाते हैं:

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

आपके पास अपने कॉन्टेंट के क्रम के स्ट्रक्चर के लिए, इन हिंट की वैल्यू के आधार पर लॉजिक को ब्रांच करने का विकल्प होता है. ऐसा तब किया जा सकता है, जब Android Auto और AAOS के अलावा, MediaBrowser इंटिग्रेशन में आपका क्रम अलग-अलग हो.

उदाहरण के लिए, अगर आम तौर पर रूट का कोई ऐसा आइटम दिखाया जाता है जिसे चलाया जा सकता है, तो हो सकता है कि आपको उसे रूट के किसी ऐसे आइटम के तहत नेस्ट करना पड़े जिसे ब्राउज़ किया जा सकता है. ऐसा, काम करने वाले फ़्लैग हिंट की वैल्यू की वजह से करना पड़ सकता है.

टैब को बेहतर तरीके से रेंडर करने के लिए, रूट हिंट के अलावा इन दिशा-निर्देशों का इस्तेमाल करें:

  • हर टैब आइटम के लिए मोनोक्रोम (बेहतर है कि सफ़ेद) आइकॉन

  • हर टैब आइटम के लिए छोटे और काम के लेबल (छोटे लेबल होने से, लेबल के कटने की संभावना कम हो जाती है)