"مساعد Google" وتطبيقات الوسائط

يسمح لك "مساعد Google" باستخدام الطلبات الصوتية للتحكّم في العديد من الأجهزة، مثل Google Home وهاتفك وغير ذلك الكثير. ويشتمل هذا البرنامج على إمكانية مضمّنة لفهم أوامر الوسائط ("تشغيل أغنية لـ Beyoncé") كما يتوافق مع عناصر التحكّم في الوسائط (مثل الإيقاف المؤقت والتخطي والتقديم السريع وإبداء الإعجاب).

يتواصل "مساعد Google" مع تطبيقات الوسائط على Android باستخدام جلسة وسائط. ويمكنها استخدام النية أو الخدمات لإطلاق التطبيق وبدء التشغيل. للحصول على أفضل النتائج، يجب أن ينفِّذ تطبيقك جميع الميزات الموضحة في هذه الصفحة.

.

استخدام جلسة وسائط

يجب أن ينفّذ كل تطبيق صوتي أو فيديو جلسة وسائط لكي يتمكّن "مساعد Google" من تشغيل عناصر التحكّم في النقل عند بدء التشغيل.

يُرجى العِلم أنّ "مساعد Google" لا يستخدم سوى الإجراءات المدرَجة في هذا القسم، إلا أنّ أفضل الممارسات هي تنفيذ جميع واجهات برمجة تطبيقات الإعداد والتشغيل لضمان التوافق مع التطبيقات الأخرى. بالنسبة إلى أي إجراءات غير متاحة، يمكن أن تعرض عمليات استدعاء جلسة الوسائط ببساطة خطأ باستخدام ERROR_CODE_NOT_SUPPORTED.

يمكنك تفعيل عناصر التحكّم في الوسائط والنقل من خلال ضبط هذه العلامات في عنصر MediaSession في تطبيقك:

Kotlin

session.setFlags(
        MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or
        MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS
)

Java

session.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
    MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);

يجب أن تعرض جلسة الوسائط في تطبيقك الإجراءات المتوافقة مع التطبيق، وأن تنفّذ عمليات استدعاء جلسة تشغيل الوسائط المقابلة. يُرجى تعريف الإجراءات المتاحة في setActions().

ويشكّل مشروع Universal Android Music Player مثالاً جيدًا على كيفية إعداد جلسة وسائط.

إجراءات التشغيل

لبدء التشغيل من خدمة، يجب أن تتضمّن جلسة الوسائط إجراءات PLAY هذه واستدعاءاتها:

الإجراء هاتف معاودة الاتصال
ACTION_PLAY onPlay()
ACTION_PLAY_FROM_SEARCH onPlayFromSearch()
ACTION_PLAY_FROM_URI (*) onPlayFromUri()

يجب أن تنفّذ جلستك أيضًا إجراءات PREPARE هذه وعمليات معاودة الاتصال المرتبطة بها:

الإجراء هاتف معاودة الاتصال
ACTION_PREPARE onPrepare()
ACTION_PREPARE_FROM_SEARCH onPrepareFromSearch()
ACTION_PREPARE_FROM_URI (*) onPrepareFromUri()

(*) تعمل الإجراءات المستندة إلى معرّف الموارد المنتظم (URI) في "مساعد Google" فقط مع الشركات التي تقدّم معرّفات الموارد المنتظمة (URI) إلى Google. لمعرفة المزيد من المعلومات حول وصف محتوى الوسائط لمحرّك بحث Google، راجع إجراءات الوسائط.

من خلال تنفيذ واجهات برمجة تطبيقات الإعداد، يمكن تقليل وقت استجابة التشغيل الذي يأتي بعد توجيه طلب صوتي. ويمكن لتطبيقات الوسائط التي تريد تحسين وقت استجابة التشغيل استخدام الوقت الإضافي لبدء التخزين المؤقت للمحتوى وإعداد تشغيل الوسائط.

تحليل طلبات البحث

عندما يبحث المستخدم عن عنصر وسائط محدّد، مثل "تشغيل موسيقى الجاز على [اسم تطبيقك]" أو "الاستماع إلى [عنوان الأغنية]"، تتلقّى طريقة معاودة الاتصال onPrepareFromSearch() أو onPlayFromSearch() مَعلمة طلب بحث وحزمة ميزات إضافية.

