دليل نقل البيانات إلى AndroidX Media3

يجب نقل التطبيقات التي تستخدم حاليًا مكتبة com.google.android.exoplayer2 المستقلة وandroidx.media إلى androidx.media3. يمكنك استخدام النص البرمجي لنقل البيانات لنقل ملفات إصدار Grava وملفات مصدر Java وKotlin وملفات تنسيق XML من ExoPlayer 2.19.1 إلى AndroidX Media3 1.1.1.

نظرة عامة

قبل إجراء عملية النقل، راجِع الأقسام التالية للاطّلاع على مزيد من المعلومات عن مزايا واجهات برمجة التطبيقات وواجهات برمجة التطبيقات الجديدة المطلوب نقلها والمتطلبات الأساسية التي يجب أن يستوفيها مشروع تطبيقك.

أسباب نقل البيانات إلى Jetpack Media3

  • إنّه الموقع الرئيسي الجديد لمنصّة ExoPlayer، بينما تم إيقاف com.google.android.exoplayer2 نهائيًا.
  • استخدام Player API في مختلف المكوّنات/العمليات من خلال MediaBrowser/MediaController
  • استخدِم الإمكانات المحسَّنة لـ MediaSession وواجهة برمجة التطبيقات MediaController.
  • الإعلان عن إمكانات التشغيل باستخدام عنصر تحكّم في الوصول بالغ الدقة
  • يمكنك تبسيط تطبيقك من خلال إزالة MediaSessionConnector وPlayerNotificationManager.
  • متوافق مع الأنظمة القديمة مع واجهات برمجة تطبيقات برنامج media-compat (MediaBrowserCompat/MediaControllerCompat/MediaMetadataCompat)

واجهات برمجة تطبيقات الوسائط المراد نقلها إلى AndroidX Media3

  • ExoPlayer وإضافاته
    يشمل ذلك جميع وحدات مشروع ExoPlayer القديم باستثناء وحدة mediasession التي تم إيقافها. يمكن نقل التطبيقات أو الوحدات استنادًا إلى الحزم في com.google.android.exoplayer2 باستخدام النص البرمجي لنقل البيانات.
  • MediaSessionConnector (استنادًا إلى حِزم androidx.media.* في androidx.media:media:1.4.3+)
    يجب إزالة MediaSessionConnector واستخدام androidx.media3.session.MediaSession بدلاً من ذلك.
  • MediaBrowserServiceCompat (اعتمادًا على حزم androidx.media.* الخاصة بـ androidx.media:media:1.4.3+)
    عليك نقل الفئات الفرعية من androidx.media.MediaBrowserServiceCompat إلى androidx.media3.session.MediaLibraryService واستخدام الرموز البرمجية من خلال MediaBrowserCompat.MediaItem إلى androidx.media3.common.MediaItem.
  • MediaBrowserCompat (اعتمادًا على حِزم android.support.v4.media.* من androidx.media:media:1.4.3+)
    نقل رمز العميل باستخدام MediaBrowserCompat أو MediaControllerCompat لاستخدام androidx.media3.session.MediaBrowser مع androidx.media3.common.MediaItem.

المتطلّبات الأساسية

  1. التأكُّد من أنّ مشروعك خاضعًا للتحكم في المصدر

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

  2. تحديث تطبيقك

    • ننصحك بتعديل مشروعك لاستخدام أحدث إصدار من مكتبة ExoPlayer وإزالة أي طلبات استدعاء للأساليب المتوقّفة نهائيًا. إذا أردت استخدام النص البرمجي لعملية نقل البيانات، عليك مطابقة الإصدار الذي يتم التحديث إليه مع الإصدار الذي يتعامل معه النص البرمجي.

    • يجب زيادة قيمة compileSdkVersion في تطبيقك إلى 32 على الأقل.

    • عليك ترقية Gradle والمكوّن الإضافي "Android Studio Gradle" إلى إصدار حديث يعمل مع الملحقات المُعدَّلة الواردة أعلاه. على سبيل المثال:

      • إصدار المكوّن الإضافي لنظام Gradle المتوافق مع Android: 7.1.0
      • إصدار Gradle: 7.4
    • استبدال جميع عبارات استيراد أحرف البدل التي تستخدم علامة النجمة (*) واستخدام عبارات الاستيراد المؤهلة بالكامل: احذف عبارات استيراد أحرف البدل واستخدِم "استوديو Android" لاستيراد العبارات المؤهلة بالكامل (F2 - Alt/Enter وF2 - Alt/Enter ، ...).

    • نقل البيانات من com.google.android.exoplayer2.PlayerView إلى com.google.android.exoplayer2.StyledPlayerView وهو ضروري لأنه لا يتوفر مكافئ لـ com.google.android.exoplayer2.PlayerView في AndroidX Media3.

