افزودن ویژگی‌های اصلی به گیرنده Android TV

این صفحه حاوی تکه‌کدها و شرح ویژگی‌های دردسترس برای سفارشی‌سازی برنامه «گیرنده Android TV» است.

درحال پیکربندی کتابخانه‌ها

برای دردسترس قرار دادن Cast Connect API برای برنامه Android TV:

Android
  1. فایل build.gradle را در فهرست راهنمای واحد برنامه باز کنید.
  2. تأیید کنید که google() در repositories فهرست‌شده گنجانده شده است.
      repositories {
        google()
      }
  3. بسته به نوع دستگاه هدف برای برنامه‌تان، جدیدترین نسخه‌های کتابخانه‌ها را به وابستگی‌هایتان اضافه کنید:
    • برای برنامه Android Receiver:
        dependencies {
          implementation 'com.google.android.gms:play-services-cast-tv:21.1.1'
          implementation 'com.google.android.gms:play-services-cast:23.0.0'
        }
    • برای برنامه «فرستنده Android»:
        dependencies {
          implementation 'com.google.android.gms:play-services-cast:21.1.1'
          implementation 'com.google.android.gms:play-services-cast-framework:23.0.0'
        }
    حتماً هربار که سرویس‌ها به‌روزرسانی می‌شوند، این شماره نسخه را به‌روز کنید.
  4. تغییرات را ذخیره کنید و روی Sync Project with Gradle Files در نوارابزار کلیک کنید.
iOS
  1. مطمئن شوید Podfile شما google-cast-sdk نسخه ۴.۸.۶ یا بالاتر را هدف قرار می‌دهد
  2. iOS 16 یا بالاتر را هدف قرار دهد. برای جزئیات بیشتر، یادداشت‌های انتشار را ببینید.
      platform: ios, '16'
    
      def target_pods
         pod 'google-cast-sdk', '~>4.8.6'
      end
وب
  1. به مرورگر Chromium نسخه M87 یا بالاتر نیاز دارد.
  2. کتابخانه Web Sender API را به پروژه‌تان اضافه کنید
      <script src="//www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>

الزامات AndroidX

نسخه‌های جدید «خدمات Google Play» مستلزم این است که برنامه برای استفاده از فضای نام androidx به‌روز شده باشد. دستورالعمل‌های انتقال به AndroidX را دنبال کنید.

برنامه Android TV—پیش‌نیازها

برای پشتیبانی از Cast Connect در برنامه Android TV، باید رویدادها را از جلسه رسانه ایجاد و پشتیبانی کنید. داده‌های ارائه‌شده توسط جلسه رسانه شما اطلاعات اولیه (مثلاً موقعیت، وضعیت بازپخش، و غیره) را برای وضعیت رسانه شما ارائه می‌دهد. جلسه رسانه شما همچنین توسط کتابخانه Cast Connect استفاده می‌شود تا زمانی‌که پیام‌های خاصی را از فرستنده دریافت کرده است، مانند مکث، سیگنال دهد.

برای اطلاعات بیشتر درباره جلسه رسانه و نحوه مقداردهی اولیه جلسه رسانه، راهنمای کار با جلسه رسانه را ببینید.

چرخه حیات جلسه رسانه

برنامه شما باید هنگام شروع بازپخش، جلسه رسانه ایجاد کند و وقتی دیگر قابل‌کنترل نیست، آن را رها کند. برای مثال، اگر برنامه‌تان برنامه ویدیو است، باید وقتی کاربر از فعالیت بازپخش خارج می‌شود (با انتخاب «برگشت» برای مرور محتوای دیگر یا با بردن برنامه به پس‌زمینه)، جلسه را رها کنید. اگر برنامه‌تان برنامه موسیقی است، باید وقتی برنامه‌تان دیگر رسانه‌ای پخش نمی‌کند، آن را رها کنید.

درحال به‌روزرسانی وضعیت جلسه

داده‌های موجود در جلسه رسانه شما باید با وضعیت پخش‌کننده شما به‌روز نگه داشته شود. برای مثال، وقتی بازپخش موقتاً متوقف می‌شود، باید وضعیت بازپخش و همچنین کنش‌های پشتیبانی‌شده را به‌روز کنید. جدول‌های زیر نشان می‌دهند که مسئول به‌روز نگه داشتن کدام ایالت‌ها هستید.

MediaMetadataCompat

فیلد فراداده شرح
METADATA_KEY_TITLE (الزامی) عنوان رسانه.
METADATA_KEY_DISPLAY_SUBTITLE زیرنویس.
METADATA_KEY_DISPLAY_ICON_URI نشانی وب نماد.
METADATA_KEY_DURATION (الزامی) مدت‌زمان رسانه.
METADATA_KEY_MEDIA_URI Content ID.
METADATA_KEY_ARTIST هنرمند.
METADATA_KEY_ALBUM آلبوم.

PlaybackStateCompat

روش الزامی شرح
setActions() فرمان‌های رسانه‌ای پشتیبانی‌شده را تنظیم می‌کند.
setState() وضعیت پخش و موقعیت فعلی را تنظیم کنید.

MediaSessionCompat

روش الزامی شرح
setRepeatMode() حالت تکرار را تنظیم می‌کند.
setShuffleMode() حالت پخش درهم را تنظیم می‌کند.
setMetadata() فراداده‌های رسانه را تنظیم می‌کند.
setPlaybackState() وضعیت بازپخش را تنظیم می‌کند.
Kotlin
private fun updateMediaSession() {
    val metadata = MediaMetadataCompat.Builder()
         .putString(MediaMetadataCompat.METADATA_KEY_TITLE, "title")
         .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, "subtitle")
         .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI, mMovie.getCardImageUrl())
         .build()

    val playbackState = PlaybackStateCompat.Builder()
         .setState(
             PlaybackStateCompat.STATE_PLAYING,
             player.getPosition(),
             player.getPlaybackSpeed(),
             System.currentTimeMillis()
        )
         .build()

    mediaSession.setMetadata(metadata)
    mediaSession.setPlaybackState(playbackState)
}
جاوا
private void updateMediaSession() {
  MediaMetadataCompat metadata =
      new MediaMetadataCompat.Builder()
          .putString(MediaMetadataCompat.METADATA_KEY_TITLE, "title")
          .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, "subtitle")
          .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI,mMovie.getCardImageUrl())
          .build();

  PlaybackStateCompat playbackState =
      new PlaybackStateCompat.Builder()
          .setState(
               PlaybackStateCompat.STATE_PLAYING,
               player.getPosition(),
               player.getPlaybackSpeed(),
               System.currentTimeMillis())
          .build();

  mediaSession.setMetadata(metadata);
  mediaSession.setPlaybackState(playbackState);
}

مدیریت کردن کنترل حمل‌ونقل

برنامه شما باید بازخوانی کنترل انتقال جلسه رسانه را پیاده‌سازی کند. جدول زیر نشان می‌دهد که آن‌ها باید به چه کنش‌های کنترل انتقالی رسیدگی کنند:

MediaSessionCompat.Callback

