광고 시점
Android Sender SDK는 지정된 미디어 스트림 내에서 광고 시점 및 컴패니언 광고를 지원합니다.
광고 시점의 작동 방식에 관한 자세한 내용은 웹 수신기 광고 시점 개요를 참고하세요.
시점은 발신기와 수신기 모두에서 지정할 수 있지만 플랫폼 전반에서 일관된 동작을 유지하려면 웹 수신기 및 Android TV 수신기에서 지정하는 것이 좋습니다.
Android에서는 AdBreakClipInfo
및 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);
맞춤 작업 추가
발신자 앱은 MediaIntentReceiver
를 확장하여 맞춤 작업을 처리하거나 동작을 재정의할 수 있습니다. 자체 MediaIntentReceiver
를 구현한 경우 매니페스트에 추가하고 CastMediaOptions
에서 이름을 설정해야 합니다. 이 예에서는 원격 미디어 재생 전환, 미디어 버튼 누르기, 기타 유형의 작업을 재정의하는 맞춤 작업을 제공합니다.
// 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) { } }
맞춤 채널 추가
발신기 앱이 수신기 앱과 통신하려면 앱에서 맞춤 채널을 만들어야 합니다. 발신자는 맞춤 채널을 사용하여 수신자에게 문자열 메시지를 보낼 수 있습니다. 각 맞춤 채널은 고유한 네임스페이스로 정의되며 urn:x-cast:
접두사로 시작해야 합니다(예: urn:x-cast:com.example.custom
). 각각 고유한 네임스페이스를 가진 맞춤 채널을 여러 개 보유할 수 있습니다. 수신기 앱은 동일한 네임스페이스를 사용하여 메시지를 주고받을 수도 있습니다.
맞춤 채널은 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); } }
발신자 앱이 수신자 앱에 연결되면 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); }
맞춤 채널이 생성되면 발신자는 sendMessage
메서드를 사용하여 해당 채널을 통해 수신자에게 문자열 메시지를 보낼 수 있습니다.
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); } } }
자동재생 지원
자동재생 및 현재 재생목록 API 섹션을 참고하세요.
UX 위젯의 이미지 선택 재정의
프레임워크의 다양한 구성요소(예: 전송 대화상자, 미니 컨트롤러, UIMediaController(구성된 경우))는 현재 전송 중인 미디어의 아트워크를 표시합니다. 이미지 아트워크의 URL은 일반적으로 미디어의 MediaMetadata
에 포함되지만 발신자 앱에 URL의 대체 소스가 있을 수 있습니다.
ImagePicker
클래스는 이미지 사용(예: 알림 썸네일 또는 전체 화면 배경)에 따라 MediaMetadata
의 이미지 목록에서 적절한 이미지를 선택하는 수단을 정의합니다. 기본 ImagePicker
구현은 항상 첫 번째 이미지를 선택하거나 MediaMetadata
에 사용 가능한 이미지가 없는 경우 null을 반환합니다. 앱은 ImagePicker
를 서브클래스화하고 onPickImage(MediaMetadata, ImageHints)
메서드를 재정의하여 대체 구현을 제공한 다음 CastMediaOptions.Builder
의 setImagePicker
메서드로 해당 서브클래스를 선택할 수 있습니다.
ImageHints
는 UI에 표시하기 위해 선택할 이미지의 유형과 크기에 관한 힌트를 ImagePicker
에 제공합니다.
전송 대화상자 맞춤설정
세션 수명 주기 관리
SessionManager
는 세션 수명 주기를 관리하는 중앙 장소입니다. SessionManager
는 Android MediaRouter
경로 선택 상태 변경사항을 리슨하여 세션을 시작, 재개, 종료합니다. 경로가 선택되면 SessionManager
는 Session
객체를 만들고 시작하거나 재개하려고 시도합니다. 경로를 선택 해제하면 SessionManager
에서 현재 세션을 종료합니다.
따라서 SessionManager
가 세션 수명 주기를 올바르게 관리하려면 다음을 확인해야 합니다.
- 경로 선택기 대화상자에서 사용자가 기기를 선택하면
MediaRouter.selectRoute(MediaRouter.RouteInfo)
를 호출합니다. - 경로 컨트롤러 대화상자 (연결됨 상태 또는 전송 상태)에서 사용자가 전송을 중지하면
MediaRouter.unselect(int)
를 호출합니다.
전송 대화상자를 만드는 방법에 따라 추가 작업을 실행해야 할 수도 있습니다.
MediaRouteChooserDialog
및MediaRouteControllerDialog
를 사용하여 전송 대화상자를 만들면 이러한 대화상자가MediaRouter
의 경로 선택을 자동으로 업데이트하므로 아무것도 할 필요가 없습니다.CastButtonFactory.setUpMediaRouteButton(Context, Menu, int)
또는CastButtonFactory.setUpMediaRouteButton(Context, MediaRouteButton)
를 사용하여 전송 버튼을 설정하는 경우 대화상자는 실제로MediaRouteChooserDialog
및MediaRouteControllerDialog
를 사용하여 만들어지므로 아무것도 할 필요가 없습니다.- 그 밖의 경우에는 맞춤 Cast 대화상자를 만들게 되므로 위 안내에 따라
MediaRouter
에서 경로 선택 상태를 업데이트해야 합니다.
0 기기 상태
맞춤 Cast 대화상자를 만드는 경우 맞춤 MediaRouteChooserDialog
은 기기가 0개 발견된 경우를 올바르게 처리해야 합니다. 대화상자에는 앱이 기기를 찾으려고 시도 중인지, 기기 검색 시도가 더 이상 진행되지 않는지 사용자에게 명확하게 알리는 표시기가 있어야 합니다.
기본 MediaRouteChooserDialog
를 사용하는 경우 기기 0개 상태가 이미 처리됩니다.
다음 단계
Android 송신기 앱에 추가할 수 있는 기능은 이로써 모두 완료되었습니다. 이제 다른 플랫폼(iOS 또는 웹)용 송신기 앱을 빌드하거나 웹 수신기 앱을 빌드할 수 있습니다.