نقل بيانات ExoPlayer من خلال إتاحة النص البرمجي

يسهّل النص البرمجي الانتقال من com.google.android.exoplayer2 إلى بنية الحزمة والوحدة الجديدة ضمن androidx.media3. يطبق النص البرمجي بعض عمليات التحقق من الصحة على مشروعك ويطبع التحذيرات في حالة فشل التحقق من الصحة. وبخلاف ذلك، يتم تطبيق عمليات تعيين الصفوف والحزم التي تمت إعادة تسميتها في موارد مشروع Android Gradle المكتوب بلغة Java أو Kotlin.

usage: ./media3-migration.sh [-p|-c|-d|-v]|[-m|-l [-x <path>] [-f] PROJECT_ROOT]
 PROJECT_ROOT: path to your project root (location of 'gradlew')
 -p: list package mappings and then exit
 -c: list class mappings (precedence over package mappings) and then exit
 -d: list dependency mappings and then exit
 -l: list files that will be considered for rewrite and then exit
 -x: exclude the path from the list of file to be changed: 'app/src/test'
 -m: migrate packages, classes and dependencies to AndroidX Media3
 -f: force the action even when validation fails
 -v: print the exoplayer2/media3 version strings of this script
 -h, --help: show this help text

استخدام النص البرمجي لنقل البيانات

  1. نزِّل النص البرمجي لنقل البيانات من علامة مشروع ExoPlayer على GitHub المتوافق مع الإصدار الذي حدّثت تطبيقك إليه:

    curl -o media3-migration.sh \
      "https://raw.githubusercontent.com/google/ExoPlayer/r2.19.1/media3-migration.sh"
    
  2. جعل النص البرمجي قابلاً للتنفيذ:

    chmod 744 media3-migration.sh
    
  3. شغِّل النص البرمجي باستخدام --help للاطّلاع على الخيارات.

  4. شغِّل النص البرمجي باستخدام -l لإدراج مجموعة الملفات التي تم اختيارها لنقلها (استخدِم -f لفرض عرض البيانات بدون تحذيرات):

    ./media3-migration.sh -l -f /path/to/gradle/project/root
    
  5. شغِّل النص البرمجي باستخدام -m لربط الحِزم والفئات والوحدات بـ Media3. سيؤدي تشغيل النص البرمجي باستخدام الخيار -m إلى تطبيق التغييرات على الملفات المحدّدة.

    • التوقف عند خطأ في التحقق من الصحة بدون إجراء تغييرات
    ./media3-migration.sh -m /path/to/gradle/project/root
    
    • التنفيذ الإجباري

    إذا كشف النص البرمجي عن مخالفة للمتطلبات الأساسية، يمكن فرض عملية النقل باستخدام علامة -f:

    ./media3-migration.sh -m -f /path/to/gradle/project/root
    
 # list files selected for migration when excluding paths
 ./media3-migration.sh -l -x "app/src/test/" -x "service/" /path/to/project/root
 # migrate the selected files
 ./media3-migration.sh -m -x "app/src/test/" -x "service/" /path/to/project/root

