إضافة ميزات متقدّمة إلى تطبيق Android

الفواصل الإعلانية

تتيح حزمة تطوير البرامج (SDK) لمرسِل Android استخدام الفواصل الإعلانية والإعلانات المصاحبة ضمن بث وسائط معيّن.

يمكنك الاطّلاع على نظرة عامة على الفواصل الإعلانية في Web Receiver لمزيد من المعلومات حول طريقة عمل الفواصل الإعلانية.

على الرغم من إمكانية تحديد الفواصل على كل من جهاز الإرسال وجهاز الاستقبال، يُنصح بتحديدها على جهاز استقبال الويب وجهاز استقبال Android TV للحفاظ على اتساق السلوك على جميع الأنظمة الأساسية.

على أجهزة Android، حدِّد الفواصل الإعلانية في أمر التحميل باستخدام AdBreakClipInfo وAdBreakInfo:

Kotlin
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)
Java
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" />
Kotlin
// 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) {
    }
}
Java
// 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:

Kotlin
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")
    }
}
Java
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:

Kotlin
try {
    mCastSession.setMessageReceivedCallbacks(
        mHelloWorldChannel.namespace,
        mHelloWorldChannel)
} catch (e: IOException) {
    Log.e(TAG, "Exception while creating channel", e)
}
Java
try {
    mCastSession.setMessageReceivedCallbacks(
            mHelloWorldChannel.getNamespace(),
            mHelloWorldChannel);
} catch (IOException e) {
    Log.e(TAG, "Exception while creating channel", e);
}

بعد إنشاء القناة المخصّصة، يمكن للمُرسِل استخدام الطريقة sendMessage لإرسال رسائل نصية إلى المُستلِم عبر تلك القناة:

Kotlin
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)
        }
    }
}
Java
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 لدورات حياة الجلسات بشكل صحيح، عليك التأكّد مما يلي:

بناءً على طريقة إنشاء مربّعات حوار Cast، قد تحتاج إلى تنفيذ إجراءات إضافية:

حالة عدم توفّر أجهزة

إذا أنشأت مربّعات حوار مخصّصة للبث، يجب أن يتعامل MediaRouteChooserDialog المخصّص بشكل صحيح مع حالة عدم العثور على أي أجهزة. يجب أن يحتوي مربّع الحوار على مؤشرات توضّح للمستخدمين متى لا يزال تطبيقك يحاول العثور على الأجهزة ومتى لم تعد محاولة الاكتشاف نشطة.

إذا كنت تستخدم MediaRouteChooserDialog التلقائي، ستتم معالجة حالة عدم توفّر أي أجهزة تلقائيًا.

الخطوات التالية

بهذا نكون قد انتهينا من الميزات التي يمكنك إضافتها إلى تطبيق الإرسال على Android. يمكنك الآن إنشاء تطبيق إرسال لنظام أساسي آخر (iOS أو الويب)، أو إنشاء تطبيق استقبال على الويب.