يجب أن يحلل التطبيق طلب البحث الصوتي ويبدأ التشغيل من خلال اتباع الخطوات التالية:

  1. استخدم حزمة الإضافات وسلسلة طلب البحث المعروضة من البحث الصوتي لتصفية النتائج.
  2. أنشئ قائمة انتظار التشغيل بناءً على هذه النتائج.
  3. شغِّل عنصر الوسائط الأكثر صلة من النتائج.

تأخذ الطريقة onPlayFromSearch() مَعلمة إضافية تتضمّن معلومات أكثر تفصيلاً من البحث الصوتي. تساعدك هذه الميزات الإضافية في العثور على محتوى الصوت في تطبيقك لتشغيله. إذا لم تتمكن من تقديم هذه البيانات في نتائج البحث، يمكنك استخدام المنطق لتحليل استعلام البحث الأولي وتشغيل المسارات المناسبة بناءً على طلب البحث.

تتوفر الميزات الإضافية التالية في نظامَي التشغيل Android Automotive وAndroid Auto:

يعرض مقتطف الرمز التالي كيفية إلغاء طريقة onPlayFromSearch() في تنفيذ MediaSession.Callback لتحليل طلب البحث الصوتي وبدء التشغيل:

Kotlin

override fun onPlayFromSearch(query: String?, extras: Bundle?) {
    if (query.isNullOrEmpty()) {
        // The user provided generic string e.g. 'Play music'
        // Build appropriate playlist queue
    } else {
        // Build a queue based on songs that match "query" or "extras" param
        val mediaFocus: String? = extras?.getString(MediaStore.EXTRA_MEDIA_FOCUS)
        if (mediaFocus == MediaStore.Audio.Artists.ENTRY_CONTENT_TYPE) {
            isArtistFocus = true
            artist = extras.getString(MediaStore.EXTRA_MEDIA_ARTIST)
        } else if (mediaFocus == MediaStore.Audio.Albums.ENTRY_CONTENT_TYPE) {
            isAlbumFocus = true
            album = extras.getString(MediaStore.EXTRA_MEDIA_ALBUM)
        }

        // Implement additional "extras" param filtering
    }

    // Implement your logic to retrieve the queue
    var result: String? = when {
        isArtistFocus -> artist?.also {
            searchMusicByArtist(it)
        }
        isAlbumFocus -> album?.also {
            searchMusicByAlbum(it)
        }
        else -> null
    }
    result = result ?: run {
        // No focus found, search by query for song title
        query?.also {
            searchMusicBySongTitle(it)
        }
    }

    if (result?.isNotEmpty() == true) {
        // Immediately start playing from the beginning of the search results
        // Implement your logic to start playing music
        playMusic(result)
    } else {
        // Handle no queue found. Stop playing if the app
        // is currently playing a song
    }
}

Java

@Override
public void onPlayFromSearch(String query, Bundle extras) {
    if (TextUtils.isEmpty(query)) {
        // The user provided generic string e.g. 'Play music'
        // Build appropriate playlist queue
    } else {
        // Build a queue based on songs that match "query" or "extras" param
        String mediaFocus = extras.getString(MediaStore.EXTRA_MEDIA_FOCUS);
        if (TextUtils.equals(mediaFocus,
                MediaStore.Audio.Artists.ENTRY_CONTENT_TYPE)) {
            isArtistFocus = true;
            artist = extras.getString(MediaStore.EXTRA_MEDIA_ARTIST);
        } else if (TextUtils.equals(mediaFocus,
                MediaStore.Audio.Albums.ENTRY_CONTENT_TYPE)) {
            isAlbumFocus = true;
            album = extras.getString(MediaStore.EXTRA_MEDIA_ALBUM);
        }

        // Implement additional "extras" param filtering
    }

    // Implement your logic to retrieve the queue
    if (isArtistFocus) {
        result = searchMusicByArtist(artist);
    } else if (isAlbumFocus) {
        result = searchMusicByAlbum(album);
    }

    if (result == null) {
        // No focus found, search by query for song title
        result = searchMusicBySongTitle(query);
    }

    if (result != null && !result.isEmpty()) {
        // Immediately start playing from the beginning of the search results
        // Implement your logic to start playing music
        playMusic(result);
    } else {
        // Handle no queue found. Stop playing if the app
        // is currently playing a song
    }
}