کنش‌ها شرح
onPlay() ازسرگیری
onPause() مکث
onSeekTo() رفتن به موقعیت
onStop()‎ متوقف کردن رسانه فعلی
Kotlin
class MyMediaSessionCallback : MediaSessionCompat.Callback() {
  override fun onPause() {
    // Pause the player and update the play state.
    ...
  }

  override fun onPlay() {
    // Resume the player and update the play state.
    ...
  }

  override fun onSeekTo (long pos) {
    // Seek and update the play state.
    ...
  }
  ...
}

mediaSession.setCallback( MyMediaSessionCallback() );
جاوا
public MyMediaSessionCallback extends MediaSessionCompat.Callback {
  public void onPause() {
    // Pause the player and update the play state.
    ...
  }

  public void onPlay() {
    // Resume the player and update the play state.
    ...
  }

  public void onSeekTo (long pos) {
    // Seek and update the play state.
    ...
  }
  ...
}

mediaSession.setCallback(new MyMediaSessionCallback());

درحال پیکربندی پشتیبانی Cast

وقتی درخواست راه‌اندازی توسط برنامه فرستنده ارسال می‌شود، قصدی با فضای نام برنامه ایجاد می‌شود. برنامه شما مسئول رسیدگی به آن و ایجاد نمونه‌ای از شیء CastReceiverContext هنگام راه‌اندازی برنامه تلویزیون است. شیء CastReceiverContext برای تعامل با Cast درحین اجرای برنامه تلویزیون لازم است. این شیء به برنامه تلویزیون شما امکان می‌دهد پیام‌های رسانه Cast را که از هر فرستنده متصلی می‌آید بپذیرد.

راه‌اندازی Android TV

درحال افزودن فیلتر قصد راه‌اندازی

فیلتر هدف جدیدی به فعالیتی که می‌خواهید هدف راه‌اندازی را از برنامه فرستنده شما مدیریت کند اضافه کنید:

<activity android:name="com.example.activity">
  <intent-filter>
      <action android:name="com.google.android.gms.cast.tv.action.LAUNCH" />
      <category android:name="android.intent.category.DEFAULT" />
  </intent-filter>
</activity>

ارائه‌دهنده گزینه‌های گیرنده را مشخص کنید

باید ReceiverOptionsProvider را پیاده‌سازی کنید تا CastReceiverOptions را ارائه دهید:

Kotlin
class MyReceiverOptionsProvider : ReceiverOptionsProvider {
  override fun getOptions(context: Context?): CastReceiverOptions {
    return CastReceiverOptions.Builder(context)
          .setStatusText("My App")
          .build()
    }
}
جاوا
public class MyReceiverOptionsProvider implements ReceiverOptionsProvider {
  @Override
  public CastReceiverOptions getOptions(Context context) {
    return new CastReceiverOptions.Builder(context)
        .setStatusText("My App")
        .build();
  }
}

سپس ارائه‌دهنده گزینه‌ها را در AndroidManifest مشخص کنید:

 <meta-data
    android:name="com.google.android.gms.cast.tv.RECEIVER_OPTIONS_PROVIDER_CLASS_NAME"
    android:value="com.example.mysimpleatvapplication.MyReceiverOptionsProvider" />

از ReceiverOptionsProvider برای ارائه CastReceiverOptions هنگام مقداردهی اولیه CastReceiverContext استفاده می‌شود.

بافت گیرنده Cast

وقتی برنامه‌تان ایجاد شد، CastReceiverContext را مقداردهی اولیه کنید:

Kotlin
override fun onCreate() {
  CastReceiverContext.initInstance(this)

  ...
}
جاوا
@Override
public void onCreate() {
  CastReceiverContext.initInstance(this);

  ...
}

وقتی برنامه‌تان به پیش‌زمینه منتقل می‌شود، CastReceiverContext را شروع کنید:

Kotlin
CastReceiverContext.getInstance().start()
جاوا
CastReceiverContext.getInstance().start();

برای برنامه‌های ویدیویی یا برنامه‌هایی که از بازپخش پس‌زمینه‌ای پشتیبانی نمی‌کنند، stop() را در CastReceiverContext فراخوانی کنید:

Kotlin
// Player has stopped.
CastReceiverContext.getInstance().stop()
جاوا
// Player has stopped.
CastReceiverContext.getInstance().stop();

علاوه‌براین، اگر برنامه‌تان از پخش در پس‌زمینه پشتیبانی می‌کند، وقتی پخش در پس‌زمینه متوقف می‌شود، stop() را در CastReceiverContext فراخوانی کنید.

اکیداً توصیه می‌کنیم از LifecycleObserver از کتابخانه androidx.lifecycle برای مدیریت تماس CastReceiverContext.start() و CastReceiverContext.stop() استفاده کنید، به‌ویژه اگر برنامه بومی شما چندین فعالیت دارد. این کار از شرایط رقابت هنگام فراخوانی start() و stop() از فعالیت‌های مختلف جلوگیری می‌کند.

Kotlin
// Create a LifecycleObserver class.
class MyLifecycleObserver : DefaultLifecycleObserver {
  override fun onStart(owner: LifecycleOwner) {
    // App prepares to enter foreground.
    CastReceiverContext.getInstance().start()
  }

  override fun onStop(owner: LifecycleOwner) {
    // App has moved to the background or has terminated.
    CastReceiverContext.getInstance().stop()
  }
}

// Add the observer when your application is being created.
class MyApplication : Application() {
  fun onCreate() {
    super.onCreate()

    // Initialize CastReceiverContext.
    CastReceiverContext.initInstance(this /* android.content.Context */)

    // Register LifecycleObserver
    ProcessLifecycleOwner.get().lifecycle.addObserver(
        MyLifecycleObserver())
  }
}
جاوا
// Create a LifecycleObserver class.
public class MyLifecycleObserver implements DefaultLifecycleObserver {
  @Override
  public void onStart(LifecycleOwner owner) {
    // App prepares to enter foreground.
    CastReceiverContext.getInstance().start();
  }

  @Override
  public void onStop(LifecycleOwner owner) {
    // App has moved to the background or has terminated.
    CastReceiverContext.getInstance().stop();
  }
}

// Add the observer when your application is being created.
public class MyApplication extends Application {
  @Override
  public void onCreate() {
    super.onCreate();

    // Initialize CastReceiverContext.
    CastReceiverContext.initInstance(this /* android.content.Context */);

    // Register LifecycleObserver
    ProcessLifecycleOwner.get().getLifecycle().addObserver(
        new MyLifecycleObserver());
  }
}
// In AndroidManifest.xml set MyApplication as the application class
<application
    ...
    android:name=".MyApplication">

متصل کردن MediaSession به MediaManager

وقتی MediaSession ایجاد می‌کنید، باید کد MediaSession فعلی را نیز به CastReceiverContext ارائه دهید تا بداند فرمان‌ها را به کجا ارسال کند و وضعیت بازپخش رسانه را بازیابی کند:

