این صفحه شامل قطعه کد و توضیحاتی از ویژگی های موجود برای سفارشی کردن برنامه گیرنده تلویزیون Android است.
پیکربندی کتابخانه ها
برای در دسترس قرار دادن Cast Connect API برای برنامه Android TV:
- فایل
build.gradleرا در دایرکتوری ماژول برنامه خود باز کنید. - بررسی کنید که
google()درrepositoriesفهرست شده گنجانده شده باشد.repositories { google() } - بسته به نوع دستگاه مورد نظر خود برای برنامه خود، آخرین نسخه های کتابخانه ها را به وابستگی های خود اضافه کنید:
- برای برنامه گیرنده اندروید:
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' }
- برای برنامه گیرنده اندروید:
- تغییرات را ذخیره کنید و روی
Sync Project with Gradle Filesدر نوار ابزار کلیک کنید.
- مطمئن شوید که
Podfilegoogle-cast-sdk4.8.4 یا بالاتر را هدف قرار داده است - iOS 15 یا بالاتر را هدف قرار دهید. برای جزئیات بیشتر به یادداشت های انتشار مراجعه کنید.
platform: ios, '15' def target_pods pod 'google-cast-sdk', '~>4.8.4' end
- به مرورگر Chromium نسخه M87 یا بالاتر نیاز دارد.
- کتابخانه 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(); } }
به نسخه 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);
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);
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);
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 TaskonLoad(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 TaskonSkipAd(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()); به نسخه v4.8.4 یا بالاتر 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 TaskcheckLaunchRequestSupported(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());