للحصول على مثال أكثر تفصيلاً حول كيفية إجراء البحث الصوتي لتشغيل محتوى صوتي في تطبيقك، راجع النموذج Universal Android Music Player.

معالجة طلبات البحث الفارغة

إذا تم استدعاء onPrepare() أو onPlay() أو onPrepareFromSearch() أو onPlayFromSearch() بدون طلب بحث، من المفترض أن يشغِّل تطبيق الوسائط الوسائط "الحالية". وإذا لم تكن هناك وسائط حالية، يجب أن يحاول التطبيق تشغيل شيء ما، مثل أغنية من آخر قائمة تشغيل أو قائمة انتظار عشوائية. ويستخدم المساعد واجهات برمجة التطبيقات هذه عندما يطلب المستخدم "تشغيل الموسيقى على [اسم تطبيقك]" بدون معلومات إضافية.

عندما يقول المستخدم "تشغيل الموسيقى على [اسم تطبيقك]"، يحاول نظام التشغيل Android Automotive أو Android Auto تشغيل تطبيقك وتشغيل الصوت من خلال استدعاء طريقة onPlayFromSearch() في تطبيقك. وبما أنّ المستخدم لم يذكر اسم عنصر الوسائط، ستتلقّى الطريقة onPlayFromSearch() مَعلمة طلب بحث فارغة. في هذه الحالات، من المفترض أن يستجيب التطبيق من خلال تشغيل الصوت على الفور، مثل أغنية من أحدث قائمة تشغيل أو قائمة انتظار عشوائية.

توضيح إتاحة الإجراءات الصوتية القديمة

في معظم الحالات، تمنح إجراءات التشغيل الموضحة أعلاه تطبيقك كل وظائف التشغيل التي يحتاج إليها. ومع ذلك، تتطلب بعض الأنظمة أن يحتوي تطبيقك على فلتر Intent للبحث. يجب أن تذكر دعمًا لفلتر Intent هذا في ملفات بيان تطبيقك.

يمكنك تضمين هذا الرمز في ملف البيان لتطبيق الهاتف:

<activity>
    <intent-filter>
        <action android:name=
             "android.media.action.MEDIA_PLAY_FROM_SEARCH" />
        <category android:name=
             "android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

عناصر التحكّم في النقل

بعد تفعيل جلسة الوسائط في التطبيق، يمكن لخدمة "مساعد Google" إصدار طلبات صوتية للتحكّم في التشغيل وتعديل البيانات الوصفية للوسائط. ولكي ينجح ذلك، يجب أن تمكّن التعليمة البرمجية الإجراءات التالية وأن تنفذ عمليات استدعاء الاتصال المقابلة:

الإجراء هاتف معاودة الاتصال الوصف
ACTION_SKIP_TO_NEXT onSkipToNext() الفيديو التالي
ACTION_SKIP_TO_PREVIOUS onSkipToPrevious() الأغنية السابقة
ACTION_PAUSE, ACTION_PLAY_PAUSE onPause() إيقاف مؤقت
ACTION_STOP onStop() إيقاف
ACTION_PLAY onPlay() استئناف التشغيل
ACTION_SEEK_TO onSeekTo() ترجيع بمقدار 30 ثانية
ACTION_SET_RATING onSetRating(android.support.v4.media.RatingCompat) رائع/لا يعجبني.
ACTION_SET_CAPTIONING_ENABLED onSetCaptioningEnabled(boolean) فعِّل ميزة الترجمة والشرح أو أوقِفها.

