الفواصل الإعلانية
توفّر حزمة تطوير البرامج (SDK) الخاصة بـ "أداة الإرسال" على Android إمكانية عرض فواصل إعلانية وإعلانات مصاحبة ضمن بث وسائط معيّن.
يمكنك الاطّلاع على نظرة عامة على فواصل الإعلانات في Web Receiver لمزيد من المعلومات حول طريقة عمل فواصل الإعلانات.
على الرغم من إمكانية تحديد فواصل الإعلانات على كل من جهاز الإرسال وجهاز الاستقبال، ننصح بتحديدها على Web Receiver وAndroid TV Receiver للحفاظ على سلوك متّسق على جميع الأنظمة الأساسية.
على Android، حدِّد الفواصل الإعلانية في أمر تحميل باستخدام
AdBreakClipInfo
وAdBreakInfo:
val breakClip1: AdBreakClipInfo = AdBreakClipInfo.Builder("bc0") .setTitle("Clip title") .setPosterUrl("https://www.some.url") .setDuration(60000) .setWhenSkippableInMs(5000) // Set this field so that the ad is skippable .build() val breakClip2: AdBreakClipInfo = … val breakClip3: AdBreakClipInfo = … val break1: AdBreakClipInfo = AdBreakInfo.Builder(/* playbackPositionInMs= */ 10000) .setId("b0") .setBreakClipIds({"bc0","bc1","bc2"}) … .build() val mediaInfo: MediaInfo = MediaInfo.Builder() … .setAdBreaks({break1}) .setAdBreakClips({breakClip1, breakClip2, breakClip3}) .build() val mediaLoadRequestData: MediaLoadRequestData = MediaInfo.Builder() … .setMediaInfo(mediaInfo) .build() remoteMediaClient.load(mediaLoadRequestData)
AdBreakClipInfo breakClip1 = new AdBreakClipInfo.Builder("bc0") .setTitle("Clip title") .setPosterUrl("https://www.some.url") .setDuration(60000) .setWhenSkippableInMs(5000) // Set this field so that the ad is skippable .build(); AdBreakClipInfo breakClip2 = … AdBreakClipInfo breakClip3 = … AdBreakInfo break1 = new AdBreakInfo.Builder(/* playbackPositionInMs= */ 10000) .setId("b0") .setBreakClipIds({"bc0","bc1","bc2"}) … .build(); MediaInfo mediaInfo = new MediaInfo.Builder() … .setAdBreaks({break1}) .setAdBreakClips({breakClip1, breakClip2, breakClip3}) .build(); MediaLoadRequestData mediaLoadRequestData = new MediaInfo.Builder() … .setMediaInfo(mediaInfo) .build(); remoteMediaClient.load(mediaLoadRequestData);
إضافة إجراءات مخصّصة
يمكن لتطبيق المرسِل توسيع نطاق
MediaIntentReceiver
للتعامل مع الإجراءات المخصّصة أو إلغاء سلوكه. إذا كنت قد نفّذت السمة MediaIntentReceiver الخاصة بك، عليك إضافتها إلى ملف البيان، وتحديد اسمها في السمة CastMediaOptions. يقدّم هذا المثال إجراءات مخصّصة تتجاوز إمكانية إيقاف تشغيل الوسائط عن بُعد أو تشغيلها، والضغط على زر الوسائط، وأنواع أخرى من الإجراءات.
// In AndroidManifest.xml
<receiver android:name="com.example.MyMediaIntentReceiver" />
// In your OptionsProvider var mediaOptions = CastMediaOptions.Builder() .setMediaIntentReceiverClassName(MyMediaIntentReceiver::class.java.name) .build() // Implementation of MyMediaIntentReceiver internal class MyMediaIntentReceiver : MediaIntentReceiver() { override fun onReceiveActionTogglePlayback(currentSession: Session) { } override fun onReceiveActionMediaButton(currentSession: Session, intent: Intent) { } override fun onReceiveOtherAction(context: Context?, action: String, intent: Intent) { } }
// In your OptionsProvider CastMediaOptions mediaOptions = new CastMediaOptions.Builder() .setMediaIntentReceiverClassName(MyMediaIntentReceiver.class.getName()) .build(); // Implementation of MyMediaIntentReceiver class MyMediaIntentReceiver extends MediaIntentReceiver { @Override protected void onReceiveActionTogglePlayback(Session currentSession) { } @Override protected void onReceiveActionMediaButton(Session currentSession, Intent intent) { } @Override protected void onReceiveOtherAction(Context context, String action, Intent intent) { } }
إضافة قناة مخصّصة
لكي يتواصل تطبيق المُرسِل مع تطبيق المُستلِم، يجب أن ينشئ تطبيقك قناة مخصّصة. يمكن للمرسِل استخدام القناة المخصّصة لإرسال رسائل سلسلة إلى المستلِم. يتم تحديد كل قناة مخصّصة من خلال مساحة اسم فريدة ويجب أن تبدأ بالبادئة urn:x-cast:، مثلاً، urn:x-cast:com.example.custom. يمكن أن تتضمّن السمة قنوات مخصّصة متعدّدة، ولكل منها مساحة اسم فريدة. يمكن لتطبيق المستلِم أيضًا إرسال الرسائل وتلقّيها باستخدام مساحة الاسم نفسها.
يتم تنفيذ القناة المخصّصة باستخدام واجهة
Cast.MessageReceivedCallback:
class HelloWorldChannel : MessageReceivedCallback { val namespace: String get() = "urn:x-cast:com.example.custom" override fun onMessageReceived(castDevice: CastDevice, namespace: String, message: String) { Log.d(TAG, "onMessageReceived: $message") } }
class HelloWorldChannel implements Cast.MessageReceivedCallback { public String getNamespace() { return "urn:x-cast:com.example.custom"; } @Override public void onMessageReceived(CastDevice castDevice, String namespace, String message) { Log.d(TAG, "onMessageReceived: " + message); } }
بعد ربط تطبيق المرسِل بتطبيق المستلِم، يمكن إنشاء القناة المخصّصة باستخدام طريقة setMessageReceivedCallbacks:
try { mCastSession.setMessageReceivedCallbacks( mHelloWorldChannel.namespace, mHelloWorldChannel) } catch (e: IOException) { Log.e(TAG, "Exception while creating channel", e) }
try { mCastSession.setMessageReceivedCallbacks( mHelloWorldChannel.getNamespace(), mHelloWorldChannel); } catch (IOException e) { Log.e(TAG, "Exception while creating channel", e); }
بعد إنشاء القناة المخصّصة، يمكن للمُرسِل استخدام طريقة
sendMessage
لإرسال رسائل نصية إلى المستلِم عبر تلك القناة:
private fun sendMessage(message: String) { if (mHelloWorldChannel != null) { try { mCastSession.sendMessage(mHelloWorldChannel.namespace, message) .setResultCallback { status -> if (!status.isSuccess) { Log.e(TAG, "Sending message failed") } } } catch (e: Exception) { Log.e(TAG, "Exception while sending message", e) } } }
private void sendMessage(String message) { if (mHelloWorldChannel != null) { try { mCastSession.sendMessage(mHelloWorldChannel.getNamespace(), message) .setResultCallback( status -> { if (!status.isSuccess()) { Log.e(TAG, "Sending message failed"); } }); } catch (Exception e) { Log.e(TAG, "Exception while sending message", e); } } }
إتاحة التشغيل التلقائي
راجِع القسم واجهات برمجة التطبيقات الخاصة بالتشغيل التلقائي وإضافة المحتوى إلى قائمة الانتظار.
تجاوز اختيار الصور للتطبيقات المصغّرة الخاصة بتجربة المستخدم
ستعرض مكوّنات مختلفة من إطار العمل (مثل مربّع حوار Cast ووحدة التحكّم المصغّرة وUIMediaController، إذا تم ضبطها على هذا النحو) العمل الفني للوسائط التي يتم بثّها حاليًا. عادةً ما يتم تضمين عناوين URL الخاصة برسومات الصور في MediaMetadata للوسائط، ولكن قد يتضمّن تطبيق المرسِل مصدرًا بديلاً لعناوين URL.
يحدّد الصف
ImagePicker
وسيلة لاختيار صورة مناسبة من قائمة الصور
في MediaMetadata، استنادًا إلى استخدام الصورة، مثل
الصورة المصغّرة للإشعار أو خلفية ملء الشاشة. يختار التنفيذ التلقائي ImagePicker دائمًا الصورة الأولى، أو يعرض قيمة فارغة إذا لم تتوفّر أي صورة في MediaMetadata. يمكن لتطبيقك إنشاء فئة فرعية من ImagePicker وتجاوز طريقة onPickImage(MediaMetadata, ImageHints) لتوفير تنفيذ بديل، ثم اختيار تلك الفئة الفرعية باستخدام طريقة setImagePicker الخاصة بالفئة CastMediaOptions.Builder.
يقدّم ImageHints
تلميحات إلى ImagePicker بشأن نوع وحجم الصورة التي سيتم اختيارها لعرضها في واجهة المستخدم.
تخصيص مربّعات حوار Cast
إدارة مراحل الجلسة
SessionManager
هي المكان المركزي لإدارة دورة حياة الجلسة. تستمع SessionManager إلى
تغييرات حالة اختيار المسار في Android
MediaRouter
لبدء الجلسات واستئنافها وإنهاءها. عند اختيار مسار، ستنشئ SessionManager عنصر Session وتحاول بدء المسار أو استئنافه. عند إلغاء اختيار مسار، سيؤدي ذلك إلى إنهاء الجلسة الحالية في SessionManager.
لذلك، ولضمان إدارة SessionManager لدورات حياة الجلسات بشكل سليم، عليك التأكّد مما يلي:
- في مربّع حوار أداة اختيار المسار،
استدعِ
MediaRouter.selectRoute(MediaRouter.RouteInfo)عندما يختار المستخدم جهازًا. - في مربّع حوار أداة التحكّم في المسار (إما في حالة الاتصال أو حالة البث)، استدعِ
MediaRouter.unselect(int)عندما يتوقف المستخدم عن البث.
استنادًا إلى طريقة إنشاء مربّعات الحوار الخاصة بميزة Cast، قد تحتاج إلى تنفيذ إجراءات إضافية:
- إذا أنشأت مربّعات حوار Cast باستخدام
MediaRouteChooserDialogوMediaRouteControllerDialog، سيعدّل مربّع الحوار هذا اختيار المسار فيMediaRouterتلقائيًا، لذلك ليس عليك اتّخاذ أي إجراء. - إذا أعددت زر البث باستخدام
CastButtonFactory.setUpMediaRouteButton(Context, Menu, int)أوCastButtonFactory.setUpMediaRouteButton(Context, MediaRouteButton)، سيتم إنشاء مربّعات الحوار باستخدامMediaRouteChooserDialogوMediaRouteControllerDialog، لذلك لن تحتاج إلى اتّخاذ أي إجراء. - في حالات أخرى، ستنشئ مربّعات حوار مخصّصة للبث، لذا عليك اتّباع التعليمات أعلاه لتعديل حالة اختيار المسار في
MediaRouter.
حالة عدم توفّر أجهزة
في حال إنشاء مربّعات حوار مخصّصة لـ Cast، يجب أن يتعامل
MediaRouteChooserDialog المخصّص بشكل سليم مع حالة عدم العثور على أي أجهزة. يجب أن يتضمّن مربّع الحوار مؤشرات توضّح للمستخدمين الحالات التي لا يزال فيها تطبيقك يحاول العثور على الأجهزة والحالات التي لم يعُد فيها البحث نشطًا.
إذا كنت تستخدم MediaRouteChooserDialog التلقائي، سيتم التعامل مع حالة عدم توفّر أجهزة.
الخطوات التالية
بهذا نكون قد انتهينا من الميزات التي يمكنك إضافتها إلى تطبيق المرسِل على Android. يمكنك الآن إنشاء تطبيق مرسِل لنظام أساسي آخر (iOS أو الويب)، أو إنشاء تطبيق استقبال على الويب.