Kotlin
val mediaManager: MediaManager = receiverContext.getMediaManager()
mediaManager.setSessionCompatToken(currentMediaSession.getSessionToken())
جاوا
MediaManager mediaManager = receiverContext.getMediaManager();
mediaManager.setSessionCompatToken(currentMediaSession.getSessionToken());

وقتی MediaSession را به‌دلیل بازپخش غیرفعال منتشر می‌کنید، باید یک نشان پوچ در MediaManager تنظیم کنید:

Kotlin
myPlayer.stop()
mediaSession.release()
mediaManager.setSessionCompatToken(null)
جاوا
myPlayer.stop();
mediaSession.release();
mediaManager.setSessionCompatToken(null);

اگر برنامه‌تان از پخش رسانه درحالی‌که برنامه در پس‌زمینه است پشتیبانی می‌کند، به‌جای فراخوانی CastReceiverContext.stop() وقتی برنامه‌تان به پس‌زمینه ارسال می‌شود، باید آن را فقط زمانی فراخوانی کنید که برنامه‌تان در پس‌زمینه است و دیگر رسانه پخش نمی‌کند. برای مثال:

Kotlin
class MyLifecycleObserver : DefaultLifecycleObserver {
  ...
  // App has moved to the background.
  override fun onPause(owner: LifecycleOwner) {
    mIsBackground = true
    myStopCastReceiverContextIfNeeded()
  }
}

// Stop playback on the player.
private fun myStopPlayback() {
  myPlayer.stop()

  myStopCastReceiverContextIfNeeded()
}

// Stop the CastReceiverContext when both the player has
// stopped and the app has moved to the background.
private fun myStopCastReceiverContextIfNeeded() {
  if (mIsBackground && myPlayer.isStopped()) {
    CastReceiverContext.getInstance().stop()
  }
}
جاوا
public class MyLifecycleObserver implements DefaultLifecycleObserver {
  ...
  // App has moved to the background.
  @Override
  public void onPause(LifecycleOwner owner) {
    mIsBackground = true;

    myStopCastReceiverContextIfNeeded();
  }
}

// Stop playback on the player.
private void myStopPlayback() {
  myPlayer.stop();

  myStopCastReceiverContextIfNeeded();
}

// Stop the CastReceiverContext when both the player has
// stopped and the app has moved to the background.
private void myStopCastReceiverContextIfNeeded() {
  if (mIsBackground && myPlayer.isStopped()) {
    CastReceiverContext.getInstance().stop();
  }
}

استفاده از Exoplayer با Cast Connect

اگر از Exoplayer استفاده می‌کنید، می‌توانید از MediaSessionConnector استفاده کنید تا به‌طور خودکار جلسه و همه اطلاعات مربوطه ازجمله وضعیت بازپخش را به‌جای ردیابی دستی تغییرات حفظ کنید.

MediaSessionConnector.MediaButtonEventHandler می‌تواند برای رسیدگی به رویدادهای MediaButton با فراخوانی setMediaButtonEventHandler(MediaButtonEventHandler) استفاده شود که درغیراین‌صورت به‌طور پیش‌فرض توسط MediaSessionCompat.Callback رسیدگی می‌شود.

برای ادغام کردن MediaSessionConnector در برنامه‌تان، موارد زیر را به کلاس فعالیت پخش‌کننده یا هرجایی که جلسه رسانه‌تان را مدیریت می‌کنید اضافه کنید:

Kotlin
class PlayerActivity : Activity() {
  private var mMediaSession: MediaSessionCompat? = null
  private var mMediaSessionConnector: MediaSessionConnector? = null
  private var mMediaManager: MediaManager? = null

  override fun onCreate(savedInstanceState: Bundle?) {
    ...
    mMediaSession = MediaSessionCompat(this, LOG_TAG)
    mMediaSessionConnector = MediaSessionConnector(mMediaSession!!)
    ...
  }

  override fun onStart() {
    ...
    mMediaManager = receiverContext.getMediaManager()
    mMediaManager!!.setSessionCompatToken(currentMediaSession.getSessionToken())
    mMediaSessionConnector!!.setPlayer(mExoPlayer)
    mMediaSessionConnector!!.setMediaMetadataProvider(mMediaMetadataProvider)
    mMediaSession!!.isActive = true
    ...
  }

  override fun onStop() {
    ...
    mMediaSessionConnector!!.setPlayer(null)
    mMediaSession!!.release()
    mMediaManager!!.setSessionCompatToken(null)
    ...
  }
}
جاوا
public class PlayerActivity extends Activity {
  private MediaSessionCompat mMediaSession;
  private MediaSessionConnector mMediaSessionConnector;
  private MediaManager mMediaManager;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    ...
    mMediaSession = new MediaSessionCompat(this, LOG_TAG);
    mMediaSessionConnector = new MediaSessionConnector(mMediaSession);
    ...
  }

  @Override
  protected void onStart() {
    ...
    mMediaManager = receiverContext.getMediaManager();
    mMediaManager.setSessionCompatToken(currentMediaSession.getSessionToken());

    mMediaSessionConnector.setPlayer(mExoPlayer);
    mMediaSessionConnector.setMediaMetadataProvider(mMediaMetadataProvider);
    mMediaSession.setActive(true);
    ...
  }

  @Override
  protected void onStop() {
    ...
    mMediaSessionConnector.setPlayer(null);
    mMediaSession.release();
    mMediaManager.setSessionCompatToken(null);
    ...
  }
}

راه‌اندازی برنامه فرستنده

فعال کردن پشتیبانی از Cast Connect

پس‌از به‌روزرسانی برنامه فرستنده با پشتیبانی Cast Connect، می‌توانید با تنظیم پرچم androidReceiverCompatible روی LaunchOptions به‌صورت true، آمادگی آن را اعلام کنید.

Android

به نسخه play-services-cast-framework 19.0.0 یا بالاتر نیاز دارد.

پرچم androidReceiverCompatible در LaunchOptions (که بخشی از CastOptions است) تنظیم شده است:

Kotlin
class CastOptionsProvider : OptionsProvider {
  override fun getCastOptions(context: Context?): CastOptions {
    val launchOptions: LaunchOptions = Builder()
          .setAndroidReceiverCompatible(true)
          .build()
    return CastOptions.Builder()
          .setLaunchOptions(launchOptions)
          ...
          .build()
    }
}
جاوا
public class CastOptionsProvider implements OptionsProvider {
  @Override
  public CastOptions getCastOptions(Context context) {
    LaunchOptions launchOptions = new LaunchOptions.Builder()
              .setAndroidReceiverCompatible(true)
              .build();
    return new CastOptions.Builder()
        .setLaunchOptions(launchOptions)
        ...
        .build();
  }
}
iOS

به google-cast-sdk نسخه v4.4.8 یا بالاتر نیاز دارد.

پرچم androidReceiverCompatible در GCKLaunchOptions (که بخشی از GCKCastOptions است) تنظیم شده است:

let options = GCKCastOptions(discoveryCriteria: GCKDiscoveryCriteria(applicationID: kReceiverAppID))
...
let launchOptions = GCKLaunchOptions()
launchOptions.androidReceiverCompatible = true
options.launchOptions = launchOptions
GCKCastContext.setSharedInstanceWith(options)
وب

