Dodaj zaawansowane funkcje do swojej aplikacji na Androida

Przerwy na reklamę

Pakiet SDK Android Sender obsługuje przerwy na reklamę i reklamy towarzyszące w danym strumieniu multimediów.

Więcej informacji o tym, jak działają przerwy na reklamę, znajdziesz w artykule Omówienie przerw na reklamę w Web Receiver.

Przerwy można określać zarówno w nadajniku, jak i odbiorniku, ale zalecamy ich określanie w Web Receiver i Android TV Receiver, aby zachować spójność działania na różnych platformach.

Na urządzeniu z Androidem określ przerwy na reklamy 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);

Dodawanie działań niestandardowych

Aplikacja nadawcy może rozszerzyć MediaIntentReceiver, aby obsługiwać działania niestandardowe lub zastąpić jego działanie. Jeśli masz zaimplementowany własny element MediaIntentReceiver, musisz go dodać do pliku manifestu i ustawić jego nazwę w elementach CastMediaOptions. W tym przykładzie przedstawiono działania niestandardowe, które zastępują przełączanie odtwarzania multimediów z dalnie, naciśnięcie przycisku multimediów i inne rodzaje działań.

// 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 nadawcza mogła komunikować się z aplikacją odbiorczą, 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 zdefiniowany za pomocą unikalnej przestrzeni nazw i musi zaczynać się od prefiksu urn:x-cast:, na przykład urn:x-cast:com.example.custom. Możesz mieć wiele niestandardowych kanałów, z których każdy ma unikalną przestrzeń nazw. Aplikacja odbiorcy może też wysyłać i odbierać wiadomości przy użyciu tej samej przestrzeni nazw.

Kanał niestandardowy jest implementowany 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 nadawcza zostanie połączona z aplikacją odbiorczą, możesz utworzyć kanał niestandardowy 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ć wiadomości tekstowe do odbiorcy 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

Zobacz sekcję Interfejsy API autoodtwarzania i kolejkowania.

Zastępowanie wyboru obrazu w widżetach UX

Różne komponenty platformy (w tym okno przesyłania, minikontroler i UIMediaController, jeśli są skonfigurowane) będą wyświetlać grafikę dla przesyłanych obecnie multimediów. Adresy URL obrazów są zwykle uwzględnione w MediaMetadata dla multimediów, ale aplikacja nadawcy może mieć alternatywne źródło tych adresów.

Klasa ImagePicker definiuje sposób wybierania odpowiedniego obrazu z listy obrazów w MediaMetadata na podstawie sposobu użycia obrazu, np. miniatury powiadomienia lub tła na pełnym ekranie. Domyślna implementacja funkcji ImagePicker zawsze wybiera pierwszy obraz lub zwraca wartość null, jeśli w elementzie MediaMetadata nie ma żadnego obrazu. Aplikacja może być podklasą klasy ImagePicker i zastąpić metodę onPickImage(MediaMetadata, ImageHints), aby zapewnić alternatywną implementację, a następnie wybrać tę podklasę za pomocą metody setImagePicker klasy CastMediaOptions.Builder. ImageHints podaje ImagePicker podpowiedzi dotyczące typu i rozmiaru obrazu, który ma być wyświetlany w interfejsie.

Dostosowywanie okienek przesyłania

Zarządzanie cyklem życia sesji

SessionManager to centralne miejsce do zarządzania cyklem życia sesji. SessionManager nasłuchuje zmian stanu wyboru trasy w Androidzie MediaRouteraby rozpoczynać, wznawiać i kończyć sesje. Po wybraniu trasy SessionManager utworzy obiekt Session i spróbuje go uruchomić lub wznowić. Gdy trasa nie jest wybrana, SessionManager spowoduje zakończenie bieżącej sesji.

Dlatego, aby mieć pewność, że SessionManager będzie prawidłowo zarządzać cyklem życia sesji, musisz się upewnić, że:

W zależności od sposobu tworzenia dialogów przesyłania danych może być konieczne wykonanie dodatkowych czynności:

Stan urządzeń w stanie zero

Jeśli tworzysz niestandardowe okna dialogowe przesyłania, niestandardowe MediaRouteChooserDialog powinno prawidłowo obsługiwać przypadek, gdy nie znaleziono żadnych urządzeń. Okno powinno zawierać wskaźniki, które ułatwiają użytkownikom zrozumienie, kiedy aplikacja nadal próbuje wykrywać urządzenia, a kiedy próba wykrywania nie jest już aktywna.

Jeśli używasz domyślnego MediaRouteChooserDialog, stan zero urządzeń jest już obsługiwany.

Dalsze kroki

To już wszystkie funkcje, które możesz dodać do aplikacji nadawczej na Androida. Teraz możesz utworzyć aplikację nadawczą na inną platformę (iOS lub sieć) albo aplikację odbiorczą internetową.