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

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 เพื่อปฏิเสธการเข้าถึงเนื้อหา

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

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

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

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

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