بدء استخدام CastPlayer

CastPlayer هو تنفيذ مشغّل Jetpack Media3 يتيح التشغيل على الجهاز وإرسال المحتوى إلى جهاز خارجي متوافق مع تكنولوجيا Google Cast. CastPlayer تسهّل إضافة وظيفة البث إلى تطبيقك وتوفّر ميزات غنية تتيح التبديل بسلاسة بين التشغيل المحلي والتشغيل عن بُعد. يوضّح لك هذا الدليل كيفية دمج CastPlayer في تطبيق الوسائط.

لدمج Cast مع منصات أخرى، يُرجى الاطّلاع على حزمة تطوير البرامج (SDK) الخاصة بـ Cast.

إضافة CastPlayer كعنصر تابع

لبدء استخدام CastPlayer، أضِف الاعتماديات المطلوبة في AndroidX Media3 وCastPlayer إلى ملف build.gradle الخاص بوحدة تطبيقك.

Kotlin

implementation("androidx.media3:media3-exoplayer:1.9.0-alpha01")
implementation("androidx.media3:media3-ui:1.9.0-alpha01")
implementation("androidx.media3:media3-session:1.9.0-alpha01")
implementation("androidx.media3:media3-cast:1.9.0-alpha01")

Groovy

implementation "androidx.media3:media3-exoplayer:1.9.0-alpha01"
implementation "androidx.media3:media3-ui:1.9.0-alpha01"
implementation "androidx.media3:media3-session:1.9.0-alpha01"
implementation "androidx.media3:media3-cast:1.9.0-alpha01"

راجِع ملاحظات إصدار Jetpack Media للعثور على أحدث إصدار أولي حتى تتمكّن من دمج CastPlayer في تطبيقك، علمًا بأنّه يجب أن تكون جميع الوحدات النمطية من الإصدار نفسه.

لمزيد من المعلومات حول وحدات المكتبة المتاحة، راجِع صفحة Google Maven AndroidX Media3.

إعداد CastPlayer

لضبط CastPlayer، عدِّل ملف AndroidManifest.xml باستخدام موفّر خيارات.

موفّر الخيارات

يتطلّب CastPlayer موفّر خيارات لضبط سلوكه. لإعداد بسيط، يمكنك استخدام موفّر الخيارات التلقائي من خلال إضافته إلى ملف AndroidManifest.xml. يستخدم هذا الخيار الإعدادات التلقائية، بما في ذلك تطبيق الاستقبال التلقائي.

<application>
  <meta-data
    android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
    android:value="androidx.media3.cast.DefaultCastOptionsProvider" />
</application>

لتخصيص الإعدادات، عليك تنفيذ OptionsProvider مخصّص. اطّلِع على دليل CastOptions لمعرفة كيفية إجراء ذلك.

إضافة جهاز استقبال لعمليات نقل الوسائط

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

<application>
  <receiver android:name="androidx.mediarouter.media.MediaTransferReceiver" />
</application>

إنشاء CastPlayer

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

Kotlin

override fun onCreate() {
  super.onCreate()

  val exoPlayer = ExoPlayer.Builder(context).build()
  val castPlayer = CastPlayer.Builder(context)
      .setLocalPlayer(exoPlayer)
      .build()

  mediaSession = MediaSession.Builder(context, castPlayer).build()
}

Java

@Override
public void onCreate() {
  super.onCreate();

  ExoPlayer exoPlayer = new ExoPlayer.Builder(context).build();
  CastPlayer castPlayer = new CastPlayer.Builder(context)
      .setLocalPlayer(exoPlayer)
      .build();

  mediaSession = new MediaSession.Builder(
    /* context= */ context, /* player= */ castPlayer).build();
}

إضافة عناصر واجهة المستخدم

أضِف MediaRouteButton إلى واجهة مستخدم تطبيقك للسماح للمستخدمين باختيار جهاز Cast. يوضّح لك هذا القسم كيفية إضافة الزر ومعالجة الأحداث لتعديل واجهة المستخدم عند التبديل بين تشغيل المحتوى على الجهاز المحلي والجهاز البعيد.

ضبط MediaRouteButton

هناك أربع طرق محتملة لإضافة MediaRouteButton إلى واجهة المستخدم الخاصة بنشاطك ليتفاعل معها المستخدمون. سيعتمد الاختيار على المظهر الذي تريده لواجهة المستخدم الخاصة بنشاط اللاعبين وطريقة عملها.

إضافة زر مسار وسائط قابل للإنشاء إلى "المشغّل"

يمكنك إضافة العنصر القابل للإنشاء MediaRouteButton إلى واجهة مستخدم المشغّل. لمزيد من المعلومات، يُرجى الاطّلاع على دليل إنشاء.

Kotlin

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.media3.cast.MediaRouteButton

@Composable
fun PlayerComposeView(player: Player, modifier: Modifier = Modifier) {
  var controlsVisible by remember { mutableStateOf(false) }

  Box(
    modifier = modifier.clickable { controlsVisible = true },
    contentAlignment = Alignment.Center,
  ) {
    PlayerSurface(player = player, modifier = modifier)
    AnimatedVisibility(visible = controlsVisible, enter = fadeIn(), exit = fadeOut()) {
      Box(modifier = Modifier.fillMaxSize()) {
        MediaRouteButton(modifier = Modifier.align(Alignment.TopEnd))
        PrimaryControls(player = player, modifier = Modifier.align(Alignment.Center))
      }
    }
  }
}

@Composable
fun PrimaryControls(player: Player, modifier: Modifier = Modifier) {
  ...
}

