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

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

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

برای دردسترس قرار دادن «میاناهای برنامه‌سازی کاربردی اتصال پخش محتوا» برای برنامه 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:22.3.1'
        }
    • برای برنامه «فرستنده Android»:
        dependencies {
          implementation 'com.google.android.gms:play-services-cast:21.1.1'
          implementation 'com.google.android.gms:play-services-cast-framework:22.3.1'
        }
    حتماً هربار که سرویس‌ها به‌روزرسانی می‌شوند، این شماره نسخه را به‌روز کنید.
  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)
}
Java
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 را که از فرستندگان متصل می‌آیند بپذیرد.

راه‌اندازی 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()
    }
}
Java
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 استفاده می‌شود.

بافت گیرنده پخش محتوا

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

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

  ...
}
Java
@Override
public void onCreate() {
  CastReceiverContext.initInstance(this);

  ...
}

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

Kotlin
CastReceiverContext.getInstance().start()
Java
CastReceiverContext.getInstance().start();

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

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

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

به‌شدت توصیه می‌کنیم از کتابخانه androidx.lifecycle از LifecycleObserver برای مدیریت تماس 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())
Java
MediaManager mediaManager = receiverContext.getMediaManager();
mediaManager.setSessionCompatToken(currentMediaSession.getSessionToken());

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

Kotlin
myPlayer.stop()
mediaSession.release()
mediaManager.setSessionCompatToken(null)
Java
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()
  }
}
Java
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 می‌تواند برای مدیریت رویدادهای «دکمه رسانه» با فراخوانی 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، می‌توانید آمادگی آن را با تنظیم پرچم androidReceiverCompatible روی LaunchOptions به‌صورت درست اعلام کنید.

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()
    }
}
Java
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)
Java
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 شما راه‌اندازی شود، کیت توسعه نرم‌افزار (SDK) 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)
Java
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.
    ...
  }
}
Java
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)
  }
Java
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())
Java
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(). همچنین، برخی‌از دستورات صف باید در اینجا پیاده‌سازی شوند زیرا صف «پخش محتوا» با صف 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())
Java
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());

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

همانند گیرنده پخش محتوا، برنامه 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)
Java
// 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()
Java
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 قبل‌از ارسال

همانند «کیت توسعه نرم‌افزار گیرنده وب»، اگر می‌خواهید قبل‌از ارسال، تغییرات نهایی را انجام دهید، می‌توانید MediaStatusInterceptor را برای پردازش MediaStatus برای ارسال مشخص کنید. ما MediaStatusWriter را برای دستکاری MediaStatus قبل‌از ارسال آن وارد می‌کنیم.

Kotlin
mediaManager.setMediaStatusInterceptor(object : MediaStatusInterceptor {
    override fun intercept(mediaStatusWriter: MediaStatusWriter) {
      // Perform customization.
        mediaStatusWriter.setCustomData(JSONObject("{data: \"my Hello\"}"))
    }
})
Java
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.
}
Java
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 برنامه «گیرنده وب» شما را راه‌اندازی می‌کند.

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

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

Android TV—فضای نام سفارشی را مشخص کنید

باید جای‌نام‌های پشتیبانی‌شده‌تان را در 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)
Java
// 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());