Przerwy na reklamy
Pakiet SDK nadawcy na Androida 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 Przegląd przerw na reklamę w odbiorniku internetowym.
Przerwy można określić zarówno po stronie nadawcy, jak i odbiornika, ale zalecamy, aby były one określone w odbiorniku internetowym i odbiorniku Android TV, aby zachować spójne działanie na różnych platformach.
Na Androidzie określ przerwy na reklamę w poleceniu wczytywania, używając 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ć klasę MediaIntentReceiver, aby obsługiwać działania niestandardowe lub zastępować jej zachowanie. Jeśli masz własną implementację MediaIntentReceiver, musisz dodać ją do pliku manifestu i ustawić jej nazwę w CastMediaOptions. Ten przykład zawiera działania niestandardowe, które zastępują przełączanie zdalnego odtwarzania multimediów, 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 nadawcy mogła komunikować się z aplikacją odbiorcy, musisz 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 unikalną przestrzeń nazw i musi zaczynać się od prefiksu urn:x-cast:, na przykład urn:x-cast:com.example.custom. Możesz mieć wiele kanałów niestandardowych, z których każdy ma unikalną przestrzeń nazw. Aplikacja odbiornika 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); } }
Po połączeniu aplikacji nadawczej z aplikacją odbiorczą można 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żywać 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 przypadku widżetów UX
Różne komponenty platformy (czyli okno Cast, minikontroler i UIMediaController, jeśli jest skonfigurowany) będą wyświetlać grafikę aktualnie przesyłanych multimediów. Adresy URL grafiki są zwykle zawarte w MediaMetadata multimediów, ale aplikacja nadawcy może mieć alternatywne źródło adresów URL.
Klasa ImagePicker definiuje sposób wybierania odpowiedniego obrazu z listy obrazów w obiekcie MediaMetadata na podstawie zastosowania obrazu, np. miniatury powiadomienia lub tła pełnego ekranu. Domyślna implementacja ImagePicker zawsze wybiera pierwszy obraz lub zwraca wartość null, jeśli w MediaMetadata nie ma żadnego obrazu. Aplikacja może utworzyć podklasę 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 zawiera wskazówki dla ImagePicker dotyczące typu i rozmiaru obrazu, który ma zostać wybrany do wyświetlenia w interfejsie.
Dostosowywanie okien Cast
Zarządzanie cyklem życia sesji
SessionManager to centralne miejsce do zarządzania cyklem życia sesji. SessionManager nasłuchuje zmian stanu wyboru trasy Androida MediaRouter, aby rozpoczynać, wznawiać i kończyć sesje. Po wybraniu trasy SessionManager utworzy obiekt Session i spróbuje go uruchomić lub wznowić. Gdy trasa zostanie odznaczona, SessionManager zakończy bieżącą sesję.
Dlatego, aby usługa SessionManager prawidłowo zarządzała cyklami życia sesji, musisz upewnić się, że:
- W oknie wyboru trasy wywołaj
MediaRouter.selectRoute(MediaRouter.RouteInfo), gdy użytkownik wybierze urządzenie. - W oknie kontrolera trasy (w stanie połączenia lub stanie przesyłania) wywołaj
MediaRouter.unselect(int), gdy użytkownik przestanie przesyłać.
W zależności od tego, jak tworzysz okna Cast, może być konieczne wykonanie dodatkowych działań:
- Jeśli tworzysz okna Cast za pomocą
MediaRouteChooserDialogiMediaRouteControllerDialog, te okna będą automatycznie aktualizować wybór trasy wMediaRouter, więc nie musisz nic robić. - Jeśli przycisk Cast został skonfigurowany za pomocą
CastButtonFactory.setUpMediaRouteButton(Context, Menu, int)lubCastButtonFactory.setUpMediaRouteButton(Context, MediaRouteButton), okna są tworzone za pomocąMediaRouteChooserDialogiMediaRouteControllerDialog, więc nie trzeba nic robić. - W innych przypadkach będziesz tworzyć niestandardowe okna Cast, więc musisz postępować zgodnie z powyższymi instrukcjami, aby zaktualizować stan wyboru trasy w
MediaRouter.
Stan braku urządzeń
Jeśli tworzysz niestandardowe okna przesyłania, niestandardowy element MediaRouteChooserDialog powinien prawidłowo obsługiwać sytuację, gdy nie znaleziono żadnych urządzeń. Okno powinno zawierać wskaźniki, które jasno informują użytkowników, kiedy aplikacja nadal próbuje znaleźć urządzenia, a kiedy próba wykrywania nie jest już aktywna.
Jeśli używasz domyślnego MediaRouteChooserDialog, stan braku urządzeń jest już obsługiwany.
Dalsze kroki
To już wszystkie funkcje, które możesz dodać do aplikacji nadawczej na Androida. Możesz teraz utworzyć aplikację nadawczą na inną platformę (iOS lub internet) albo utworzyć aplikację odbiornika internetowego.