إضافة زر مسار الوسائط إلى PlayerView

يمكنك إضافة MediaRouteButton مباشرةً ضمن عناصر تحكّم واجهة المستخدم في PlayerView. بعد ضبط MediaController كمشغّل PlayerView، قدِّم MediaRouteButtonViewProvider لعرض زر البث على المشغّل.

Kotlin

override fun onStart() {
  super.onStart()

  playerView.player = mediaController
  playerView.setMediaRouteButtonViewProvider(MediaRouteButtonViewProvider())
}

Java

@Override
public void onStart() {
  super.onStart();

  playerView.setPlayer(mediaController);
  playerView.setMediaRouteButtonViewProvider(new MediaRouteButtonViewProvider());
}

إضافة زر مسار الوسائط إلى قائمة شريط التطبيق

تُعدّ هذه الطريقة زر مسار الوسائط في قائمة شريط التطبيق. يجب إجراء تعديلات على كل من ملف البيان وActivity لعرض هذا النمط من الأزرار.

<menu xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:app="http://schemas.android.com/apk/res-auto">
  <item android:id="@+id/media_route_menu_item"
    android:title="@string/media_route_menu_title"
    app:showAsAction="always"
    app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"/>
</menu>

Kotlin

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    ...
    menuInflater.inflate(R.menu.sample_media_route_button_menu, menu)
    val menuItemFuture: ListenableFuture<MenuItem> =
        MediaRouteButtonFactory.setUpMediaRouteButton(
            context, menu, R.id.media_route_menu_item)
    Futures.addCallback(
        menuItemFuture,
        object : FutureCallback<MenuItem> {
            override fun onSuccess(menuItem: MenuItem?) {
                // Do something with the menu item.
            }

            override fun onFailure(t: Throwable) {
                // Handle the failure.
            }
        },
        executor)
    ...
}

Java

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    ...
    getMenuInflater().inflate(R.menu.sample_media_route_button_menu, menu);
    ListenableFuture<MenuItem> menuItemFuture =
        MediaRouteButtonFactory.setUpMediaRouteButton(
          context, menu, R.id.media_route_menu_item);
    Futures.addCallback(
        menuItemFuture,
        new FutureCallback<MenuItem>() {
          @Override
          public void onSuccess(MenuItem menuItem) {
            // Do something with the menu item.
          }

          @Override
          public void onFailure(Throwable t) {
            // Handle the failure.
          }
        },
        executor);
    ...
}

إضافة زر مسار الوسائط كطريقة عرض

بدلاً من ذلك، يمكنك إعداد MediaRouteButton في ملف activity layout.xml. لإكمال عملية إعداد MediaRouteButton، استخدِم MediaRouteButtonFactory Media3 Cast في رمز Activity.

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)

  findViewById<MediaRouteButton>(R.id.media_route_button)?.also {
    val unused = MediaRouteButtonFactory.setUpMediaRouteButton(context, it)
  }
}

Java

@Override
public void onCreate(Bundle savedInstanceState) {
    ...
    MediaRouteButton button = findViewById(R.id.media_route_button);
    ListenableFuture<Void> setUpFuture =
        MediaRouteButtonFactory.setUpMediaRouteButton(context, button);
}

أداة معالجة النشاط

أنشئ Player.Listener في Activity للاستماع إلى التغييرات في الموقع الجغرافي لتشغيل الوسائط. عندما يتغيّر playbackType بين PLAYBACK_TYPE_LOCAL وPLAYBACK_TYPE_REMOTE، يمكنك تعديل واجهة المستخدم حسب الحاجة. لمنع تسرُّب الذاكرة وحصر نشاط أداة معالجة الأحداث في الحالات التي يكون فيها تطبيقك مرئيًا فقط، سجِّل أداة معالجة الأحداث في onStart وألغِ تسجيلها في onStop:

Kotlin

import androidx.media3.common.DeviceInfo
import androidx.media3.common.Player

private val playerListener: Player.Listener =
  object : Player.Listener {
    override fun onDeviceInfoChanged(deviceInfo: DeviceInfo) {
      if (deviceInfo.playbackType == DeviceInfo.PLAYBACK_TYPE_LOCAL) {
        // Add UI changes for local playback.
      } else if (deviceInfo.playbackType == DeviceInfo.PLAYBACK_TYPE_REMOTE) {
        // Add UI changes for remote playback.
      }
    }
  }

override fun onStart() {
  super.onStart()
  mediaController.addListener(playerListener)
}

override fun onStop() {
  super.onStop()
  mediaController.removeListener(playerListener)
}

Java

import androidx.media3.common.DeviceInfo;
import androidx.media3.common.Player;

private Player.Listener playerListener =
    new Player.Listener() {
      @Override
      public void onDeviceInfoChanged(DeviceInfo deviceInfo) {
        if (deviceInfo.playbackType == DeviceInfo.PLAYBACK_TYPE_LOCAL) {
          // Add UI changes for local playback.
        } else if (deviceInfo.playbackType == DeviceInfo.PLAYBACK_TYPE_REMOTE) {
          // Add UI changes for remote playback.
        }
      }
    };

@Override
protected void onStart() {
  super.onStart();
  mediaController.addListener(playerListener);
}

@Override
protected void onStop() {
  super.onStop();
  mediaController.removeListener(playerListener);
}

لمزيد من المعلومات حول الاستماع إلى أحداث التشغيل والاستجابة لها، يُرجى الاطّلاع على دليل أحداث المشغّل.