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

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

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

يمكنك الاطّلاع على نظرة عامة على الفواصل الإعلانية في أجهزة استقبال الويب لمزيد من المعلومات للحصول على معلومات عن طريقة عمل الفواصل الإعلانية

بينما يمكن تحديد الفواصل على كل من المرسل والمستلم، يُنصح بتحديدها المحدد في جهاز استقبال الويب جهاز استقبال 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);
        }
    }
}

تفعيل ميزة التشغيل التلقائي

راجِع القسم التشغيل التلقائي واجهات برمجة التطبيقات لإضافة المحتوى إلى قائمة المحتوى التالي

إلغاء اختيار الصور لأدوات تجربة المستخدم

المكونات المختلفة لإطار العمل (تحديدًا مربع حوار البث، والإطار المصغر وUIMediaController، إذا تم ضبطها) سيتم عرض العمل الفني للوسائط التي يتم بثها حاليًا عادةً ما تكون عناوين URL الخاصة بالصورة الفنية مضمّنة في MediaMetadata للوسائط، ولكن قد يحتوي تطبيق المرسِل على مصدر بديل لعناوين URL.

تشير رسالة الأشكال البيانية ImagePicker تحدد الفئة وسيلة لاختيار صورة مناسبة من قائمة الصور في MediaMetadata، استنادًا إلى استخدام الصورة، على سبيل المثال، إشعار صورة مصغّرة أو خلفية بملء الشاشة عملية تنفيذ "ImagePicker" التلقائية تختار الصورة الأولى دائمًا، أو تعرض قيمة خالية إذا لم تتوفر أي صورة في MediaMetadata يمكن لتطبيقك تصنيف "ImagePicker" ضمن الفئة الفرعية وإلغاء onPickImage(MediaMetadata, ImageHints) لتوفير طريقة تنفيذ بديلة، ثم تحديد تلك الفئة الفرعية مع setImagePicker لـ CastMediaOptions.Builder. ImageHints يقدّم تلميحات إلى ImagePicker عن نوع الصورة وحجمها المطلوب اختيارهما للعرض في واجهة المستخدم.

تخصيص مربعات حوار البث

إدارة مراحل نشاط الجلسة

SessionManager هو المكان المركزي لإدارة دورة حياة الجلسة. عدد مرات الاستماع: SessionManager إلى Android MediaRouter تغيير حالة اختيار المسار لبدء الجلسات واستئنافها وإنهائها. عندما يكون المسار محددة، سيتم إنشاء SessionManager Session ويحاول تشغيله أو استئنافه. عند إلغاء اختيار مسار، يؤدي الرمز SessionManager إلى إنهاء الجلسة الحالية.

لذلك، لضمان أن يدير SessionManager دورات حياة الجلسات بشكلٍ صحيح، يجب التأكّد ممّا يلي:

بناءً على كيفية إنشاء مربعات حوار البث، قد يلزم اتخاذ إجراءات إضافية تم:

  • إذا أنشأت مربّعات حوار لتطبيق Cast باستخدام MediaRouteChooserDialog و MediaRouteControllerDialog، ستُعدّل مربّعات الحوار هذه اختيار المسار في MediaRouter تلقائيًا، ولا حاجة إلى اتّخاذ أي إجراء.
  • إذا أعددت زرّ البث باستخدام CastButtonFactory.setUpMediaRouteButton(Context, Menu, int) أو CastButtonFactory.setUpMediaRouteButton(Context, MediaRouteButton)، يتم إنشاء مربّعات الحوار باستخدام MediaRouteChooserDialog وMediaRouteControllerDialog، وبالتالي، لا يلزم اتخاذ أي إجراء.
  • في الحالات الأخرى، ستتمكن من إنشاء مربعات حوار مخصصة للبث، ولذلك يتعين عليك اتبع التعليمات أعلاه لتعديل حالة اختيار المسار في MediaRouter

حالة "ما مِن أجهزة"

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

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

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

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