أكمِل هذه الخطوات اليدوية بعد تشغيل النص البرمجي باستخدام الخيار -m:

  1. التحقّق من الطريقة التي غيّر بها النص البرمجي رمزك: استخدِم أداة مختلفة وأصلح المشاكل المحتملة (يمكنك الإبلاغ عن خطأ إذا كنت تعتقد أنّ النص البرمجي يتضمّن مشكلة عامة تم طرحها بدون ضبط الخيار -f).
  2. إنشاء المشروع: إمّا استخدام "./gradlew clean build" أو في "استوديو Android" اختَر ملف > مزامنة المشروع مع ملفات Gradle، ثم إنشاء > تنظيف المشروع، ثم إنشاء > إعادة إنشاء المشروع (راقب الإصدار في علامة التبويب "إنشاء - إنشاء النتائج" في "استوديو Android".

خطوات المتابعة المقترَحة:

  1. حلّ الموافقة على الأخطاء المتعلّقة باستخدام واجهات برمجة التطبيقات غير الثابتة
  2. استبدال طلبات البيانات من واجهة برمجة التطبيقات المتوقّفة نهائيًا: استخدام واجهة برمجة التطبيقات البديلة المقترَحة ضع مؤشر الماوس فوق التحذير في "استوديو Android" وراجع JavaDoc الخاص بالرمز الذي تم إيقافه لمعرفة ما يجب استخدامه بدلاً من طلب معيّن.
  3. ترتيب عبارات الاستيراد: افتح المشروع في "استوديو Android"، ثم انقر بزر الماوس الأيمن على عقدة مجلد الحزمة في عارض المشروع واختَر تحسين عمليات الاستيراد في الحزم التي تحتوي على الملفات المصدر التي تمّ تغييرها.

استبدال MediaSessionConnector بـ androidx.media3.session.MediaSession

في عالم MediaSessionCompat القديم، كان MediaSessionConnector مسؤولاً عن مزامنة حالة المشغّل مع حالة الجلسة وتلقّي الأوامر من وحدات التحكّم التي تحتاج إلى التفويض بالأساليب المناسبة للمشغّل. باستخدام AndroidX Media3، يتم تنفيذ ذلك من خلال MediaSession مباشرةً بدون الحاجة إلى موصِّل.

  1. إزالة جميع مراجع MediaSessionConnector واستخداماته: إذا كنت قد استخدمت النص البرمجي الآلي لنقل فئات وحزم ExoPlayer، من المحتمل أن يكون النص البرمجي قد ترك الرمز في حالة غير قابلة للتجميع بشأن MediaSessionConnector التي لا يمكن حلها. سيعرض لك Android Studio الرمز المعطّل عند محاولة إنشاء التطبيق أو تشغيله.

  2. في ملف build.gradle الذي تحتفظ فيه بتبعياتك، أضِف تبعية للتنفيذ إلى وحدة جلسة AndroidX Media3 وأزِل التبعية القديمة:

    implementation "androidx.media3:media3-session:1.3.1"
    
  3. استبدِل MediaSessionCompat بـ androidx.media3.session.MediaSession.

  4. في موقع الترميز الإلكتروني الذي أنشأت فيه MediaSessionCompat القديم، استخدِم androidx.media3.session.MediaSession.Builder من أجل إنشاء MediaSession. مرر المشغِّل لإنشاء أداة إنشاء الجلسات.

    val player = ExoPlayer.Builder(context).build()
    mediaSession = MediaSession.Builder(context, player)
        .setSessionCallback(MySessionCallback())
        .build()
    
  5. نفِّذ MySessionCallback حسب ما يطلبه تطبيقك. وهذا إجراء اختياري. إذا أردت السماح لوحدات التحكّم بإضافة عناصر الوسائط إلى المشغِّل، فنفِّذ السمة MediaSession.Callback.onAddMediaItems(). وهي توفّر طرقًا متعددة حالية وقديمة خاصة بواجهات برمجة التطبيقات تضيف ملفات الوسائط إلى المشغّل بطريقة متوافقة مع الأنظمة القديمة. ويشمل ذلك طرق MediaController.set/addMediaItems() الخاصة بوحدة التحكّم Media3، بالإضافة إلى طرق TransportControls.prepareFrom*/playFrom* في واجهة برمجة التطبيقات القديمة. يمكن العثور على نموذج لتنفيذ onAddMediaItems في PlaybackService في تطبيق العرض التوضيحي للجلسة.

  6. ارفع إصبعك عن جلسة الوسائط في موقع الرمز البرمجي حيث تلفّت جلستك قبل عملية النقل:

    mediaSession?.run {
      player.release()
      release()
      mediaSession = null
    }
    

وظيفة "MediaSessionConnector" في Media3

يعرض الجدول التالي واجهات برمجة تطبيقات Media3 التي تعالج الوظائف التي تم تنفيذها سابقًا في MediaSessionConnector.

أداة MediaSessionConnectorAndroidX Media3
CustomActionProvider MediaSession.Callback.onCustomCommand()/ MediaSession.setCustomLayout()
PlaybackPreparer MediaSession.Callback.onAddMediaItems() (يُطلق على prepare() داخليًا)
QueueNavigator ForwardingPlayer
QueueEditor MediaSession.Callback.onAddMediaItems()
RatingCallback MediaSession.Callback.onSetRating()
PlayerNotificationManager DefaultMediaNotificationProvider/ MediaNotification.Provider

نقل بيانات MediaBrowserService إلى MediaLibraryService

يقدّم AndroidX Media3 الإصدار MediaLibraryService الذي يحل محل MediaBrowserServiceCompat. يوفّر مستند JavaDoc التابع لـ MediaLibraryService وفئته MediaSessionService مقدمة جيدة حول واجهة برمجة التطبيقات ونموذج البرمجة غير المتزامنة للخدمة.

تتوافق السمة MediaLibraryService مع الإصدارات القديمة مع "MediaBrowserService". ويستمر تطبيق العميل الذي يستخدم MediaBrowserCompat أو MediaControllerCompat في العمل بدون تغيير الرمز عند الربط بجهاز MediaLibraryService. بالنسبة إلى العميل، يكون واضحًا ما إذا كان تطبيقك يستخدم MediaLibraryService أو MediaBrowserServiceCompat قديم.

مخطط لمكونات التطبيق مع الخدمة والنشاط والتطبيقات الخارجية.
الشكل 1: نظرة عامة على مكوِّنات تطبيق الوسائط
  1. لكي يعمل التوافق مع الأنظمة القديمة، يجب تسجيل واجهتَي الخدمة مع خدمتك في AndroidManifest.xml. بهذه الطريقة، يعثر العميل على خدمتك من خلال واجهة الخدمة المطلوبة:

    <service android:name=".MusicService" android:exported="true">
        <intent-filter>
            <action android:name="androidx.media3.session.MediaLibraryService"/>
            <action android:name="android.media.browse.MediaBrowserService" />
        </intent-filter>
    </service>
    
  2. في ملف build.gradle الذي تحتفظ فيه بتبعياتك، أضِف تبعية للتنفيذ إلى وحدة جلسة AndroidX Media3 وأزِل التبعية القديمة:

    implementation "androidx.media3:media3-session:1.3.1"
    
  3. تغيير خدمتك ليتم اكتسابها من MediaLibraryService بدلاً من MediaBrowserService كما ذكرنا سابقًا، يتوافق MediaLibraryService مع الإصدار MediaBrowserService القديم. وبالتالي، لا تزال واجهة برمجة التطبيقات الأوسع التي توفّرها الخدمة للعملاء لا تزال كما هي. لذا من المحتمل أن يتمكّن أي تطبيق من الاحتفاظ بمعظم المنطق المطلوب لتنفيذ MediaBrowserService وتعديله بما يتناسب مع MediaLibraryService الجديد.

    في ما يلي الاختلافات الرئيسية مقارنةً بإصدار MediaBrowserServiceCompat القديم:

    • تنفيذ طرق دورة حياة الخدمة: الطرق التي يجب إلغاؤها في الخدمة نفسها هي onCreate/onDestroy، حيث يخصص أو يخصص التطبيق جلسة المكتبة والمشغّل والموارد الأخرى. بالإضافة إلى الطرق العادية لدورة حياة الخدمة، يجب أن يتجاهل التطبيق onGetSession(MediaSession.ControllerInfo) لعرض MediaLibrarySession الذي تم إنشاؤه في onCreate.

    • تنفيذ MediaLibraryService.MediaLibrarySessionCallback: يتطلب إنشاء جلسة MediaLibraryService.MediaLibrarySessionCallback لتنفيذ الطُرق الفعلية لواجهات برمجة التطبيقات في النطاق. لذا بدلاً من إلغاء طُرق واجهة برمجة التطبيقات في الخدمة القديمة، سيتم إلغاء طرق MediaLibrarySession.Callback بدلاً من ذلك.

      بعد ذلك، يتم استخدام هذه الدالة لإنشاء MediaLibrarySession:

      mediaLibrarySession =
            MediaLibrarySession.Builder(this, player, MySessionCallback())
               .build()
      

      ابحث عن واجهة برمجة التطبيقات الكاملة لـ MediaLibrarySessionCallback في وثائق واجهة برمجة التطبيقات.

    • تنفيذ MediaSession.Callback.onAddMediaItems(): دالة الاستدعاء onAddMediaItems(MediaSession, ControllerInfo, List<MediaItem>) تعرض طرقًا متعددة لواجهة برمجة التطبيقات الحالية والقديمة التي تضيف ملفات وسائط إلى المشغّل بطريقة متوافقة مع الأنظمة القديمة. ويتضمّن ذلك طرق MediaController.set/addMediaItems() الخاصة بوحدة التحكّم Media3، بالإضافة إلى طرق TransportControls.prepareFrom*/playFrom* في واجهة برمجة التطبيقات القديمة. يمكن العثور على نموذج لتنفيذ عملية الاستدعاء في PlaybackService من تطبيق العرض التوضيحي للجلسة.

    • يستخدم AndroidX Media3 androidx.media3.common.MediaItem بدلاً من MediaBrowserCompat.MediaItem وMediaMetadataCompat. يجب تغيير أجزاء الرمز المرتبطة بالفئات القديمة وفقًا لذلك، أو ربطها بـ Media3 MediaItem بدلاً من ذلك.

    • تم تغيير نموذج البرمجة غير المتزامنة إلى Futures العام على عكس أسلوب Result القابل للفصل في "MediaBrowserServiceCompat". يمكن أن يعرض تنفيذ خدمتك ListenableFuture غير متزامن بدلاً من فصل نتيجة أو إرجاع مستقبل فوري لعرض قيمة مباشرةً.

إزالة PlayerNotificationManager

يتوافق "MediaLibraryService" مع إشعارات الوسائط تلقائيًا ويمكن إزالة "PlayerNotificationManager" عند استخدام MediaLibraryService أو MediaSessionService.

يمكن للتطبيق تخصيص الإشعار من خلال ضبط قيمة MediaNotification.Provider مخصّصة في onCreate() تحل محل DefaultMediaNotificationProvider. بعد ذلك، يتولى MediaLibraryService بدء الخدمة في المقدّمة على النحو المطلوب.

من خلال تجاوز MediaLibraryService.updateNotification()، سيتمكّن التطبيق من الحصول على الملكية الكاملة لنشر إشعار وبدء/إيقاف الخدمة في المقدّمة على النحو المطلوب.

نقل رمز العميل باستخدام MediaBrowser

في AndroidX Media3، ينفذ MediaBrowser الواجهات MediaController/Player ويمكن استخدامه للتحكّم في تشغيل الوسائط إلى جانب تصفُّح مكتبة الوسائط. إذا كان عليك إنشاء MediaBrowserCompat وMediaControllerCompat في الإصدار القديم، يمكنك تنفيذ الإجراء نفسه من خلال استخدام MediaBrowser فقط في Media3.

يمكن إنشاء MediaBrowser وانتظار الاتصال بالخدمة التي يتم إنشاؤها:

scope.launch {
    val sessionToken =
        SessionToken(context, ComponentName(context, MusicService::class.java)
    browser =
        MediaBrowser.Builder(context, sessionToken))
            .setListener(BrowserListener())
            .buildAsync()
            .await()
    // Get the library root to start browsing the library.
    root = browser.getLibraryRoot(/* params= */ null).await();
    // Add a MediaController.Listener to listen to player state events.
    browser.addListener(playerListener)
    playerView.setPlayer(browser)
}

ألقِ نظرة على القسم التحكّم في التشغيل في جلسة الوسائط لمعرفة كيفية إنشاء MediaController للتحكم في التشغيل في الخلفية.

خطوات إضافية وإخلاء

أخطاء واجهة برمجة التطبيقات غير الثابتة

بعد النقل إلى Media3، قد تظهر لك أخطاء أداة Lint حول الاستخدامات غير المستقرة لواجهة برمجة التطبيقات. إن واجهات برمجة التطبيقات هذه آمنة للاستخدام، كما أن أخطاء الوبر هي منتج ثانوي لضمانات التوافق الثنائي الجديدة. إذا كنت لا تطلب توافقًا ثنائيًا صارمًا، يمكن منع هذه الأخطاء بأمان باستخدام تعليق توضيحي @OptIn.

معلومات أساسية

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

أدّت هذه التغييرات التي قد تؤدي إلى أعطال في الوصول إلى مشكلتَين لمستخدمي مكتبتَي ExoPlayer v1 والإصدار 2:

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

التحسينات في Media3

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

بعد الترحيل من ExoPlayer v2 إلى Media3، قد تظهر لك الكثير من أخطاء أداة Lint غير المستقرة لواجهة برمجة التطبيقات. وقد يجعل ذلك يبدو أن Media3 "أقل استقرارًا" من الإصدار 2 من ExoPlayer. ولكن الأمر ليس كذلك. تتمتع الأجزاء "غير الثابتة" من Media3 API بمستوى الثبات نفسه مثل كامل سطح واجهة برمجة التطبيقات ExoPlayer v2، ولا تتوفر ضمانات سطح واجهة برمجة التطبيقات Media3 API الثابت في الإصدار الثاني من ExoPlayer على الإطلاق. يكمن الاختلاف ببساطة في أن خطأ الوبر ينبهك الآن إلى مستويات الثبات المختلفة.

معالجة أخطاء أداة Lint غير الثابتة لواجهة برمجة التطبيقات

راجِع قسم تحديد المشاكل وحلّها في أخطاء أداة Lint هذه للاطّلاع على تفاصيل حول كيفية إضافة تعليقات توضيحية إلى استخدامات Java وKotlin لواجهات برمجة التطبيقات غير المستقرة باستخدام @OptIn.

واجهات برمجة التطبيقات التي تم إيقافها نهائيًا

قد تلاحظ أنّه تم في "استوديو Android" تنفيذ طلبات البيانات إلى واجهات برمجة التطبيقات المتوقّفة نهائيًا. نقترح استبدال هذه المكالمات بالبديل المناسب. مرِّر مؤشر الماوس فوق الرمز لعرض JavaDoc الذي يحدد واجهة برمجة التطبيقات التي يجب استخدامها بدلاً من ذلك.

لقطة شاشة: كيفية عرض JavaDoc مع طريقة أخرى متوقّفة نهائيًا
الشكل 3: يقترح تلميح JavaDoc في "استوديو Android" بديلاً لأي رمز تم إيقاف العمل به.

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

  • التطبيق التجريبي لجلسة AndroidX Media3 (الأجهزة الجوّالة وأجهزة WearOS)
    • الإجراءات المخصّصة
    • إشعار واجهة مستخدم النظام، MediaButton/BT
    • التحكّم في التشغيل باستخدام "مساعد Google"
  • UAMP: Android Media Player (branch media3) (الأجهزة الجوّالة، AutomotiveOS)
    • إشعار واجهة مستخدم النظام، MediaButton/BT، استئناف التشغيل
    • عنصر التحكّم في التشغيل على نظام التشغيل Wear OS أو "مساعد Google"
    • AutomotiveOS: الطلب المخصَّص وتسجيل الدخول