Dodaj zaawansowane funkcje do swojej aplikacji na Androida

Przerwy na reklamy

Pakiet Android Sender SDK zapewnia obsługę przerw na reklamę i reklam towarzyszących w danym strumieniu multimediów.

Więcej informacji o tym, jak działają przerwy na reklamy, znajdziesz w artykule o przerwach na reklamy w odbiorniku internetowym.

Przerwy można określić zarówno w przypadku nadawcy, jak i odbiorcy, ale zaleca się, aby były one określone w odbiorniku internetowym i odbiorniku Android TV. Pozwoli to zachować spójność działania na różnych platformach.

Na urządzeniu z Androidem przerwy na reklamy określ w poleceniu wczytywania za pomocą AdBreakClipInfo i 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);

Dodaj działania niestandardowe

Aplikacja nadawcy może rozszerzyć zakres MediaIntentReceiver, aby obsługiwać działania niestandardowe lub zastąpić jego działanie. Jeśli masz zaimplementowany własny zasób MediaIntentReceiver, musisz go dodać do pliku manifestu oraz określić jego nazwę w polu CastMediaOptions. Ten przykład przedstawia niestandardowe działania, które zastępują włączanie i wyłączanie zdalnego odtwarzania multimediów przez naciśnięcie przycisku multimediów oraz inne działania.

// 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) {
    }
}

Dodawanie kanału niestandardowego

Aby aplikacja nadawcy mogła komunikować się z aplikacją adresata, musi utworzyć kanał niestandardowy. Nadawca może używać kanału niestandardowego do wysyłania wiadomości tekstowych do odbiorcy. Każdy kanał niestandardowy jest definiowany przez niepowtarzalną przestrzeń nazw i musi się zaczynać od prefiksu urn:x-cast:, np. urn:x-cast:com.example.custom. Możesz mieć wiele kanałów niestandardowych, z których każdy ma unikalną przestrzeń nazw. Aplikacja odbierająca może też wysyłać i odbierać wiadomości, korzystając z tej samej przestrzeni nazw.

Kanał niestandardowy jest zaimplementowany za pomocą interfejsu 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);
    }
}

Gdy aplikacja nadawcy zostanie połączona z aplikacją odbiorcy, kanał niestandardowy można utworzyć za pomocą metody 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);
}

Po utworzeniu kanału niestandardowego nadawca może użyć metody sendMessage, aby wysyłać do odbiorcy wiadomości z ciągiem tekstowym przez ten kanał:

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);
        }
    }
}

Obsługa autoodtwarzania

Zapoznaj się z sekcją Interfejsy API autoodtwarzania i kolejkowania.

Zastępowanie wyboru obrazów na potrzeby widżetów UX

Różne komponenty platformy (np. okno przesyłania, minikontroler i kontroler UIMediaController, jeśli tak są skonfigurowane) wyświetlają elementy graficzne dla aktualnie przesyłanych multimediów. Adresy URL grafiki z obrazem są zwykle umieszczane w elemencie MediaMetadata w przypadku mediów, ale aplikacja nadawcy może mieć alternatywne źródło tych adresów.

Klasa ImagePicker definiuje sposoby wybierania odpowiedniego obrazu z listy obrazów w elemencie MediaMetadata na podstawie użycia obrazu, na przykład miniatury powiadomienia lub tła pełnego ekranu. Domyślna implementacja ImagePicker zawsze wybiera pierwszy obraz lub zwraca wartość null, jeśli w interfejsie MediaMetadata nie ma żadnego obrazu. Aplikacja może utworzyć podklasę ImagePicker i zastąpić metodę onPickImage(MediaMetadata, ImageHints), aby udostępnić alternatywną implementację, a następnie wybrać tę podklasę za pomocą metody setImagePicker funkcji CastMediaOptions.Builder. ImageHints zawiera wskazówki ImagePicker na temat typu i rozmiaru obrazu, który ma być wyświetlany w interfejsie.

Dostosowywanie okien przesyłania

Zarządzanie cyklem życia sesji

SessionManager to główne miejsce zarządzania cyklem życia sesji. SessionManager nasłuchuje Androida MediaRouter powoduje zmiany stanu wyboru trasy podczas rozpoczynania, wznawiania i zakończenia sesji. Po wybraniu trasy SessionManager utworzy obiekt Session i spróbuje go uruchomić lub wznowić. Gdy nie wybierzesz trasy, SessionManager zakończy bieżącą sesję.

Dlatego, aby mieć pewność, że SessionManager prawidłowo zarządza cyklami życia sesji, musisz sprawdzić, czy:

W zależności od sposobu tworzenia okien dialogowych przesyłania konieczne może być wykonanie dodatkowych czynności:

Stan Zero urządzeń

Jeśli utworzysz niestandardowe okna przesyłania, niestandardowy MediaRouteChooserDialog powinien prawidłowo obsługiwać przypadki braku znalezionych urządzeń. Okno powinno zawierać wskaźniki, które będą jasno informować użytkowników, że aplikacja nadal próbuje znaleźć urządzenia i gdy próba wykrycia nie jest już aktywna.

Jeśli używasz domyślnego ustawienia MediaRouteChooserDialog, obsługa stanu zero urządzeń jest już obsługiwana.

Dalsze kroki

To już koniec funkcji, które możesz dodać do aplikacji Android Sender. Teraz możesz utworzyć aplikację nadawcy na inną platformę (iOS lub Internet) albo utworzyć aplikację Web Recipient.