افزودن «ویژگی‌های پیشرفته» به برنامه Android

وقفه آگهی

کیت توسعه نرم‌افزار Android Sender از «وقفه‌های آگهی» و آگهی‌های همپا در یک جاری‌سازی رسانه معین پشتیبانی می‌کند.

برای اطلاعات بیشتر درباره نحوه عملکرد «وقفه‌های آگهی»، نمای کلی وقفه‌های آگهی گیرنده وب را ببینید.

درحالی‌که وقفه‌ها را می‌توان هم در فرستنده و هم در گیرنده مشخص کرد، توصیه می‌شود آن‌ها را در گیرنده وب و گیرنده 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)
جاوا
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) {
    }
}
جاوا
// 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")
    }
}
جاوا
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)
}
جاوا
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)
        }
    }
}
جاوا
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);
        }
    }
}

پشتیبانی از پخش خودکار

بخش Autoplay & Queueing APIs را ببینید.

لغو انتخاب تصویر برای ابزاره‌های UX

بخش‌های مختلف چارچوب (یعنی کادر گفتگوی Cast، کنترل‌کننده کوچک، و UIMediaController، درصورت پیکربندی) آثار هنری رسانه درحال پخش محتوا را نمایش خواهند داد. نشانی‌های وب مربوط به تصویر هنری معمولاً در MediaMetadata برای رسانه گنجانده شده است، اما برنامه فرستنده ممکن است منبع جایگزینی برای نشانی‌های وب داشته باشد.

کلاس ImagePicker روشی را برای انتخاب تصویر مناسب از فهرست تصاویر در MediaMetadata براساس کاربرد تصویر تعریف می‌کند، برای مثال، ریزعکس اعلان یا پس‌زمینه تمام‌صفحه. پیاده‌سازی پیش‌فرض ImagePicker همیشه اولین تصویر را انتخاب می‌کند، یا اگر تصویری در MediaMetadata دردسترس نباشد، null برمی‌گرداند. برنامه شما می‌تواند زیرکلاس ImagePicker باشد و روش onPickImage(MediaMetadata, ImageHints) را لغو کند تا پیاده‌سازی جایگزینی ارائه دهد، و سپس آن زیرکلاس را با روش setImagePicker CastMediaOptions.Builder انتخاب کند. ImageHints نکاتی را درباره نوع و اندازه تصویری که باید برای نمایش در میانای کاربری انتخاب شود به ImagePicker ارائه می‌دهد.

سفارشی‌سازی کردن کادرهای گفتگوی Cast

مدیریت چرخه حیات جلسه

SessionManager مکان مرکزی برای مدیریت چرخه حیات جلسه است. SessionManager به تغییرات وضعیت انتخاب مسیر Android MediaRouter گوش می‌دهد تا جلسه‌ها را شروع کند، ازسر بگیرد، و پایان دهد. وقتی مسیری انتخاب می‌شود، SessionManager شیء Session ایجاد می‌کند و سعی می‌کند آن را شروع یا ازسر بگیرد. وقتی مسیری لغو انتخاب شود، SessionManager جلسه فعلی را پایان می‌دهد.

بنابراین، برای اطمینان از اینکه SessionManager چرخه‌های حیات جلسه را به‌درستی مدیریت می‌کند، باید مطمئن شوید که:

بسته به اینکه چگونه کادرهای گفتگوی Cast را ایجاد می‌کنید، ممکن است لازم باشد اقدامات بیشتری انجام شود:

  • اگر کادرهای گفتگوی Cast را بااستفاده از MediaRouteChooserDialog و MediaRouteControllerDialog ایجاد می‌کنید، این کادرهای گفتگو انتخاب مسیر را در MediaRouter به‌طور خودکار به‌روز می‌کنند، بنابراین لازم نیست کاری انجام دهید.
  • اگر دکمه «پخش محتوا» را بااستفاده از CastButtonFactory.setUpMediaRouteButton(Context, Menu, int) یا CastButtonFactory.setUpMediaRouteButton(Context, MediaRouteButton) راه‌اندازی کرده‌اید، کادرهای گفتگو درواقع بااستفاده از MediaRouteChooserDialog و MediaRouteControllerDialog ایجاد شده‌اند، بنابراین نیازی به انجام هیچ کاری نیست.
  • در موارد دیگر، شما درحال ایجاد کادرهای گفتگوی سفارشی Cast هستید، بنابراین باید دستورالعمل‌های بالا را برای به‌روزرسانی وضعیت انتخاب مسیر در MediaRouter دنبال کنید.

وضعیت صفر دستگاه

اگر گفتگوی Cast سفارشی ایجاد می‌کنید، MediaRouteChooserDialog سفارشی شما باید به‌درستی شرایطی را که هیچ دستگاهی پیدا نمی‌شود مدیریت کند. کادر گفتگو باید نشانگرهایی داشته باشد که وقتی برنامه‌تان همچنان در تلاش برای پیدا کردن دستگاه‌ها است و وقتی تلاش برای یافتن دیگر فعال نیست، این موضوع را برای کاربران روشن کند.

اگر از MediaRouteChooserDialog پیش‌فرض استفاده می‌کنید، وضعیت صفر دستگاه ازقبل مدیریت شده است.

مراحل بعدی

این پایان ویژگی‌هایی است که می‌توانید به برنامه «فرستنده Android» خود اضافه کنید. اکنون می‌توانید یک برنامه فرستنده برای پلاتفرم دیگری بسازید (iOS یا وب)، یا یک برنامه گیرنده وب بسازید.