הוספה של תכונות מתקדמות לאפליקציית Android

הפסקות למודעות

ה-SDK של Android Sender כולל תמיכה בהפסקות למודעות ובמודעות נלוות בשידור מדיה נתון.

אפשר לקרוא את הסקירה הכללית על הפסקות למודעות של מקלטי אינטרנט כדי לקבל מידע נוסף על אופן הפעולה של ההפסקות למודעות.

אפשר לציין את ההפסקות גם אצל השולח וגם אצל המקבל, אבל מומלץ לציין אותן ב-WebReceiver וב-Android TV בבקשה כדי לשמור על התנהגות עקבית בכל הפלטפורמות.

ב-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)
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" />
קוטלין
// 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:

קוטלין
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:

קוטלין
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);
}

אחרי שיוצרים את הערוץ המותאם אישית, השולח יכול להשתמש ב-method 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)
        }
    }
}
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);
        }
    }
}

תמיכה בהפעלה אוטומטית

עיינו בקטע ממשקי API של הפעלה אוטומטית ותור.

שינוי בחירת התמונה לווידג'טים של UX

רכיבים שונים של ה-framework (כלומר, תיבת הדו-שיח Cast, המיני-בקר וה-UIMediaController, אם כן) יציגו גרפיקה של המדיה שמועברת כרגע. כתובות ה-URL לגרפיקה של התמונה בדרך כלל כלולות ב-MediaMetadata של המדיה, אבל יכול להיות שלאפליקציית השולח יש מקור חלופי לכתובות ה-URL.

המחלקה ImagePicker מגדירה אמצעי לבחירת תמונה מתאימה מרשימת התמונות ב-MediaMetadata, על סמך השימוש בתמונה. לדוגמה, תמונה ממוזערת של התראה או רקע של מסך מלא. הטמעת ברירת המחדל ImagePicker תמיד בוחרת את התמונה הראשונה, או מחזירה null אם אין תמונה זמינה ב-MediaMetadata. האפליקציה יכולה לתת סיווג משנה ImagePicker ולבטל את השיטה onPickImage(MediaMetadata, ImageHints) כדי לספק הטמעה חלופית, ולאחר מכן לבחור את מחלקת המשנה הזו באמצעות השיטה setImagePicker של CastMediaOptions.Builder. ImageHints מספק רמזים ל-ImagePicker לגבי הסוג והגודל של התמונה שצריך לבחור להצגה בממשק המשתמש.

התאמה אישית של תיבות דו-שיח של Cast

ניהול מחזור החיים של הסשן

SessionManager הוא המקום המרכזי לניהול מחזור החיים של סשנים. SessionManager מקשיב לשינויים במצב הבחירה של MediaRouter ב-Android כדי להתחיל, להמשיך ולסיים סשנים. כשבוחרים מסלול, SessionManager יוצר אובייקט Session ומנסה להתחיל או להמשיך אותו. אם לא בוחרים מסלול, SessionManager יסיים את הסשן הנוכחי.

לכן, כדי לוודא ש-SessionManager מנהל את מחזורי החיים של הסשנים כמו שצריך, צריך לוודא את הדברים הבאים:

בהתאם לאופן שבו יוצרים את תיבות הדו-שיח של Cast, ייתכן שיהיה צורך לבצע פעולות נוספות:

  • במקרה שיוצרים תיבות דו-שיח של העברה (cast) באמצעות MediaRouteChooserDialog ו-MediaRouteControllerDialog, תיבות הדו-שיח האלה יעדכנו את בחירת המסלול ב-MediaRouter באופן אוטומטי, כך שלא צריך לעשות שום דבר.
  • במקרה שהגדרת את לחצן הפעלת Cast באמצעות CastButtonFactory.setUpMediaRouteButton(Context, Menu, int) או CastButtonFactory.setUpMediaRouteButton(Context, MediaRouteButton), תיבות הדו-שיח נוצרות באמצעות MediaRouteChooserDialog ו-MediaRouteControllerDialog, כך שלא צריך לעשות כלום.
  • במקרים אחרים, תיצרו תיבות דו-שיח בהתאמה אישית ל-Cast, כך שתצטרכו לבצע את ההוראות שלמעלה כדי לעדכן את מצב בחירת המסלול ב-MediaRouter.

מצב 'אפס מכשירים'

אם יוצרים תיבות דו-שיח בהתאמה אישית של Cast, MediaRouteChooserDialog בהתאמה אישית צריך לטפל כראוי במקרים שבהם לא נמצאו מכשירים. בתיבת הדו-שיח צריכים להופיע אינדיקטורים שיבהירו למשתמשים מתי האפליקציה עדיין מנסה למצוא מכשירים ומתי ניסיון הגילוי כבר לא פעיל.

אם משתמשים בברירת המחדל MediaRouteChooserDialog, מצב אפס המכשירים כבר מטופל.

השלבים הבאים

הגענו למסקנה שיש לך אפשרות להוסיף תכונות לאפליקציה Android Sender. עכשיו אפשר לפתח אפליקציית שולח לפלטפורמה אחרת (iOS או אינטרנט), או ליצור אפליקציה של Web Acceptr.