ویژگی های اصلی را به گیرنده Android TV خود اضافه کنید

این صفحه شامل قطعه کدها و توضیحاتی در مورد ویژگی‌های موجود برای سفارشی‌سازی برنامه گیرنده تلویزیون اندروید است.

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

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

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

الزامات اندروید ایکس

نسخه‌های جدید سرویس‌های گوگل پلی نیاز به به‌روزرسانی برنامه برای استفاده از فضای نام androidx دارند. دستورالعمل‌های مهاجرت به AndroidX را دنبال کنید.

پیش‌نیازهای اپلیکیشن اندروید تی‌وی

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

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

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

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

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

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

مدیافراداده سازگار

فیلد فراداده توضیحات
عنوان کلید داده متا (الزامی) عنوان رسانه.
کلید داده متاداده نمایش عنوان زیرنویس
متاداده_کلید_نمایش_آیکون_URI آدرس اینترنتی آیکون.
مدت زمان کلید داده متاداده (الزامی) مدت زمان رسانه.
کلید داده متاداده شناسه محتوا.
کلید داده متاداده هنرمند هنرمند
کلید داده متاداده آلبوم.

PlaybackStateCompat

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

مدیاسشن کامپت

روش مورد نیاز توضیحات
حالت تکرار ()setRepeatMode حالت تکرار را تنظیم می‌کند.
تابع setShuffleMode() حالت پخش تصادفی را تنظیم می‌کند.
تنظیم فراداده () ابرداده‌های رسانه را تنظیم می‌کند.
تابع ()setPlaybackState وضعیت پخش را تنظیم می‌کند.
کاتلین
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

اقدامات توضیحات
روی پخش() رزومه
onPause() مکث
onSeekTo() دنبال مقام و منصب بودن
onStop() رسانه‌های فعلی را متوقف کنید
کاتلین
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

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

تنظیمات تلویزیون اندروید

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

یک فیلتر intent جدید به activity ای که می خواهید intent راه اندازی را از برنامه فرستنده خود مدیریت کند، اضافه کنید:

<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>

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

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

کاتلین
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 استفاده می‌شود.

زمینه گیرنده بازیگران

هنگام ایجاد برنامه CastReceiverContext مقداردهی اولیه کنید:

کاتلین
override fun onCreate() {
  CastReceiverContext.initInstance(this)

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

  ...
}

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

کاتلین
CastReceiverContext.getInstance().start()
جاوا
CastReceiverContext.getInstance().start();

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

کاتلین
// Player has stopped.
CastReceiverContext.getInstance().stop()
جاوا
// Player has stopped.
CastReceiverContext.getInstance().stop();

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

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

کاتلین
// 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 ارائه دهید تا بداند دستورات را به کجا ارسال کند و وضعیت پخش رسانه را بازیابی کند:

کاتلین
val mediaManager: MediaManager = receiverContext.getMediaManager()
mediaManager.setSessionCompatToken(currentMediaSession.getSessionToken())
جاوا
MediaManager mediaManager = receiverContext.getMediaManager();
mediaManager.setSessionCompatToken(currentMediaSession.getSessionToken());

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

کاتلین
myPlayer.stop()
mediaSession.release()
mediaManager.setSessionCompatToken(null)
جاوا
myPlayer.stop();
mediaSession.release();
mediaManager.setSessionCompatToken(null);

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

کاتلین
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 در برنامه خود، موارد زیر را به کلاس فعالیت پخش‌کننده یا هر جایی که جلسه رسانه خود را مدیریت می‌کنید، اضافه کنید:

کاتلین
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، آمادگی آن را اعلام کنید.

اندروید

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

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

کاتلین
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();
  }
}
آی‌او‌اس

به نسخه 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)
وب

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

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

راه‌اندازی کنسول توسعه‌دهنده کست

برنامه تلویزیون اندروید را پیکربندی کنید

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

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

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

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

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

بارگیری رسانه

اگر قبلاً پشتیبانی از لینک‌های عمیق را در برنامه Android TV خود پیاده‌سازی کرده‌اید، باید تعریف مشابهی را در Manifest 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 در اطلاعات رسانه برای درخواست بارگذاری، لینک عمیق را ارسال کنید:

