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
:
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);
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" />
// 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 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
:
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 nadawcy zostanie połączona z aplikacją odbiorcy, kanał niestandardowy można utworzyć 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ć do odbiorcy wiadomości z ciągiem tekstowym 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
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:
- Gdy użytkownik wybierze urządzenie, w oknie wyboru trasy wywołaj
MediaRouter.selectRoute(MediaRouter.RouteInfo)
. - W oknie kontrolera trasy (w stanie połączenia lub stanie przesyłania) wywołaj
MediaRouter.unselect(int)
, gdy użytkownik zakończy przesyłanie.
W zależności od sposobu tworzenia okien dialogowych przesyłania konieczne może być wykonanie dodatkowych czynności:
- Jeśli tworzysz okna przesyłania za pomocą
MediaRouteChooserDialog
iMediaRouteControllerDialog
, wybór trasy w nich zostanie automatycznie zaktualizowany wMediaRouter
. Dzięki temu nie musisz nic robić. - Jeśli skonfigurujesz przycisk przesyłania za pomocą
CastButtonFactory.setUpMediaRouteButton(Context, Menu, int)
lubCastButtonFactory.setUpMediaRouteButton(Context, MediaRouteButton)
, okna będą faktycznie tworzone za pomocą znacznikówMediaRouteChooserDialog
iMediaRouteControllerDialog
, więc też nie musisz nic robić. - W innych przypadkach będziesz tworzyć niestandardowe okna przesyłania. Postępuj zgodnie z powyższymi instrukcjami, aby zaktualizować stan wyboru trasy w
MediaRouter
.
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.