ملاحظة:

  • لكي تعمل أوامر التقديم، يجب تحديث PlaybackState مع state, position, playback speed, and update time. يجب أن يتصل التطبيق بالرمز setPlaybackState() عندما تتغير الحالة.
  • ويجب أيضًا أن يعدّل تطبيق الوسائط البيانات الوصفية لجلسة الوسائط باستمرار. يدعم ذلك أسئلة مثل "ما الأغنية التي يتم تشغيلها؟" يجب أن يتصل التطبيق بـ setMetadata() عند تغيير الحقول المناسبة (مثل عنوان المقطع الصوتي والفنان والاسم).
  • يجب ضبط MediaSession.setRatingType() للإشارة إلى نوع التقييم المتوافق مع التطبيق، ويجب أن ينفِّذ onSetRating(). إذا كان التطبيق لا يتيح التقييم، يجب ضبط نوع التقييم على RATING_NONE.

ومن المرجح أن تختلف الإجراءات الصوتية التي تتيحها حسب نوع المحتوى.

نوع المحتوى الإجراءات المطلوبة
تطبيق موسيقى

ضرورة الدعم: التشغيل والإيقاف المؤقت والإيقاف والتخطّي إلى التالي والتخطّي إلى السابق

أوصي بشدة بالحصول على الدعم بشأن: "تقديم"

بودكاست

ضرورة الدعم: التشغيل والإيقاف المؤقت والإيقاف والسعي إلى

اقتراح الدعم لـ: التخطّي إلى التالي والتخطّي إلى السابق

كتاب مسموع ضرورة الدعم: التشغيل والإيقاف المؤقت والإيقاف والسعي إلى
راديو ضرورة الدعم: التشغيل والإيقاف المؤقت والإيقاف
أخبار ضرورة الدعم: التشغيل والإيقاف المؤقت والإيقاف والتخطّي إلى التالي والتخطّي إلى السابق
الفيديو

ضرورة الدعم: التشغيل، والإيقاف المؤقت، والإيقاف، والتقديم، والترجيع، والتقديم السريع

ننصح بشدة بتوفير الدعم لـ: التخطّي إلى التالي والتخطّي إلى السابق

عليك دعم أكبر عدد ممكن من الإجراءات المذكورة أعلاه على النحو الذي تسمح به عروض منتجاتك، مع الاستمرار في الاستجابة بشكل ملائم لأي إجراءات أخرى. على سبيل المثال، إذا كان بإمكان المستخدمين المشتركين في Premium فقط الرجوع إلى العنصر السابق، قد تعرض رسالة خطأ إذا طلب مستخدم المستوى المجاني من "مساعد Google" الرجوع إلى العنصر السابق. راجِع قسم التعامل مع الأخطاء للحصول على مزيد من الإرشادات.

نماذج طلبات صوتية يمكن تجربتها

يوضح الجدول التالي بعض نماذج طلبات البحث التي يجب استخدامها أثناء اختبار التنفيذ:

معاودة الاتصال في MediaSession عبارة "Ok Google" التي يمكن استخدامها
onPlay()

"تشغيل"

"استئناف التشغيل"

onPlayFromSearch()
onPlayFromUri()
الموسيقى

"تشغيل موسيقى أو أغانٍ على (اسم التطبيق)". هذا طلب بحث فارغ.

"تشغيل (أغنية | فنان | ألبوم | نوع | قائمة تشغيل) على (اسم التطبيق)"

الراديو "تشغيل (التردد | المحطة) على (اسم التطبيق)"
كتاب مسموع

"قراءة كتابي المسموع عن (اسم التطبيق)"

"يُرجى قراءة (كتاب مسموع) على (اسم التطبيق)".

Podcasts "أريد تشغيل (بودكاست) على (اسم التطبيق)".
onPause() "الإيقاف مؤقّتًا"
onStop() "إيقاف"
onSkipToNext() "التالي (الأغنية | الحلقة | المقطع الصوتي)".
onSkipToPrevious() "(الأغنية | الحلقة | المقطع الصوتي) السابقة".
onSeekTo()

"إعادة التشغيل"

"التخطّي إلى الأمام ## ثانية".

"الرجوع بمقدار ## دقيقة"

لا ينطبق (يجب تعديل معلومات MediaMetadata الخاصة بك) "ما الذي يتم تشغيله؟"

الأخطاء

