Android 앱에 고급 기능 추가

광고 시점

Android Sender SDK는 지정된 미디어 스트림 내에서 광고 시점과 컴패니언 광고를 지원합니다.

광고 시점의 작동 방식에 관한 자세한 내용은 웹 수신기 광고 시점 개요를 참고하세요.

브레이크는 발신자와 수신기 모두에서 지정할 수 있지만 플랫폼 전반에서 일관된 동작을 유지하려면 웹 수신기Android TV 수신기에서 지정하는 것이 좋습니다.

Android에서는 AdBreakClipInfoAdBreakInfo를 사용하여 로드 명령어에서 광고 시점을 지정합니다.

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);

맞춤 작업 추가

전송자 앱은 MediaIntentReceiver를 확장하여 맞춤 작업을 처리하거나 동작을 재정의할 수 있습니다. 자체 MediaIntentReceiver를 구현한 경우 이를 매니페스트에 추가하고 CastMediaOptions에서 이름을 설정해야 합니다. 이 예에서는 원격 미디어 재생 전환, 미디어 버튼 누르기, 기타 작업 유형을 재정의하는 맞춤 작업을 제공합니다.

// 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) {
    }
}

맞춤 채널 추가

발신자 앱이 수신자 앱과 통신하려면 앱에서 맞춤 채널을 만들어야 합니다. 발신자는 맞춤 채널을 사용하여 수신자에게 문자열 메시지를 보낼 수 있습니다. 각 맞춤 채널은 고유한 네임스페이스로 정의되며 urn:x-cast: 접두사로 시작해야 합니다(예: urn:x-cast:com.example.custom). 각각 고유한 네임스페이스가 있는 맞춤 채널을 여러 개 사용할 수 있습니다. 수신자 앱은 동일한 네임스페이스를 사용하여 메시지를 보내고 받을 수도 있습니다.

맞춤 채널은 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);
    }
}

전송자 앱이 수신자 앱에 연결되면 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);
}

맞춤 채널이 생성되면 발신자는 sendMessage 메서드를 사용하여 해당 채널을 통해 수신자에게 문자열 메시지를 전송할 수 있습니다.

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);
        }
    }
}

자동재생 지원

자동 재생 및 대기열 API 섹션을 참고하세요.

UX 위젯의 이미지 선택 재정의

프레임워크의 다양한 구성요소(즉, Cast 대화상자, 미니 컨트롤러, UIMediaController(구성된 경우))는 현재 전송 중인 미디어의 아트를 표시합니다. 이미지 아트워크의 URL은 일반적으로 미디어의 MediaMetadata에 포함되지만, 전송자 앱에 URL의 대체 소스가 있을 수 있습니다.

ImagePicker 클래스는 이미지 사용(예: 알림 썸네일 또는 전체 화면 배경)에 따라 MediaMetadata의 이미지 목록에서 적절한 이미지를 선택하는 방법을 정의합니다. 기본 ImagePicker 구현은 항상 첫 번째 이미지를 선택하거나 MediaMetadata에 사용할 수 있는 이미지가 없는 경우 null을 반환합니다. 앱은 ImagePicker를 서브클래스로 지정하고 onPickImage(MediaMetadata, ImageHints) 메서드를 재정의하여 대체 구현을 제공한 다음 CastMediaOptions.BuildersetImagePicker 메서드로 해당 서브클래스를 선택할 수 있습니다. ImageHints는 UI에 표시할 이미지의 유형과 크기에 관한 힌트를 ImagePicker에 제공합니다.

Cast 대화상자 맞춤설정

세션 수명 주기 관리

SessionManager은 세션 수명 주기를 관리하는 중앙 위치입니다. SessionManager는 Android MediaRouter 경로 선택 상태 변경을 수신 대기하여 세션을 시작, 재개, 종료합니다. 경로가 선택되면 SessionManagerSession 객체를 만들고 이를 시작하거나 재개하려고 시도합니다. 경로가 선택 해제되면 SessionManager에서 현재 세션을 종료합니다.

따라서 SessionManager가 세션 수명 주기를 올바르게 관리하도록 하려면 다음을 확인해야 합니다.

전송 대화상자를 만드는 방법에 따라 추가 작업을 실행해야 할 수 있습니다.

기기 없음 상태

맞춤 Cast 대화상자를 만드는 경우 맞춤 MediaRouteChooserDialog에서 기기가 0개인 경우를 올바르게 처리해야 합니다. 대화상자에는 앱이 기기를 계속 찾으려고 시도하는지, 검색 시도가 더 이상 활성화되지 않는지 사용자에게 명확하게 알려주는 표시기가 있어야 합니다.

기본 MediaRouteChooserDialog을 사용하는 경우 기기 0개 상태가 이미 처리됩니다.

다음 단계

이로써 Android 전송자 앱에 추가할 수 있는 기능이 모두 설명되었습니다. 이제 다른 플랫폼(iOS 또는 )용 전송자 앱을 빌드하거나 웹 수신기 앱을 빌드할 수 있습니다.