สร้างลำดับชั้นเนื้อหา

Android Auto และ Android Automotive OS (AAOS) จะเรียกใช้บริการ Media Browser ของแอปเพื่อค้นหาเนื้อหาที่พร้อมใช้งาน หากต้องการรองรับการทำงานนี้ คุณต้องใช้ 2 เมธอดต่อไปนี้ในบริการ Media Browser

ใช้ 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);
}

ดูตัวอย่างโดยละเอียดของเมธอดนี้ได้ที่ onGetRoot ในแอปตัวอย่าง Universal Android Music Player บน GitHub

เพิ่มการตรวจสอบแพ็กเกจ

เมื่อมีการเรียกใช้เมธอด onGetRoot ของบริการ แพ็กเกจที่เรียกจะส่งข้อมูลระบุตัวบุคคลไปยังบริการ บริการสามารถใช้ข้อมูลนี้เพื่อตัดสินใจว่าแพ็กเกจดังกล่าวเข้าถึงเนื้อหาได้หรือไม่

ตัวอย่างเช่น คุณสามารถจำกัดการเข้าถึงเนื้อหาของแอปไว้เฉพาะรายการแพ็กเกจที่ได้รับอนุมัติได้โดยทำดังนี้

  • เปรียบเทียบ clientPackageName กับรายการที่อนุญาต
  • ยืนยันใบรับรองที่ใช้ลงนาม APK สำหรับแพ็กเกจ

หากยืนยันแพ็กเกจไม่ได้ ให้แสดงผล null เพื่อปฏิเสธการเข้าถึงเนื้อหา

หากต้องการให้แอประบบ เช่น Android Auto และ AAOS เข้าถึงเนื้อหาได้ บริการต้องแสดงผล BrowserRoot ที่ไม่ใช่ค่า Null เมื่อแอประบบเหล่านี้เรียกใช้เมธอด 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 ของบริการ

นอกเหนือจากการอนุญาตแอประบบแล้ว คุณต้องอนุญาตให้ Gemini หรือ 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);
}

หากต้องการดูตัวอย่างของเมธอดนี้ โปรดดู onLoadChildren ใน แอปตัวอย่าง Universal Android Music Player บน GitHub

จัดโครงสร้างเมนูราก

Android Auto และ Android Automotive OS มีข้อจำกัดเฉพาะเกี่ยวกับโครงสร้างของเมนูราก ข้อจำกัดเหล่านี้จะสื่อสารกับ MediaBrowserService ผ่านคำแนะนำราก ซึ่งอ่านได้ผ่านอาร์กิวเมนต์ Bundle ที่ส่งไปยัง onGetRoot() เมื่อทำตามคำแนะนำเหล่านี้ ระบบจะแสดงเนื้อหารากเป็นแท็บการนำทาง หากไม่ทำตามคำแนะนำเหล่านี้ ระบบอาจทิ้งเนื้อหารากบางส่วนหรือทำให้ค้นพบได้ยากขึ้น

เนื้อหาระดับบนสุดจะแสดงเป็นแท็บการนำทาง

รูปที่ 1 เนื้อหารากที่แสดงเป็นแท็บการนำทาง

เมื่อใช้คำแนะนำเหล่านี้ ระบบจะแสดงเนื้อหารากเป็นแท็บการนำทาง หากไม่ใช้คำแนะนำเหล่านี้ ระบบอาจทิ้งเนื้อหารากบางส่วนหรือทำให้ค้นพบได้ยากขึ้น คำแนะนำเหล่านี้จะถูกส่งดังนี้

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

คุณสามารถเลือกที่จะแยกตรรกะสำหรับโครงสร้างของลำดับชั้นเนื้อหาตามค่าของคำแนะนำเหล่านี้ได้ โดยเฉพาะอย่างยิ่งหากลำดับชั้นของคุณแตกต่างกันไปในระบบการผสานรวม MediaBrowser นอกเหนือจาก Android Auto และ AAOS

ตัวอย่างเช่น หากปกติคุณแสดงรายการที่เล่นได้ในราก คุณอาจต้องการซ้อนรายการดังกล่าวไว้ใต้รายการที่เรียกดูได้ในรากแทนเนื่องจากค่าของคำแนะนำแฟล็กที่รองรับ

นอกเหนือจากคำแนะนำรากแล้ว ให้ใช้หลักเกณฑ์ต่อไปนี้เพื่อแสดงแท็บอย่างเหมาะสม

  • ไอคอนสีเดียว (ควรเป็นสีขาว) สำหรับรายการแท็บแต่ละรายการ

  • ป้ายกำกับสั้นๆ ที่สื่อความหมายสำหรับรายการแท็บแต่ละรายการ (ป้ายกำกับสั้นๆ จะช่วยลดโอกาสที่ป้ายกำกับจะถูกตัดทอน)