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

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

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

برای در دسترس قرار دادن Cast Connect API برای برنامه 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.0.0'
        }
    • برای برنامه فرستنده اندروید:
        dependencies {
          implementation 'com.google.android.gms:play-services-cast:21.1.1'
          implementation 'com.google.android.gms:play-services-cast-framework:22.0.0'
        }
    مطمئن شوید که هر بار که سرویس ها به روز می شوند، شماره نسخه را به روز می کنید.
  4. تغییرات را ذخیره کنید و روی Sync Project with Gradle Files در نوار ابزار کلیک کنید.
iOS
  1. مطمئن شوید که Podfile google-cast-sdk 4.8.3 یا بالاتر را هدف قرار داده است
  2. iOS 14 یا بالاتر را هدف قرار دهید. برای جزئیات بیشتر به یادداشت های انتشار مراجعه کنید.
      platform: ios, '14'
    
      def target_pods
         pod 'google-cast-sdk', '~>4.8.3'
      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 شناسه محتوا
METADATA_KEY_ARTIST هنرمند.
METADATA_KEY_ALBUM آلبوم.

PlaybackStateCompat

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

MediaSessionCompat

روش مورد نیاز توضیحات
setRepeatMode() حالت تکرار را تنظیم می کند.
setShuffleMode() حالت زدن را تنظیم می کند.
setMetadata() فراداده رسانه را تنظیم می کند.
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

اقدامات توضیحات
onPlay() رزومه
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

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

راه اندازی Android TV

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

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

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

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

برای ارائه 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() استفاده کنید، به خصوص اگر برنامه اصلی شما دارای چندین فعالیت باشد. این از شرایط مسابقه در هنگام فراخوانی start() و stop() از فعالیت های مختلف جلوگیری می کند.

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

اندروید

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

پرچم 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();
  }
}
iOS

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

پرچم 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 Developer Console اضافه کنید تا با Cast App ID خود مرتبط شود.

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

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

بدون ثبت نام، 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);
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);

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

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

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

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

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

remoteMediaClient?.loadMedia(with: mediaLoadRequestData)
وب

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

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

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

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

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

بارگیری توسط Content ID یا MediaQueueData

اگر از entity یا atvEntity استفاده نمی‌کنید و از Content ID یا Content URL در اطلاعات رسانه خود استفاده می‌کنید یا از داده‌های درخواست بارگذاری رسانه دقیق‌تر استفاده می‌کنید، باید فیلتر هدف از پیش تعریف‌شده زیر را در برنامه 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);
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);

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

در فعالیت خود، برای رسیدگی به این درخواست‌های بارگذاری، باید مقاصد موجود در بازگشت به تماس چرخه حیات فعالیت خود را مدیریت کنید:

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

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

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

اگر MediaManager تشخیص دهد که قصد بارگذاری است، یک شی MediaLoadRequestData را از intent استخراج کرده و MediaLoadCommandCallback.onLoad() را فراخوانی می کند. برای رسیدگی به درخواست بارگیری باید این روش را لغو کنید. قبل از فراخوانی 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 شما باید مشخص کند که کدام دستورات پشتیبانی می‌شوند، بنابراین فرستنده‌ها می‌توانند برخی از کنترل‌های UI را فعال یا غیرفعال کنند. برای دستوراتی که بخشی از 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 شما فقط از کنترل رسانه اولیه پشتیبانی می کند اما برنامه گیرنده وب شما از کنترل پیشرفته تری پشتیبانی می کند، باید مطمئن شوید که برنامه فرستنده شما هنگام ارسال محتوا به برنامه 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() بازیابی کرد.

اندروید

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

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

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

می‌توان در هر زمان پس از تنظیم گزینه‌ها تماس گرفت: 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 ایجاد کنید:

کاتلین
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 برنامه گیرنده وب شما را راه اندازی می کند.

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

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

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

شما باید فضاهای نام پشتیبانی شده خود را در 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();
  }
}

Android TV—ارسال پیام

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

Android TV - پیام‌های فضای نام سفارشی را دریافت کنید

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