يعالج "مساعد Google" الأخطاء الواردة في جلسة وسائط عند حدوثها، ويُبلغ المستخدمين بها. احرص على تعديل جلسة الوسائط لحالة النقل ورمز الخطأ في PlaybackState بشكل صحيح، على النحو الموضّح في مقالة العمل مع جلسة وسائط. يتعرَّف "مساعد Google" على جميع رموز الخطأ التي يعرضها getErrorCode().

الحالات التي يُساء استخدامها عادةً

إليك بعض الأمثلة لحالات الخطأ التي يجب التأكد من معالجتها بشكل صحيح:

  • يحتاج المستخدم إلى تسجيل الدخول
    • اضبط رمز الخطأ PlaybackState على ERROR_CODE_AUTHENTICATION_EXPIRED.
    • اضبط رسالة الخطأ PlaybackState.
    • وإذا لزم الأمر للتشغيل، اضبط حالة PlaybackState على STATE_ERROR، وإلا احتفظ بباقي PlaybackState كما هي.
  • يطلب المستخدم إجراءً غير متاح
    • اضبط رمز الخطأ PlaybackState بشكل مناسب. على سبيل المثال، يمكنك ضبط PlaybackState على ERROR_CODE_NOT_SUPPORTED إذا كان الإجراء غير متاح أو على ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED إذا كان الإجراء محميًا بتسجيل الدخول.
    • اضبط رسالة الخطأ PlaybackState.
    • احتفظ بباقي PlaybackState كما هي.
  • يطلب المستخدم محتوى غير متاح في التطبيق
    • اضبط رمز الخطأ PlaybackState بشكل مناسب. على سبيل المثال، استخدِم ERROR_CODE_NOT_AVAILABLE_IN_REGION.
    • اضبط رسالة الخطأ PlaybackState.
    • يمكنك ضبط حالة PlaybackSate على STATE_ERROR لمقاطع التشغيل، وإلا احتفظ بباقي PlaybackState كما هي.
  • يطلب المستخدم محتوى في حال عدم توفّر مطابقة تامة. على سبيل المثال، يطلب مستخدم من الدرجة المجانية محتوى متاح فقط لمستخدمي الدرجة المميزة.
    • ننصحك بعدم عرض رسالة خطأ، بل يجب أن تعطي الأولوية للعثور على محتوى مشابه لتشغيله. سيتعامل "مساعد Google" مع سماع الردود الصوتية الأكثر صلة قبل بدء التشغيل.

التشغيل حسب النية بالشراء

بإمكان "مساعد Google" تشغيل تطبيق صوتي أو فيديو وبدء التشغيل من خلال إرسال هدف باستخدام رابط لصفحة في التطبيق.

يمكن أن يأتي الغرض والرابط لصفحة معيّنة في التطبيق من مصادر مختلفة:

  • عندما يبدأ "مساعد Google" تطبيقًا متوافقًا مع الأجهزة الجوّالة، يمكنه استخدام "بحث Google" لاسترداد المحتوى المرمَّز الذي يوفّر إجراء ساعة مع رابط.
  • عندما يبدأ "مساعد Google" تطبيق تلفزيون، يجب أن يتضمّن التطبيق مقدِّم خدمة البحث عن التلفزيون لعرض معرّفات الموارد المنتظمة (URI) لمحتوى الوسائط. يرسل "مساعد Google" طلبًا إلى مقدّم المحتوى والذي من المفترض أن يعرض هدفًا يحتوي على معرّف موارد منتظم (URI) لرابط صفحة معيّنة وإجراء اختياري. إذا عرض طلب البحث إجراءً في الغرض، يُرسل "مساعد Google" هذا الإجراء مع معرّف الموارد المنتظم (URI) إلى تطبيقك. إذا لم يحدّد مقدّم الخدمة إجراءً، سيضيف المساعد ACTION_VIEW إلى Intent.

يضيف "مساعد Google" EXTRA_START_PLAYBACK الإضافية ذات القيمة true إلى الغرض الذي يرسله إلى تطبيقك. ومن المفترض أن يبدأ تطبيقك في التشغيل عندما يتلقّى طلبًا من خلال EXTRA_START_PLAYBACK.

التعامل مع الأغراض أثناء النشاط