به مرورگر Chromium نسخه M87 یا بالاتر نیاز دارد.

const context = cast.framework.CastContext.getInstance();
const castOptions = new cast.framework.CastOptions();
castOptions.receiverApplicationId = kReceiverAppID;
castOptions.androidReceiverCompatible = true;
context.setOptions(castOptions);

راه‌اندازی «کنسول توسعه‌دهندگان Cast»

پیکربندی برنامه Android TV

نام بسته برنامه Android TV خود را در کنسول توسعه‌دهنده Cast اضافه کنید تا آن را با شناسه برنامه Cast خود مرتبط کنید.

ثبت دستگاه‌های توسعه‌دهنده

شماره سریال دستگاه Android TV را که می‌خواهید برای توسعه استفاده کنید در کنسول توسعه‌دهنده Cast ثبت کنید.

بدون ثبت، Cast Connect به‌دلایل امنیتی فقط برای برنامه‌های نصب‌شده از «فروشگاه Google Play» کار خواهد کرد.

برای اطلاعات بیشتر درباره ثبت دستگاه Cast یا Android TV برای توسعه Cast، به صفحه ثبت‌نام مراجعه کنید.

درحال بار کردن رسانه

اگر قبلاً پشتیبانی از پیوند عمیق را در برنامه Android TV خود پیاده‌سازی کرده‌اید، باید تعریف مشابهی را در مانیفست Android TV خود پیکربندی کرده باشید:

<activity android:name="com.example.activity">
  <intent-filter>
     <action android:name="android.intent.action.VIEW" />
     <category android:name="android.intent.category.DEFAULT" />
     <data android:scheme="https"/>
     <data android:host="www.example.com"/>
     <data android:pathPattern=".*"/>
  </intent-filter>
</activity>

بار کردن براساس نهاد در فرستنده

در فرستنده‌ها، می‌توانید با تنظیم entity در اطلاعات رسانه برای درخواست بارگیری، پیوند عمیق را ارسال کنید:

Kotlin
val mediaToLoad = MediaInfo.Builder("some-id")
    .setEntity("https://example.com/watch/some-id")
    ...
    .build()
val loadRequest = MediaLoadRequestData.Builder()
    .setMediaInfo(mediaToLoad)
    .setCredentials("user-credentials")
    ...
    .build()
remoteMediaClient.load(loadRequest)
Android
جاوا
MediaInfo mediaToLoad =
    new MediaInfo.Builder("some-id")
        .setEntity("https://example.com/watch/some-id")
        ...
        .build();
MediaLoadRequestData loadRequest =
    new MediaLoadRequestData.Builder()
        .setMediaInfo(mediaToLoad)
        .setCredentials("user-credentials")
        ...
        .build();
remoteMediaClient.load(loadRequest);
iOS
let mediaInfoBuilder = GCKMediaInformationBuilder(entity: "https://example.com/watch/some-id")
...
mediaInformation = mediaInfoBuilder.build()

let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder()
mediaLoadRequestDataBuilder.mediaInformation = mediaInformation
mediaLoadRequestDataBuilder.credentials = "user-credentials"
...
let mediaLoadRequestData = mediaLoadRequestDataBuilder.build()

remoteMediaClient?.loadMedia(with: mediaLoadRequestData)
وب

به مرورگر Chromium نسخه M87 یا بالاتر نیاز دارد.

let mediaInfo = new chrome.cast.media.MediaInfo('some-id"', 'video/mp4');
mediaInfo.entity = 'https://example.com/watch/some-id';
...

let request = new chrome.cast.media.LoadRequest(mediaInfo);
request.credentials = 'user-credentials';
...

cast.framework.CastContext.getInstance().getCurrentSession().loadMedia(request);

فرمان بارگیری ازطریق یک هدف با پیوند عمیق شما و نام بسته که در کنسول توسعه‌دهنده تعریف کرده‌اید ارسال می‌شود.

تنظیم اطلاعات کاربری ATV در فرستنده

ممکن است برنامه «گیرنده وب» و برنامه Android TV شما از پیوندهای عمیق و credentials متفاوتی پشتیبانی کنند (برای مثال اگر اصالت‌سنجی را در دو پلاتفرم به‌طور متفاوتی انجام می‌دهید). برای رفع این مشکل، می‌توانید entity و credentials جایگزین برای Android TV ارائه دهید:

Android
Kotlin
val mediaToLoad = MediaInfo.Builder("some-id")
        .setEntity("https://example.com/watch/some-id")
        .setAtvEntity("myscheme://example.com/atv/some-id")
        ...
        .build()
val loadRequest = MediaLoadRequestData.Builder()
        .setMediaInfo(mediaToLoad)
        .setCredentials("user-credentials")
        .setAtvCredentials("atv-user-credentials")
        ...
        .build()
remoteMediaClient.load(loadRequest)
جاوا
MediaInfo mediaToLoad =
    new MediaInfo.Builder("some-id")
        .setEntity("https://example.com/watch/some-id")
        .setAtvEntity("myscheme://example.com/atv/some-id")
        ...
        .build();
MediaLoadRequestData loadRequest =
    new MediaLoadRequestData.Builder()
        .setMediaInfo(mediaToLoad)
        .setCredentials("user-credentials")
        .setAtvCredentials("atv-user-credentials")
        ...
        .build();
remoteMediaClient.load(loadRequest);
iOS
let mediaInfoBuilder = GCKMediaInformationBuilder(entity: "https://example.com/watch/some-id")
mediaInfoBuilder.atvEntity = "myscheme://example.com/atv/some-id"
...
mediaInformation = mediaInfoBuilder.build()

let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder()
mediaLoadRequestDataBuilder.mediaInformation = mediaInformation
mediaLoadRequestDataBuilder.credentials = "user-credentials"
mediaLoadRequestDataBuilder.atvCredentials = "atv-user-credentials"
...
let mediaLoadRequestData = mediaLoadRequestDataBuilder.build()

remoteMediaClient?.loadMedia(with: mediaLoadRequestData)
وب

به مرورگر Chromium نسخه M87 یا بالاتر نیاز دارد.

let mediaInfo = new chrome.cast.media.MediaInfo('some-id"', 'video/mp4');
mediaInfo.entity = 'https://example.com/watch/some-id';
mediaInfo.atvEntity = 'myscheme://example.com/atv/some-id';
...

let request = new chrome.cast.media.LoadRequest(mediaInfo);
request.credentials = 'user-credentials';
request.atvCredentials = 'atv-user-credentials';
...

cast.framework.CastContext.getInstance().getCurrentSession().loadMedia(request);

اگر برنامه «گیرنده وب» راه‌اندازی شود، از entity و credentials در درخواست بارگیری استفاده می‌کند. اما اگر برنامه Android TV شما راه‌اندازی شود، کیت توسعه نرم‌افزار entity و credentials را با atvEntity و atvCredentials شما (درصورت مشخص شدن) لغو می‌کند.

بار کردن با Content ID یا MediaQueueData