کاتلین
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)
اندروید
جاوا
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);
آی‌او‌اس
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)
وب

به مرورگر کرومیوم نسخه 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);

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

تنظیم اعتبارنامه‌های ATV روی فرستنده

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

اندروید
کاتلین
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);
آی‌او‌اس
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)
وب

به مرورگر کرومیوم نسخه 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 در درخواست بارگذاری استفاده می‌کند. با این حال، اگر برنامه تلویزیون اندروید شما اجرا شود، SDK entity و credentials را با atvEntity و atvCredentials شما (در صورت مشخص شدن) لغو می‌کند.

بارگیری بر اساس شناسه محتوا یا MediaQueueData

اگر entity یا atvEntity استفاده نمی‌کنید و از Content ID یا Content URL در Media Information یا Media Load Request Data با جزئیات بیشتر استفاده می‌کنید، باید فیلتر intent از پیش تعریف شده زیر را در برنامه 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() را فراخوانی کنید.

اندروید
کاتلین
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);
آی‌او‌اس
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)
وب

به مرورگر کرومیوم نسخه 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);

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

در اکتیویتی خود، برای مدیریت این درخواست‌های بارگذاری، باید intentها را در فراخوانی‌های چرخه حیات اکتیویتی خود مدیریت کنید:

کاتلین
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 تشخیص دهد که intent مورد نظر، یک load intent است، یک شیء MediaLoadRequestData را از intent استخراج کرده و MediaLoadCommandCallback.onLoad() را فراخوانی می‌کند. برای مدیریت درخواست load، باید این متد را override کنید. callback باید قبل از فراخوانی MediaManager.onNewIntent() ثبت شود (توصیه می‌شود که در یک Activity یا Application onCreate() باشد).

کاتلین
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 برای درخواست‌های بارگذاری) تجزیه کنید.

پشتیبانی از دستورات رسانه‌ای

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

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

کاتلین
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());

پشتیبانی از دستورات کنترل Cast

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

کاتلین
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 مشخص شوند.

کاتلین
// 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 شما فقط از کنترل رسانه‌ای اولیه پشتیبانی می‌کند اما برنامه Web Receiver شما از کنترل پیشرفته‌تری پشتیبانی می‌کند، باید مطمئن شوید که برنامه فرستنده شما هنگام ارسال محتوا به برنامه Android TV به درستی رفتار می‌کند. به عنوان مثال، اگر برنامه Android TV شما از تغییر نرخ پخش پشتیبانی نمی‌کند در حالی که برنامه Web Receiver شما این کار را انجام می‌دهد، باید اقدامات پشتیبانی شده را به درستی در هر پلتفرم تنظیم کنید و مطمئن شوید که برنامه فرستنده شما رابط کاربری را به درستی رندر می‌کند.

اصلاح وضعیت رسانه

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

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

برای ایجاد و پخش MediaStatus :

کاتلین
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) قبل از ارسال

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

کاتلین
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() بازیابی کرد.

اندروید

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

کاتلین
CastContext.getSharedInstance().setLaunchCredentialsData(
    CredentialsData.Builder()
        .setCredentials("{\"userId\": \"abc\"}")
        .build()
)
جاوا
CastContext.getSharedInstance().setLaunchCredentialsData(
    new CredentialsData.Builder()
        .setCredentials("{\"userId\": \"abc\"}")
        .build());
آی‌او‌اس

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

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

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

به مرورگر کرومیوم نسخه 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 را پیاده‌سازی می‌کند:

کاتلین
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 خود تنظیم کنید:

کاتلین
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 برنامه Web Receiver شما را اجرا می‌کند.

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

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

تلویزیون اندروید - فضای نام سفارشی را مشخص کنید

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

کاتلین
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();
  }
}

تلویزیون اندروید - ارسال پیام

کاتلین
// 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);

تلویزیون اندروید - دریافت پیام‌های فضای نام سفارشی

کاتلین
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());