يمكن للمستخدمين أن يطلبوا من "مساعد Google" تشغيل محتوى ما أثناء تشغيل التطبيق لمحتوى من طلب سابق. وهذا يعني أنّ تطبيقك يمكن أن يتلقّى أغراضًا جديدة لبدء التشغيل عندما يكون نشاط التشغيل نشطًا بالفعل.

إنّ الأنشطة التي تدعم الأغراض ذات الروابط لصفحات في التطبيق يجب أن تتجاوز onNewIntent() للتعامل مع الطلبات الجديدة.

عند بدء التشغيل، قد يضيف "مساعد Google" علامات إضافية إلى الغرض الذي يرسله إلى تطبيقك. وخاصةً، قد يضيف FLAG_ACTIVITY_CLEAR_TOP أو FLAG_ACTIVITY_NEW_TASK أو كليهما. على الرغم من أنّ رمزك البرمجي لا يحتاج إلى التعامل مع هذه العلامات، يستجيب نظام Android لها. قد يؤثر ذلك في سلوك تطبيقك عند وصول طلب تشغيل ثانٍ بعنوان URI جديد أثناء تشغيل URI السابق. وفي هذه الحالة، من المفيد اختبار طريقة استجابة التطبيق. يمكنك استخدام أداة سطر الأوامر adb لمحاكاة الموقف (القيمة الثابتة 0x14000000 هي القيمة المنطقية على مستوى البت OR العلامتين):

adb shell 'am start -a android.intent.action.VIEW --ez android.intent.extra.START_PLAYBACK true -d "<first_uri>"' -f 0x14000000
adb shell 'am start -a android.intent.action.VIEW --ez android.intent.extra.START_PLAYBACK true -d "<second_uri>"' -f 0x14000000

التشغيل من خدمة

إذا كان تطبيقك يحتوي على media browser service تسمح بالاتصالات من "مساعد Google"، يمكن لخدمة "مساعد Google" تشغيل التطبيق من خلال التواصل مع media session الخاص بالخدمة. يجب ألا تشغّل خدمة متصفح الوسائط أي نشاط. سيشغِّل "مساعد Google" نشاطك بالاستناد إلى علامة PendingIntent التي تحدّدها باستخدام setSessionActivity().

تأكَّد من ضبط MediaSession.Token عند إعداد خدمة متصفح الوسائط. تذكَّر ضبط إجراءات التشغيل المتوافقة في جميع الأوقات، بما في ذلك أثناء الإعداد. يتوقع "مساعد Google" أن يضبط تطبيق الوسائط إجراءات التشغيل قبل أن يرسل "مساعد Google" أمر التشغيل الأول.

للبدء من إحدى الخدمات، ينفّذ "مساعد Google" واجهات برمجة تطبيقات عميل متصفّح الوسائط. ويجري مكالمات TransportControls التي تؤدي إلى استدعاء إجراءات PLAY في جلسة وسائط تطبيقك.

يوضِّح المخطّط التالي ترتيب المكالمات التي أنشأها "مساعد Google" وعمليات معاودة الاتصال في جلسات تشغيل الوسائط المقابلة. (يتم إرسال استدعاءات الإعداد فقط إذا كان تطبيقك يتيحها). جميع المكالمات غير متزامنة. ولا ينتظر "مساعد Google" أي ردّ من تطبيقك.

بدء التشغيل من خلال جلسة وسائط

عندما يصدر المستخدم طلبًا صوتيًا لتشغيله، يستجيب "مساعد Google" بإعلان قصير. فور اكتمال الإشعار، يُصدر "مساعد Google" إجراء PLAY. ولا ينتظر أي حالة تشغيل محددة.

إذا كان تطبيقك يتيح تنفيذ إجراءات "ACTION_PREPARE_*"، يطلب "مساعد Google" الإجراء PREPARE قبل بدء الإشعار.

الاتصال بـ MediaBrowserService

لاستخدام إحدى الخدمات لبدء تشغيل تطبيقك، يجب أن يتمكّن "مساعد Google" من الاتصال بخدمة MediaBrowserService الخاصة بالتطبيق واسترداد رمز MediaSession.Token. يتم التعامل مع طلبات الاتصال من خلال طريقة onGetRoot() الخاصة بالخدمة. هناك طريقتان لمعالجة الطلبات:

  • قبول جميع طلبات الربط
  • قبول طلبات الاتصال من تطبيق "مساعد Google" فقط