اگر از entity یا atvEntity استفاده نمی‌کنید و از Content ID یا نشانی وب محتوا در «اطلاعات رسانه» خود استفاده می‌کنید یا از «داده‌های درخواست بارگیری رسانه» با جزئیات بیشتر استفاده می‌کنید، باید فیلتر قصد ازپیش تعریف‌شده زیر را در برنامه Android TV خود اضافه کنید:

<activity android:name="com.example.activity">
  <intent-filter>
     <action android:name="com.google.android.gms.cast.tv.action.LOAD"/>
     <category android:name="android.intent.category.DEFAULT" />
  </intent-filter>
</activity>

در سمت فرستنده، مشابه بار کردن براساس نهاد، می‌توانید درخواست بار کردن با اطلاعات محتوایتان ایجاد کنید و load() را فراخوانی کنید.

Android
Kotlin
val mediaToLoad = MediaInfo.Builder("some-id").build()
val loadRequest = MediaLoadRequestData.Builder()
    .setMediaInfo(mediaToLoad)
    .setCredentials("user-credentials")
    ...
    .build()
remoteMediaClient.load(loadRequest)
جاوا
MediaInfo mediaToLoad =
    new MediaInfo.Builder("some-id").build();
MediaLoadRequestData loadRequest =
    new MediaLoadRequestData.Builder()
        .setMediaInfo(mediaToLoad)
        .setCredentials("user-credentials")
        ...
        .build();
remoteMediaClient.load(loadRequest);
iOS
let mediaInfoBuilder = GCKMediaInformationBuilder(contentId: "some-id")
...
mediaInformation = mediaInfoBuilder.build()

let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder()
mediaLoadRequestDataBuilder.mediaInformation = mediaInformation
mediaLoadRequestDataBuilder.credentials = "user-credentials"
...
let mediaLoadRequestData = mediaLoadRequestDataBuilder.build()

remoteMediaClient?.loadMedia(with: mediaLoadRequestData)
وب

به مرورگر Chromium نسخه M87 یا بالاتر نیاز دارد.

let mediaInfo = new chrome.cast.media.MediaInfo('some-id"', 'video/mp4');
...

let request = new chrome.cast.media.LoadRequest(mediaInfo);
...

cast.framework.CastContext.getInstance().getCurrentSession().loadMedia(request);

رسیدگی به درخواست‌های بارگیری

در فعالیتتان، برای رسیدگی به این درخواست‌های بارگیری، باید به هدف‌ها در فراخوانی‌های چرخه حیات فعالیتتان رسیدگی کنید:

Kotlin
class MyActivity : Activity() {
  override fun onStart() {
    super.onStart()
    val mediaManager = CastReceiverContext.getInstance().getMediaManager()
    // Pass the intent to the SDK. You can also do this in onCreate().
    if (mediaManager.onNewIntent(intent)) {
        // If the SDK recognizes the intent, you should early return.
        return
    }
    // If the SDK doesn't recognize the intent, you can handle the intent with
    // your own logic.
    ...
  }

  // For some cases, a new load intent triggers onNewIntent() instead of
  // onStart().
  override fun onNewIntent(intent: Intent) {
    val mediaManager = CastReceiverContext.getInstance().getMediaManager()
    // Pass the intent to the SDK. You can also do this in onCreate().
    if (mediaManager.onNewIntent(intent)) {
        // If the SDK recognizes the intent, you should early return.
        return
    }
    // If the SDK doesn't recognize the intent, you can handle the intent with
    // your own logic.
    ...
  }
}
جاوا
public class MyActivity extends Activity {
  @Override
  protected void onStart() {
    super.onStart();
    MediaManager mediaManager =
        CastReceiverContext.getInstance().getMediaManager();
    // Pass the intent to the SDK. You can also do this in onCreate().
    if (mediaManager.onNewIntent(getIntent())) {
      // If the SDK recognizes the intent, you should early return.
      return;
    }
    // If the SDK doesn't recognize the intent, you can handle the intent with
    // your own logic.
    ...
  }

  // For some cases, a new load intent triggers onNewIntent() instead of
  // onStart().
  @Override
  protected void onNewIntent(Intent intent) {
    MediaManager mediaManager =
        CastReceiverContext.getInstance().getMediaManager();
    // Pass the intent to the SDK. You can also do this in onCreate().
    if (mediaManager.onNewIntent(intent)) {
      // If the SDK recognizes the intent, you should early return.
      return;
    }
    // If the SDK doesn't recognize the intent, you can handle the intent with
    // your own logic.
    ...
  }
}

اگر MediaManager تشخیص دهد که هدف از نوع هدف بارگیری است، یک شیء MediaLoadRequestData را از هدف استخراج می‌کند و MediaLoadCommandCallback.onLoad() را فراخوانی می‌کند. برای رسیدگی به درخواست بارگیری، باید این روش را لغو کنید. فراخوانی برگشتی باید قبل‌از فراخوانی MediaManager.onNewIntent() ثبت شود (توصیه می‌شود در روش «فعالیت» یا «برنامه» onCreate() باشد).

Kotlin
class MyActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val mediaManager = CastReceiverContext.getInstance().getMediaManager()
        mediaManager.setMediaLoadCommandCallback(MyMediaLoadCommandCallback())
    }
}

class MyMediaLoadCommandCallback : MediaLoadCommandCallback() {
  override fun onLoad(
        senderId: String?,
        loadRequestData: MediaLoadRequestData
  ): Task {
      return Tasks.call {
        // Resolve the entity into your data structure and load media.
        val mediaInfo = loadRequestData.getMediaInfo()
        if (!checkMediaInfoSupported(mediaInfo)) {
            // Throw MediaException to indicate load failure.
            throw MediaException(
                MediaError.Builder()
                    .setDetailedErrorCode(DetailedErrorCode.LOAD_FAILED)
                    .setReason(MediaError.ERROR_REASON_INVALID_REQUEST)
                    .build()
            )
        }
        myFillMediaInfo(MediaInfoWriter(mediaInfo))
        myPlayerLoad(mediaInfo.getContentUrl())

        // Update media metadata and state (this clears all previous status
        // overrides).
        castReceiverContext.getMediaManager()
            .setDataFromLoad(loadRequestData)
        ...
        castReceiverContext.getMediaManager().broadcastMediaStatus()

        // Return the resolved MediaLoadRequestData to indicate load success.
        return loadRequestData
     }
  }

  private fun myPlayerLoad(contentURL: String) {
    myPlayer.load(contentURL)

    // Update the MediaSession state.
    val playbackState: PlaybackStateCompat = Builder()
        .setState(
            player.getState(), player.getPosition(), System.currentTimeMillis()
        )
        ...
        .build()
    mediaSession.setPlaybackState(playbackState)
  }
جاوا
public class MyActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    MediaManager mediaManager =
        CastReceiverContext.getInstance().getMediaManager();
    mediaManager.setMediaLoadCommandCallback(new MyMediaLoadCommandCallback());
  }
}

