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
:
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);
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" />
// 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) { } }
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
:
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); } }
Gdy aplikacja nadawcza zostanie połączona z aplikacją odbiorczą, możesz utworzyć kanał niestandardowy za pomocą metody setMessageReceivedCallbacks
:
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); }
Po utworzeniu kanału niestandardowego nadawca może użyć metody sendMessage
, aby wysyłać wiadomości tekstowe do odbiorcy przez ten kanał:
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); } } }
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
MediaRouter
aby 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 oknie selektora trasy wywołaj funkcję
MediaRouter.selectRoute(MediaRouter.RouteInfo)
, gdy użytkownik wybierze urządzenie. - W oknie sterowania trasą (w stanie połączenia lub przesyłania) wywołaj funkcję
MediaRouter.unselect(int)
, gdy użytkownik przestanie przesyłać.
W zależności od sposobu tworzenia dialogów przesyłania danych może być konieczne wykonanie dodatkowych czynności:
- Jeśli tworzysz dialogi przesyłania za pomocą
MediaRouteChooserDialog
iMediaRouteControllerDialog
, te dialogi automatycznie zaktualizują wybór trasy wMediaRouter
, więc nie musisz nic robić. - Jeśli skonfigurujesz przycisk przesyłania za pomocą funkcji
CastButtonFactory.setUpMediaRouteButton(Context, Menu, int)
lubCastButtonFactory.setUpMediaRouteButton(Context, MediaRouteButton)
, dialogi zostaną utworzone za pomocą funkcjiMediaRouteChooserDialog
iMediaRouteControllerDialog
, więc nie trzeba nic robić. - W pozostałych przypadkach będziesz tworzyć niestandardowe okna dialogowe przesyłania, więc musisz wykonać opisane powyżej czynności, aby zaktualizować stan wyboru trasy w
MediaRouter
.
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ą.