قبول جميع طلبات الربط

يجب إرجاع متصفِّحRoot للسماح لخدمة "مساعد Google" بإرسال الأوامر إلى جلسة تشغيل الوسائط. تتمثل أسهل طريقة في السماح لجميع تطبيقات MediaBrowser بالاتصال بخدمة MediaBrowserService. يجب عرض جذر متصفح غير فارغ. إليك الرمز الساري من Universal Music Player:

Kotlin

override fun onGetRoot(
        clientPackageName: String,
        clientUid: Int,
        rootHints: Bundle?
): BrowserRoot? {

    // To ensure you are not allowing any arbitrary app to browse your app's contents, you
    // need to check the origin:
    if (!packageValidator.isCallerAllowed(this, clientPackageName, clientUid)) {
        // If the request comes from an untrusted package, return an empty browser root.
        // If you return null, then the media browser will not be able to connect and
        // no further calls will be made to other media browsing methods.
        Log.i(TAG, "OnGetRoot: Browsing NOT ALLOWED for unknown caller. Returning empty "
                + "browser root so all apps can use MediaController. $clientPackageName")
        return MediaBrowserServiceCompat.BrowserRoot(MEDIA_ID_EMPTY_ROOT, null)
    }

    // Return browser roots for browsing...
}

Java

@Override
public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid,
                             Bundle rootHints) {

    // To ensure you are not allowing any arbitrary app to browse your app's contents, you
    // need to check the origin:
    if (!packageValidator.isCallerAllowed(this, clientPackageName, clientUid)) {
        // If the request comes from an untrusted package, return an empty browser root.
        // If you return null, then the media browser will not be able to connect and
        // no further calls will be made to other media browsing methods.
        LogHelper.i(TAG, "OnGetRoot: Browsing NOT ALLOWED for unknown caller. "
                + "Returning empty browser root so all apps can use MediaController."
                + clientPackageName);
        return new MediaBrowserServiceCompat.BrowserRoot(MEDIA_ID_EMPTY_ROOT, null);
    }

    // Return browser roots for browsing...
}

قبول حزمة تطبيق "مساعد Google" وتوقيعها

يمكنك السماح بشكل واضح لـ "مساعد Google" بالاتصال بخدمة متصفح الوسائط من خلال البحث عن اسم الحزمة والتوقيع. سيتلقّى تطبيقك اسم الحزمة في طريقة onGetRoot في MediaBrowserService. يجب إرجاع متصفِّحRoot للسماح لخدمة "مساعد Google" بإرسال الأوامر إلى جلسة تشغيل الوسائط. يحتفظ نموذج Universal Music Player بقائمة بأسماء الحزم والتوقيعات المعروفة. في ما يلي أسماء الحِزم والتوقيعات التي يستخدمها "مساعد Google".

<signature name="Google" package="com.google.android.googlequicksearchbox">
    <key release="false">19:75:b2:f1:71:77:bc:89:a5:df:f3:1f:9e:64:a6:ca:e2:81:a5:3d:c1:d1:d5:9b:1d:14:7f:e1:c8:2a:fa:00</key>
    <key release="true">f0:fd:6c:5b:41:0f:25:cb:25:c3:b5:33:46:c8:97:2f:ae:30:f8:ee:74:11:df:91:04:80:ad:6b:2d:60:db:83</key>
</signature>

<signature name="Google Assistant on Android Automotive OS" package="com.google.android.carassistant">
    <key release="false">17:E2:81:11:06:2F:97:A8:60:79:7A:83:70:5B:F8:2C:7C:C0:29:35:56:6D:46:22:BC:4E:CF:EE:1B:EB:F8:15</key>
    <key release="true">74:B6:FB:F7:10:E8:D9:0D:44:D3:40:12:58:89:B4:23:06:A6:2C:43:79:D0:E5:A6:62:20:E3:A6:8A:BF:90:E2</key>
</signature>