public class MyMediaLoadCommandCallback extends MediaLoadCommandCallback {
  @Override
  public Task onLoad(String senderId, MediaLoadRequestData loadRequestData) {
    return Tasks.call(() -> {
        // Resolve the entity into your data structure and load media.
        MediaInfo mediaInfo = loadRequestData.getMediaInfo();
        if (!checkMediaInfoSupported(mediaInfo)) {
          // Throw MediaException to indicate load failure.
          throw new MediaException(
              new MediaError.Builder()
                  .setDetailedErrorCode(DetailedErrorCode.LOAD_FAILED)
                  .setReason(MediaError.ERROR_REASON_INVALID_REQUEST)
                  .build());
        }
        myFillMediaInfo(new MediaInfoWriter(mediaInfo));
        myPlayerLoad(mediaInfo.getContentUrl());

        // Update media metadata and state (this clears all previous status
        // overrides).
        castReceiverContext.getMediaManager()
            .setDataFromLoad(loadRequestData);
        ...
        castReceiverContext.getMediaManager().broadcastMediaStatus();

        // Return the resolved MediaLoadRequestData to indicate load success.
        return loadRequestData;
    });
}

private void myPlayerLoad(String contentURL) {
  myPlayer.load(contentURL);

  // Update the MediaSession state.
  PlaybackStateCompat playbackState =
      new PlaybackStateCompat.Builder()
          .setState(
              player.getState(), player.getPosition(), System.currentTimeMillis())
          ...
          .build();
  mediaSession.setPlaybackState(playbackState);
}

برای پردازش قصد بار کردن، می‌توانید قصد را به ساختارهای داده‌ای که تعریف کردیم تجزیه کنید (MediaLoadRequestData برای درخواست‌های بار کردن).

از فرمان‌های رسانه پشتیبانی می‌کند

پشتیبانی از کنترل بازپخش پایه

فرمان‌های ادغام پایه شامل فرمان‌هایی است که با جلسه رسانه سازگار است. این فرمان‌ها ازطریق فراخوانی‌های برگشتی جلسه رسانه اطلاع داده می‌شوند. برای پشتیبانی از این ویژگی، باید یک فراخوانی برگشتی به جلسه رسانه ثبت کنید (ممکن است قبلاً این کار را انجام داده باشید).

Kotlin
private class MyMediaSessionCallback : MediaSessionCompat.Callback() {
  override fun onPause() {
    // Pause the player and update the play state.
    myPlayer.pause()
  }

  override fun onPlay() {
    // Resume the player and update the play state.
    myPlayer.play()
  }

  override fun onSeekTo(pos: Long) {
    // Seek and update the play state.
    myPlayer.seekTo(pos)
  }
    ...
 }

mediaSession.setCallback(MyMediaSessionCallback())
جاوا
private class MyMediaSessionCallback extends MediaSessionCompat.Callback {
  @Override
  public void onPause() {
    // Pause the player and update the play state.
    myPlayer.pause();
  }
  @Override
  public void onPlay() {
    // Resume the player and update the play state.
    myPlayer.play();
  }
  @Override
  public void onSeekTo(long pos) {
    // Seek and update the play state.
    myPlayer.seekTo(pos);
  }

  ...
}

mediaSession.setCallback(new MyMediaSessionCallback());

پشتیبانی از فرمان‌های کنترل «پخش محتوا»

برخی‌از فرمان‌های «ارسال محتوا» در MediaSession دردسترس نیستند، مثل skipAd() یا setActiveMediaTracks(). همچنین، برخی‌از فرمان‌های صف باید در اینجا پیاده‌سازی شوند زیرا صف Cast کاملاً با صف MediaSession سازگار نیست.

Kotlin
class MyMediaCommandCallback : MediaCommandCallback() {
    override fun onSkipAd(requestData: RequestData?): Task<Void?> {
        // Skip your ad
        ...
        return Tasks.forResult(null)
    }
}

val mediaManager = CastReceiverContext.getInstance().getMediaManager()
mediaManager.setMediaCommandCallback(MyMediaCommandCallback())
جاوا
public class MyMediaCommandCallback extends MediaCommandCallback {
  @Override
  public Task onSkipAd(RequestData requestData) {
    // Skip your ad
    ...
    return Tasks.forResult(null);
  }
}

MediaManager mediaManager =
    CastReceiverContext.getInstance().getMediaManager();
mediaManager.setMediaCommandCallback(new MyMediaCommandCallback());

فرمان‌های رسانه‌ای پشتیبانی‌شده را مشخص کنید

همانند گیرنده Cast، برنامه Android TV شما باید مشخص کند کدام فرمان‌ها پشتیبانی می‌شوند تا فرستنده‌ها بتوانند برخی‌از کنترل‌های میانای کاربر را فعال یا غیرفعال کنند. برای فرمان‌هایی که بخشی از MediaSession هستند، فرمان‌ها را در PlaybackStateCompat مشخص کنید. فرمان‌های اضافی باید در MediaStatusModifier مشخص شود.

Kotlin
// Set media session supported commands
val playbackState: PlaybackStateCompat = PlaybackStateCompat.Builder()
    .setActions(PlaybackStateCompat.ACTION_PLAY or PlaybackStateCompat.ACTION_PAUSE)
    .setState(PlaybackStateCompat.STATE_PLAYING)
    .build()

mediaSession.setPlaybackState(playbackState)

// Set additional commands in MediaStatusModifier
val mediaManager = CastReceiverContext.getInstance().getMediaManager()
mediaManager.getMediaStatusModifier()
    .setMediaCommandSupported(MediaStatus.COMMAND_QUEUE_NEXT)
جاوا
// Set media session supported commands
PlaybackStateCompat playbackState =
    new PlaybackStateCompat.Builder()
        .setActions(PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE)
        .setState(PlaybackStateCompat.STATE_PLAYING)
        .build();

mediaSession.setPlaybackState(playbackState);

// Set additional commands in MediaStatusModifier
MediaManager mediaManager = CastReceiverContext.getInstance().getMediaManager();
mediaManager.getMediaStatusModifier()
            .setMediaCommandSupported(MediaStatus.COMMAND_QUEUE_NEXT);

پنهان کردن دکمه‌های پشتیبانی‌نشده

اگر برنامه Android TV شما فقط از کنترل رسانه پایه پشتیبانی می‌کند اما برنامه «گیرنده وب» شما از کنترل پیشرفته‌تر پشتیبانی می‌کند، باید مطمئن شوید که برنامه فرستنده شما هنگام ارسال محتوا به برنامه Android TV به‌درستی رفتار می‌کند. برای مثال، اگر برنامه Android TV شما از تغییر نرخ بازپخش پشتیبانی نمی‌کند اما برنامه «گیرنده وب» شما پشتیبانی می‌کند، باید کنش‌های پشتیبانی‌شده را به‌درستی در هر پلاتفرم تنظیم کنید و مطمئن شوید که برنامه فرستنده شما واسط کاربر را به‌درستی ارائه می‌کند.

درحال اصلاح MediaStatus

برای پشتیبانی از ویژگی‌های پیشرفته مانند قطعه‌ها، آگهی‌ها، پخش زنده، و صف‌بندی، برنامه Android TV شما باید اطلاعات بیشتری ارائه دهد که نمی‌توان ازطریق MediaSession به آن‌ها دست یافت.

ما کلاس MediaStatusModifier را برای شما فراهم می‌کنیم تا به این هدف برسید. MediaStatusModifier همیشه روی MediaSession که در CastReceiverContext تنظیم کرده‌اید کار خواهد کرد.

برای ایجاد و همه‌فرستی MediaStatus:

Kotlin
val mediaManager: MediaManager = castReceiverContext.getMediaManager()
val statusModifier: MediaStatusModifier = mediaManager.getMediaStatusModifier()

statusModifier
    .setLiveSeekableRange(seekableRange)
    .setAdBreakStatus(adBreakStatus)
    .setCustomData(customData)

mediaManager.broadcastMediaStatus()
جاوا
MediaManager mediaManager = castReceiverContext.getMediaManager();
MediaStatusModifier statusModifier = mediaManager.getMediaStatusModifier();

statusModifier
    .setLiveSeekableRange(seekableRange)
    .setAdBreakStatus(adBreakStatus)
    .setCustomData(customData);

mediaManager.broadcastMediaStatus();

کتابخانه مشتری ما MediaStatus پایه را از MediaSession دریافت خواهد کرد، برنامه Android TV شما می‌تواند وضعیت اضافی را مشخص کند و وضعیت را ازطریق اصلاح‌کننده MediaStatus لغو کند.

برخی‌از حالت‌ها و فراداده‌ها را می‌توان هم در MediaSession و هم در MediaStatusModifier تنظیم کرد. اکیداً توصیه می‌کنیم آن‌ها را فقط در MediaSession تنظیم کنید. همچنان می‌توانید از اصلاح‌کننده برای لغو کردن وضعیت‌ها در MediaSession استفاده کنید—این کار توصیه نمی‌شود زیرا وضعیت در اصلاح‌کننده همیشه اولویت بالاتری نسبت به مقادیر ارائه‌شده توسط MediaSession دارد.

رهگیری MediaStatus قبل‌از ارسال

همانند SDK گیرنده وب، اگر می‌خواهید قبل‌از ارسال، کارهای نهایی را انجام دهید، می‌توانید یک MediaStatusInterceptor را برای پردازش MediaStatus که قرار است ارسال شود، مشخص کنید. ما یک MediaStatusWriter را وارد می‌کنیم تا MediaStatus را قبل‌از ارسال دستکاری کنیم.

Kotlin
mediaManager.setMediaStatusInterceptor(object : MediaStatusInterceptor {
    override fun intercept(mediaStatusWriter: MediaStatusWriter) {
      // Perform customization.
        mediaStatusWriter.setCustomData(JSONObject("{data: \"my Hello\"}"))
    }
})
جاوا
mediaManager.setMediaStatusInterceptor(new MediaStatusInterceptor() {
    @Override
    public void intercept(MediaStatusWriter mediaStatusWriter) {
        // Perform customization.
        mediaStatusWriter.setCustomData(new JSONObject("{data: \"my Hello\"}"));
    }
});

مدیریت اطلاعات اعتباری کاربر

ممکن است برنامه Android TV شما فقط به کاربران خاصی اجازه دهد جلسه برنامه را راه‌اندازی کنند یا به آن بپیوندند. برای مثال، فقط در شرایط زیر به فرستنده اجازه راه‌اندازی یا پیوستن داده شود:

  • برنامه فرستنده به همان حساب و نمایه‌ای وارد شده است که برنامه ATV وارد شده است.
  • برنامه فرستنده به همان حساب وارد شده است، اما نمایه آن با برنامه ATV متفاوت است.

اگر برنامه‌تان می‌تواند چندین کاربر یا کاربر ناشناس را مدیریت کند، می‌توانید به هر کاربر دیگری اجازه دهید به جلسه ATV بپیوندد. اگر کاربر اطلاعات کاربری ارائه دهد، برنامه ATV شما باید اطلاعات کاربری او را مدیریت کند تا پیشرفت او و سایر داده‌های کاربر بتواند به‌درستی ردیابی شود.

وقتی برنامه فرستنده شما برنامه Android TV شما را راه‌اندازی می‌کند یا به آن می‌پیوندد، برنامه فرستنده شما باید اعتبارنامه‌ای را ارائه دهد که نشان‌دهنده فردی است که به جلسه می‌پیوندد.

قبل‌از اینکه فرستنده برنامه Android TV شما را راه‌اندازی کند و به آن بپیوندد، می‌توانید بررسی‌کننده راه‌اندازی را مشخص کنید تا ببینید آیا اطلاعات کاربری فرستنده مجاز است یا نه. اگر این‌طور نباشد، Cast Connect SDK به راه‌اندازی «گیرنده وب» شما برمی‌گردد.

داده‌های اعتبارنامه راه‌اندازی برنامه فرستنده

در سمت فرستنده، می‌توانید CredentialsData را برای نشان دادن فردی که به جلسه می‌پیوندد مشخص کنید.

credentials رشته‌ای است که می‌تواند توسط کاربر تعریف شود، به‌شرطی که برنامه ATV شما بتواند آن را درک کند. credentialsType مشخص می‌کند که CredentialsData از کدام پلاتفرم می‌آید یا می‌تواند مقدار سفارشی باشد. به‌طور پیش‌فرض روی پلاتفرمی تنظیم شده است که از آن ارسال می‌شود.

CredentialsData فقط درطول زمان راه‌اندازی یا پیوستن به برنامه Android TV شما ارسال می‌شود. اگر دوباره آن را درحین اتصال تنظیم کنید، به برنامه Android TV شما منتقل نخواهد شد. اگر فرستنده شما درحین اتصال نمایه را تغییر دهد، می‌توانید در جلسه بمانید یا اگر فکر می‌کنید نمایه جدید با جلسه ناسازگار است، SessionManager.endCurrentCastSession(boolean stopCasting) را فراخوانی کنید.

CredentialsData برای هر فرستنده را می‌توان بااستفاده از getSenders در CastReceiverContext برای دریافت SenderInfo، getCastLaunchRequest() برای دریافت CastLaunchRequest، و سپس getCredentialsData() بازیابی کرد.

Android

به نسخه play-services-cast-framework 19.0.0 یا بالاتر نیاز دارد.

Kotlin
CastContext.getSharedInstance().setLaunchCredentialsData(
    CredentialsData.Builder()
        .setCredentials("{\"userId\": \"abc\"}")
        .build()
)
جاوا
CastContext.getSharedInstance().setLaunchCredentialsData(
    new CredentialsData.Builder()
        .setCredentials("{\"userId\": \"abc\"}")
        .build());
iOS

به google-cast-sdk نسخه v4.8.6 یا بالاتر نیاز دارد.

هرزمان پس‌از تنظیم گزینه‌ها می‌توان آن را فراخوانی کرد: GCKCastContext.setSharedInstanceWith(options).

GCKCastContext.sharedInstance().setLaunch(
    GCKCredentialsData(credentials: "{\"userId\": \"abc\"}")
وب

به مرورگر Chromium نسخه M87 یا بالاتر نیاز دارد.

هرزمان پس‌از تنظیم گزینه‌ها می‌توان آن را فراخوانی کرد: cast.framework.CastContext.getInstance().setOptions(options);.

let credentialsData =
    new chrome.cast.CredentialsData("{\"userId\": \"abc\"}");
cast.framework.CastContext.getInstance().setLaunchCredentialsData(credentialsData);

پیاده‌سازی بررسی‌کننده درخواست راه‌اندازی ATV

وقتی فرستنده‌ای تلاش می‌کند راه‌اندازی کند یا بپیوندد، CredentialsData به برنامه Android TV شما ارسال می‌شود. می‌توانید LaunchRequestChecker را پیاده‌سازی کنید. را برای مجاز کردن یا رد کردن این درخواست انتخاب کنید.

اگر درخواستی رد شود، «گیرنده وب» به‌جای راه‌اندازی بومی در برنامه ATV بار می‌شود. اگر ATV شما نمی‌تواند درخواست کاربر برای راه‌اندازی یا پیوستن را مدیریت کند، باید درخواست را رد کنید. برای مثال، ممکن است کاربر دیگری غیراز کاربر درخواست‌کننده به سیستم برنامه ATV وارد شده باشد و برنامه شما نتواند اطلاعات کاربری را عوض کند، یا درحال‌حاضر کاربری به سیستم برنامه ATV وارد نشده باشد.

اگر درخواست مجاز باشد، برنامه ATV راه‌اندازی می‌شود. می‌توانید این رفتار را بسته به اینکه برنامه‌تان از ارسال درخواست‌های بارگیری در زمانی که کاربر به سیستم برنامه ATV وارد نشده است پشتیبانی می‌کند یا اینکه عدم تطابق کاربر وجود دارد، سفارشی‌سازی کنید. این رفتار در LaunchRequestChecker کاملاً قابل‌سفارشی‌سازی است.

کلاسی ایجاد کنید که واسط CastReceiverOptions.LaunchRequestChecker را پیاده‌سازی کند:

Kotlin
class MyLaunchRequestChecker : LaunchRequestChecker {
  override fun checkLaunchRequestSupported(launchRequest: CastLaunchRequest): Task {
    return Tasks.call {
      myCheckLaunchRequest(
           launchRequest
      )
    }
  }
}

private fun myCheckLaunchRequest(launchRequest: CastLaunchRequest): Boolean {
  val credentialsData = launchRequest.getCredentialsData()
     ?: return false // or true if you allow anonymous users to join.

  // The request comes from a mobile device, e.g. checking user match.
  return if (credentialsData.credentialsType == CredentialsData.CREDENTIALS_TYPE_ANDROID) {
     myCheckMobileCredentialsAllowed(credentialsData.getCredentials())
  } else false // Unrecognized credentials type.
}
جاوا
public class MyLaunchRequestChecker
    implements CastReceiverOptions.LaunchRequestChecker {
  @Override
  public Task checkLaunchRequestSupported(CastLaunchRequest launchRequest) {
    return Tasks.call(() -> myCheckLaunchRequest(launchRequest));
  }
}

private boolean myCheckLaunchRequest(CastLaunchRequest launchRequest) {
  CredentialsData credentialsData = launchRequest.getCredentialsData();
  if (credentialsData == null) {
    return false;  // or true if you allow anonymous users to join.
  }

  // The request comes from a mobile device, e.g. checking user match.
  if (credentialsData.getCredentialsType().equals(CredentialsData.CREDENTIALS_TYPE_ANDROID)) {
    return myCheckMobileCredentialsAllowed(credentialsData.getCredentials());
  }

  // Unrecognized credentials type.
  return false;
}

سپس آن را در ReceiverOptionsProvider تنظیم کنید:

Kotlin
class MyReceiverOptionsProvider : ReceiverOptionsProvider {
  override fun getOptions(context: Context?): CastReceiverOptions {
    return CastReceiverOptions.Builder(context)
        ...
        .setLaunchRequestChecker(MyLaunchRequestChecker())
        .build()
  }
}
جاوا
public class MyReceiverOptionsProvider implements ReceiverOptionsProvider {
  @Override
  public CastReceiverOptions getOptions(Context context) {
    return new CastReceiverOptions.Builder(context)
        ...
        .setLaunchRequestChecker(new MyLaunchRequestChecker())
        .build();
  }
}

حل کردن true در LaunchRequestChecker برنامه ATV را راه‌اندازی می‌کند و false برنامه «گیرنده وب» شما را راه‌اندازی می‌کند.

ارسال و دریافت پیام‌های سفارشی

پروتکل Cast به شما امکان می‌دهد پیام‌های رشته‌ای سفارشی را بین فرستندگان و برنامه گیرنده خود ارسال کنید. برای ارسال پیام در سراسر CastReceiverContext، باید قبل‌از مقداردهی اولیه آن، یک فضای نام (کانال) ثبت کنید.

Android TV—Specify Custom Namespace

باید جای‌نام‌های پشتیبانی‌شده‌تان را در CastReceiverOptions درطول راه‌اندازی مشخص کنید:

Kotlin
class MyReceiverOptionsProvider : ReceiverOptionsProvider {
  override fun getOptions(context: Context?): CastReceiverOptions {
    return CastReceiverOptions.Builder(context)
        .setCustomNamespaces(
            Arrays.asList("urn:x-cast:com.example.cast.mynamespace")
        )
        .build()
  }
}
جاوا
public class MyReceiverOptionsProvider implements ReceiverOptionsProvider {
  @Override
  public CastReceiverOptions getOptions(Context context) {
    return new CastReceiverOptions.Builder(context)
        .setCustomNamespaces(
              Arrays.asList("urn:x-cast:com.example.cast.mynamespace"))
        .build();
  }
}

Android TV—Sending Messages

Kotlin
// If senderId is null, then the message is broadcasted to all senders.
CastReceiverContext.getInstance().sendMessage(
    "urn:x-cast:com.example.cast.mynamespace", senderId, customString)
جاوا
// If senderId is null, then the message is broadcasted to all senders.
CastReceiverContext.getInstance().sendMessage(
    "urn:x-cast:com.example.cast.mynamespace", senderId, customString);

Android TV—Receive Custom Namespace Messages

Kotlin
class MyCustomMessageListener : MessageReceivedListener {
    override fun onMessageReceived(
        namespace: String, senderId: String?, message: String ) {
        ...
    }
}

CastReceiverContext.getInstance().setMessageReceivedListener(
    "urn:x-cast:com.example.cast.mynamespace", new MyCustomMessageListener());
جاوا
class MyCustomMessageListener implements CastReceiverContext.MessageReceivedListener {
  @Override
  public void onMessageReceived(
      String namespace, String senderId, String message) {
    ...
  }
}

CastReceiverContext.getInstance().setMessageReceivedListener(
    "urn:x-cast:com.example.cast.mynamespace", new MyCustomMessageListener());