CCL 발신기 앱을 Cast 애플리케이션 프레임워크 (CAF)로 이전

다음 절차를 사용하면 CCL을 사용하는 Cast SDK v2에서 Android 발신기 앱을 CAF로 변환할 수 있습니다. CCL의 모든 기능이 CAF에서 구현되었으므로 이전하면 더 이상 CCL을 사용할 필요가 없습니다.

Cast CAF Sender SDK는 CastContext를 사용하여 GoogleAPIClient를 관리합니다. CastContext는 수명 주기, 오류, 콜백을 자동으로 관리하므로 Cast 앱 개발이 크게 간소화됩니다.

소개

  • CAF 발신자 디자인은 Cast 컴패니언 라이브러리의 영향을 받았기 때문에 CCL에서 CAF 발신자로 이전하는 과정에는 대부분 클래스와 클래스의 일대일 매핑이 포함됩니다.
  • CAF 발신자는 여전히 Android SDK Manager를 사용하여 Google Play 서비스의 일부로 배포됩니다.
  • CCL과 유사한 기능을 가진 CAF Sender에 추가된 새로운 패키지(com.google.android.gms.cast.framework.*)는 Google Cast 디자인 체크리스트를 준수해야 합니다.
  • CAF 발신자는 Cast UX 요구사항을 준수하는 위젯을 제공합니다. 이러한 위젯은 CCL에서 제공하는 위젯과 유사합니다.
  • CAF 발신자는 CCL과 유사한 비동기 콜백을 제공하여 상태를 추적하고 데이터를 얻습니다. CCL과 달리 CAF 발신자는 다양한 인터페이스 메서드의 노옵(no-op) 구현을 제공하지 않습니다.

다음 섹션에서는 CCL의 VideoCastManager를 기반으로 하는 동영상 중심 애플리케이션에 주로 중점을 두지만, 많은 경우 동일한 개념이 DataCastManager에도 적용됩니다.

종속 항목

CCL과 CAF는 AppCompat 지원 라이브러리, MediaRouter v7 지원 라이브러리, Google Play 서비스에서 동일한 종속 항목을 갖습니다. 하지만 차이점은 CAF가 Google Play 서비스 9.2.0 이상에서 사용 가능한 새로운 Cast 프레임워크에 종속된다는 점입니다.

build.gradle 파일에서 com.google.android.gms:play-services-castcom.google.android.libraries.cast.companionlibrary:ccl의 종속 항목을 삭제한 다음 새로운 Cast 프레임워크를 추가합니다.

dependencies {
    compile 'com.android.support:appcompat-v7:23.4.0'
    compile 'com.android.support:mediarouter-v7:23.4.0'
    compile 'com.google.android.gms:play-services-cast-framework:9.4.0'
}

Google Play 서비스 메타데이터를 삭제할 수도 있습니다.

<meta‐data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version"/>

CAF에 속하는 모든 서비스, 활동, 리소스는 앱의 매니페스트 및 리소스와 자동으로 병합됩니다.

CAF에서 지원하는 최소 Android SDK 버전은 9(Gingerbread), CCL의 최소 Android SDK 버전은 10입니다.

CCL은 호환되는 Google Play 서비스 버전을 기기에서 사용할 수 있는지 여부를 확인하는 편의 메서드 BaseCastManager.checkGooglePlayServices(activity)를 제공합니다. CAF는 Cast SDK의 일부로 이를 제공하지 않습니다. 업데이트가 모든 사용자에게 즉시 제공되지 않을 수 있으므로 기기에 Google Play 서비스 APK가 있는지 확인 절차를 따라 사용자의 기기에 올바른 Google Play 서비스 APK가 설치되었는지 확인합니다.

애플리케이션 테마에 여전히 Theme.AppCompat의 변형을 사용해야 합니다.

초기화

CCL의 경우 애플리케이션 인스턴스의 onCreate() 메서드에서 VideoCastManager.initialize()를 호출해야 했습니다. 이 로직은 애플리케이션 클래스 코드에서 삭제해야 합니다.

CAF에서는 Cast 프레임워크에 명시적인 초기화 단계도 필요합니다. 이를 위해서는 CastContext 싱글톤을 초기화하고, 적절한 OptionsProvider를 사용하여 수신기 애플리케이션 ID 및 기타 전역 옵션을 지정해야 합니다. CastContext는 클라이언트와 상호작용하는 싱글톤을 제공하여 CCL의 VideoCastManager와 유사한 역할을 합니다. OptionsProvider는 CCL의 CastConfiguration와 유사하며, 이를 통해 Cast 프레임워크 기능을 구성할 수 있습니다.

현재 CCL CastConfiguration.Builder이 다음과 같다면,

VideoCastManager.initialize(
   getApplicationContext(),
   new CastConfiguration.Builder(context.getString(R.string.app_id))
       .enableWifiReconnection()
       .enableAutoReconnect()
       .build());

그러면 CAF에서 CastOptions.Builder를 사용하는 다음 CastOptionsProvider는 유사합니다.

public class CastOptionsProvider implements OptionsProvider {

    @Override
    public CastOptions getCastOptions(Context context) {
        return new CastOptions.Builder()
                .setReceiverApplicationId(context.getString(R.string.app_id))
                .build();
    }

    @Override
    public List<SessionProvider> getAdditionalSessionProviders(
            Context context) {
        return null;
    }
}

OptionsProvider의 전체 구현은 샘플 앱을 참고하세요.

AndroidManifest.xml 파일의 'application' 요소 내에서 OptionsProvider를 선언합니다.

<application>
...
    <meta-data
        android:name=
          "com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
        android:value="com.google.sample.cast.refplayer.CastOptionsProvider"    
    />
</application>

Application 인스턴스가 아닌 각 ActivityonCreate 메서드에서 CastContext를 느리게 초기화합니다.

private CastContext mCastContext;

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.video_browser);
    setupActionBar();

    mCastContext = CastContext.getSharedInstance(this);
}

CastContext 싱글톤에 액세스하려면 다음을 사용합니다.

mCastContext = CastContext.getSharedInstance(this);

기기 검색

CCL의 VideoCastManager incrementUiCounterdecrementUiCounterActivitiesonResumeonPause 메서드에서 삭제해야 합니다.

CAF에서는 앱이 포그라운드로 이동할 때 각각 백그라운드로 이동할 때 프레임워크에서 검색 프로세스를 자동으로 시작하고 중지합니다.

전송 버튼 및 전송 대화상자

CCL과 마찬가지로 이러한 구성요소는 MediaRouter v7 지원 라이브러리에서 제공합니다.

전송 버튼은 여전히 MediaRouteButton로 구현되며 ActionBar 또는 Toolbar를 사용하여 메뉴의 메뉴 항목으로 활동에 추가할 수 있습니다.

메뉴 xml의 MediaRouteActionProvider 선언은 CCL과 동일합니다.

<item
    android:id="@+id/media_route_menu_item"
    android:title="@string/media_route_menu_title"
    app:actionProviderClass="android.support.v7.app.MediaRouteActionProvider"
    app:showAsAction="always"/>

CCL과 마찬가지로 각 Activity의 onCreateOptionMenu() 메서드를 재정의합니다. 하지만 CastManager.addMediaRouterButton을 사용하는 대신 CAF의 CastButtonFactory를 사용하여 MediaRouteButton을 Cast 프레임워크에 연결하세요.

public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    getMenuInflater().inflate(R.menu.browse, menu);
    CastButtonFactory.setUpMediaRouteButton(getApplicationContext(),
                                                menu,
                                                R.id.media_route_menu_item);
    return true;
}

기기 제어

CCL과 마찬가지로 CAF에서는 기기 제어가 대부분 프레임워크에 의해 처리됩니다. 발신기 애플리케이션은 GoogleApiClient를 사용하여 기기 연결을 처리하고 수신기 애플리케이션을 실행할 필요가 없고 처리하려고 해서도 안 됩니다.

이제 발신자와 수신자 간의 상호작용이 '세션'으로 표시됩니다. SessionManager 클래스는 세션 수명 주기를 처리하고 사용자 동작에 응답하여 자동으로 세션을 시작하고 중지합니다. 사용자가 전송 대화상자에서 Cast 기기를 선택하면 세션이 시작되고 전송 대화상자에서 '전송 중지' 버튼을 탭하거나 발신자 앱 자체가 종료되면 세션이 종료됩니다.

CCL에서는 캐스트 세션 상태를 추적하기 위해 VideoCastConsumerImpl 클래스를 확장해야 합니다.

private final VideoCastConsumer mCastConsumer = new VideoCastConsumerImpl() {
  public void onApplicationConnected(ApplicationMetadata appMetadata, 
                                     String sessionId,
                                     boolean wasLaunched) {}
  public void onDisconnectionReason(int reason) {}
  public void onDisconnected() {}
}

CAF에서 SessionManagerSessionManagerListener를 등록하여 발신기 애플리케이션에 세션 수명 주기 이벤트를 알릴 수 있습니다. SessionManagerListener 콜백은 모든 세션 수명 주기 이벤트의 콜백 메서드를 정의합니다.

다음 SessionManagerListener 메서드는 CCL의 VideoCastConsumer 인터페이스에서 매핑됩니다.

  • VideoCastConsumer.onApplicationConnected -> SessionManagerListener.onSessionStarted
  • VideoCastConsumer.onDisconnected -> SessionManagerListener.onSessionEnded

SessionManagerListener 인터페이스를 구현하는 클래스를 선언하고 VideoCastConsumerImpl 로직을 일치하는 메서드로 이동합니다.

private class CastSessionManagerListener implements SessionManagerListener<CastSession> {
  public void onSessionEnded(CastSession session, int error) {}
  public void onSessionStarted(CastSession session, String sessionId) {}
  public void onSessionEnding(CastSession session) {}
  ...
}

CastSession 클래스는 Cast 기기의 세션을 나타냅니다. 이 클래스에는 기기 볼륨 및 음소거 상태를 제어하는 메서드가 있으며 CCL은 BaseCastManager에서 실행합니다.

CCL VideoCastManager를 사용하여 소비자를 추가하는 대신

VideoCastManager.getInstance().addVideoCastConsumer(mCastConsumer);

이제 SessionManagerListener를 등록합니다.

mCastSessionManager = 
    CastContext.getSharedInstance(this).getSessionManager();
mCastSessionManagerListener = new CastSessionManagerListener();
mCastSessionManager.addSessionManagerListener(mCastSessionManagerListener,
                  CastSession.class);

CCL에서 이벤트 리슨을 중지하려면 다음 단계를 따르세요.

VideoCastManager.getInstance().removeVideoCastConsumer(mCastConsumer);

이제 SessionManager를 사용하여 세션 이벤트 리슨을 중지합니다.

mCastSessionManager.removeSessionManagerListener(mCastSessionManagerListener,
                    CastSession.class);

Cast 기기에서 명시적으로 연결을 해제하기 위해 CCL은 다음을 사용했습니다.

VideoCastManager.disconnectDevice(boolean stopAppOnExit, 
            boolean clearPersistedConnectionData,
            boolean setDefaultRoute)

CAF의 경우 SessionManager를 사용합니다.

CastContext.getSharedInstance(this).getSessionManager()
                                   .endCurrentSession(true);

발신자가 수신기에 연결되어 있는지 확인하기 위해 CCL은 VideoCastManager.getInstance().isConnected()를 제공하지만 CAF에서는 SessionManager를 사용합니다.

public boolean isConnected() {
    CastSession castSession = CastContext.getSharedInstance(mAppContext)
                                  .getSessionManager()
                                  .getCurrentCastSession();
    return (castSession != null && castSession.isConnected());
}

CAF에서 볼륨/음소거 상태 변경 알림은 여전히 Cast.Listener의 콜백 메서드를 통해 전달됩니다. 이러한 리스너는 CastSession에 등록됩니다. 나머지 모든 기기 상태 알림은 CastStateListener 콜백을 통해 전달됩니다. 이러한 리스너는 CastSession에 등록됩니다. 연결된 프래그먼트, 활동 또는 앱이 백그라운드로 이동할 때 여전히 리스너를 등록 취소해야 합니다.

재연결 로직

CAF는 일시적인 Wi-Fi 신호 손실이나 기타 네트워크 오류로 인해 연결이 끊긴 네트워크 연결을 다시 설정하려고 시도합니다. 이 작업은 이제 세션 수준에서 실행됩니다. 연결이 끊어지면 세션은 '정지됨' 상태로 전환될 수 있고, 연결이 복원되면 '연결됨' 상태로 다시 전환됩니다. 프레임워크는 이 프로세스의 일부로 수신기 애플리케이션에 다시 연결하고 Cast 채널을 다시 연결합니다.

CAF는 자체 재연결 서비스를 제공하므로 매니페스트에서 CCL ReconnectionService를 삭제할 수 있습니다.

<service android:name="com.google.android.libraries.cast.companionlibrary.cast.reconnection.ReconnectionService"/>

또한 재연결 로직에는 매니페스트에 다음 권한이 필요하지 않습니다.

<uses‐permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses‐permission android:name="android.permission.ACCESS_WIFI_STATE"/>

CAF 재연결 서비스는 기본적으로 사용 설정되어 있지만 CastOptions를 사용하여 사용 중지할 수 있습니다.

또한 CAF는 자동 세션 재개를 추가하며, 기본적으로 사용 설정되며 CastOptions를 통해 비활성화할 수 있습니다. 전송 세션이 진행되는 동안 발신자 애플리케이션이 백그라운드로 전송되거나 종료되는 경우(스와이프하거나 비정상 종료로 인해) 발신자 애플리케이션이 포그라운드로 돌아가거나 다시 실행될 때 프레임워크에서 해당 세션을 재개하려고 시도합니다. 이는 SessionManager에서 적절한 콜백을 통해 처리됩니다. SessionManagerListener에서 이를 처리합니다.

맞춤 채널 등록

CCL은 받는 사람에게 맞춤 메시지 채널을 만드는 두 가지 방법을 제공합니다.

  • CastConfiguration를 사용하면 여러 네임스페이스를 지정할 수 있으며 CCL은 채널을 만듭니다.
  • DataCastManager는 VideoCastManager와 유사하지만 미디어가 아닌 사용 사례에 중점을 둡니다.

이러한 맞춤 채널 생성 방법은 모두 CAF에서 지원하지 않습니다. 대신 발신자 앱의 커스텀 채널 추가 절차를 따라야 합니다.

CCL과 마찬가지로 미디어 애플리케이션의 경우 미디어 제어 채널을 명시적으로 등록할 필요가 없습니다.

미디어 제어

CAF에서 RemoteMediaClient 클래스는 VideoCastManager 미디어 메서드와 같습니다. RemoteMediaClient.ListenerVideoCastConsumer 메서드와 같습니다. 특히 VideoCastConsumeronRemoteMediaPlayerMetadataUpdatedonRemoteMediaPlayerStatusUpdated 메서드는 각각 RemoteMediaClient.ListeneronMetadataUpdatedonStatusUpdated 메서드에 매핑됩니다.

private class CastMediaClientListener implements RemoteMediaClient.Listener {

    @Override
    public void onMetadataUpdated() {
        setMetadataFromRemote();
    }

    @Override
    public void onStatusUpdated() {
        updatePlaybackState();
    }

    @Override
    public void onSendingRemoteMediaRequest() {
    }

    @Override
    public void onQueueStatusUpdated() {
    }

    @Override
    public void onPreloadStatusUpdated() {
    }
}

RemoteMediaClient 객체를 명시적으로 초기화하거나 등록할 필요는 없습니다. 연결 중인 수신기 애플리케이션이 미디어 네임스페이스를 지원하는 경우 프레임워크는 자동으로 객체를 인스턴스화하고 세션 시작 시간에 기본 미디어 채널을 등록합니다.

RemoteMediaClientCastSession 객체의 getRemoteMediaClient 메서드로 액세스할 수 있습니다.

CastSession castSession = CastContext.getSharedInstance(mAppContext)
                                     .getSessionManager()
                                     .getCurrentCastSession();
mRemoteMediaClient = castSession.getRemoteMediaClient();
mRemoteMediaClientListener = new CastMediaClientListener();

CCL 대신 다음을 사용합니다.

VideoCastManager.getInstance().addVideoCastConsumer(mCastConsumer);

이제 CAF를 사용합니다.

mRemoteMediaClient.addListener(mRemoteMediaClientListener);

RemoteMediaClient에 여러 리스너를 등록할 수 있으며, 이를 통해 여러 발신자 구성요소가 세션과 연결된 RemoteMediaClient의 단일 인스턴스를 공유할 수 있습니다.

CCL의 VideoCastManager는 미디어 재생을 처리하는 메서드를 제공합니다.

VideoCastManager manager = VideoCastManager.getInstance();
if (manager.isRemoteMediaLoaded()) {
    manager.pause();
    mCurrentPosition = (int) manager.getCurrentMediaPosition();
}

이제 CAF에서 RemoteMediaClient에 의해 구현됩니다.

if (mRemoteMediaClient.hasMediaSession()) {
    mRemoteMediaClient.pause();
    mCurrentPosition = 
        (int)mRemoteMediaClient.getApproximateStreamPosition();
}

CAF에서 RemoteMediaClient에 실행된 모든 미디어 요청은 요청의 진행 상황과 최종 결과를 추적하는 데 사용할 수 있는 PendingResult 콜백을 통해 RemoteMediaClient.MediaChannelResult를 반환합니다.

CCL과 CAF는 모두 MediaInfoMediaMetadata 클래스를 사용하여 미디어 항목을 표시하고 미디어를 로드합니다.

CCL에서 미디어를 로드하기 위해 VideoCastManager가 사용됩니다.

VideoCastManager.getInstance().loadMedia(media, autoPlay, mCurrentPosition, customData);

CAF에서 RemoteMediaClient는 미디어를 로드하는 데 사용됩니다.

mRemoteMediaClient.load(media, autoPlay, mCurrentPosition, customData);

수신자에서 현재 미디어 세션의 Media 정보와 상태를 가져오기 위해 CCL은 VideoCastManager를 사용합니다.

MediaInfo mediaInfo = VideoCastManager.getInstance()
                                      .getRemoteMediaInformation();
int status = VideoCastManager.getInstance().getPlaybackStatus();
int idleReason = VideoCastManager.getInstance().getIdleReason();

CAF에서 RemoteMediaClient를 사용하여 동일한 정보를 가져옵니다.

MediaInfo mediaInfo = mRemoteMediaClient.getMediaInfo();
int status = mRemoteMediaClient.getPlayerState();
int idleReason = mRemoteMediaClient.getIdleReason();

소개 오버레이

CCL과 마찬가지로, CAF는 맞춤 뷰 IntroductoryOverlay를 제공하여 전송 버튼이 처음 사용자에게 표시될 때 이를 강조표시할 수 있습니다.

CCL의 VideoCastConsumer onCastAvailabilityChanged 메서드를 사용하여 오버레이를 표시할 시기를 파악하는 대신 MediaRouter를 통해 로컬 네트워크에서 Cast 기기가 검색될 때 전송 버튼이 표시될 시점을 CastStateListener을 선언합니다.

private IntroductoryOverlay mIntroductoryOverlay;
private MenuItem mMediaRouteMenuItem;

protected void onCreate(Bundle savedInstanceState) {
    ...
    mCastStateListener = new CastStateListener() {
        @Override
        public void onCastStateChanged(int newState) {
            if (newState != CastState.NO_DEVICES_AVAILABLE) {
                showIntroductoryOverlay();
            }
        }
    };
    mCastContext = CastContext.getSharedInstance(this);
    mCastContext.registerLifecycleCallbacksBeforeIceCreamSandwich(this, 
        savedInstanceState);
}

protected void onResume() {
    mCastContext.addCastStateListener(mCastStateListener);
    ...
}

protected void onPause() {
    mCastContext.removeCastStateListener(mCastStateListener);
    ...
}

MediaRouteMenuItem 인스턴스를 추적합니다.

public boolean onCreateOptionsMenu(Menu menu) {
   super.onCreateOptionsMenu(menu);
    getMenuInflater().inflate(R.menu.browse, menu);
    mMediaRouteMenuItem = CastButtonFactory.setUpMediaRouteButton(
            getApplicationContext(), menu,
            R.id.media_route_menu_item);
    showIntroductoryOverlay();
    return true;
}

소개 오버레이를 표시할 수 있도록 MediaRouteButton가 표시되는지 확인합니다.

private void showIntroductoryOverlay() {
    if (mIntroductoryOverlay != null) {
        mIntroductoryOverlay.remove();
    }
    if ((mMediaRouteMenuItem != null) && mMediaRouteMenuItem.isVisible()) {
        new Handler().post(new Runnable() {
            @Override
            public void run() {
                mIntroductoryOverlay = new IntroductoryOverlay.Builder(
                        VideoBrowserActivity.this, mMediaRouteMenuItem)
                        .setTitleText(getString(R.string.introducing_cast))
                        .setOverlayColor(R.color.primary)
                        .setSingleTime()
                        .setOnOverlayDismissedListener(
                                new IntroductoryOverlay
                                    .OnOverlayDismissedListener() {
                                        @Override
                                        public void onOverlayDismissed() {
                                            mIntroductoryOverlay = null;
                                        }
                                })
                        .build();
                mIntroductoryOverlay.show();
            }
        });
    }
}

소개 오버레이를 표시하기 위한 전체 작동 코드는 샘플 앱을 참고하세요.

소개 오버레이의 스타일을 맞춤설정하려면 소개 오버레이 맞춤설정 절차를 따르세요.

미니 컨트롤러

CCL의 MiniController 대신 미니 컨트롤러를 표시할 활동의 앱 레이아웃 파일에 CAF의 MiniControllerFragment를 사용합니다.

<fragment
        android:id="@+id/cast_mini_controller"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        app:castShowImageThumbnail="true"
        android:visibility="gone"
        class="com.google.android.gms.cast.framework.media.widget.MiniControllerFragment" />

CAF는 CCL의 MiniController에서 지원하는 수동 구성 및 Autoplay 기능을 지원하지 않습니다.

미니 컨트롤러의 스타일과 버튼을 맞춤설정하려면 미니 컨트롤러 맞춤설정 절차를 따릅니다.

알림 및 잠금 화면

CCL의 VideoCastNotificationService와 마찬가지로 CAF는 전송 시 미디어 알림 표시를 관리하는 MediaNotificationService를 제공합니다.

매니페스트에서 다음을 삭제해야 합니다.

  • VideoIntentReceiver
  • VideoCastNotificationService

CCL은 CastConfiguration.Builder를 사용하여 맞춤 알림 서비스를 제공하는 기능을 지원합니다. 이는 CAF에서 지원하지 않습니다.

CCL을 사용하는 다음 CastManager 초기화를 고려합니다.

VideoCastManager.initialize(
   getApplicationContext(),
   new CastConfiguration.Builder(
           context.getString(R.string.app_id))
       .addNotificationAction(
           CastConfiguration.NOTIFICATION_ACTION_PLAY_PAUSE,true)
       .addNotificationAction(
           CastConfiguration.NOTIFICATION_ACTION_DISCONNECT,true)
       .build());

CAF의 동등한 구성에 따라 SDK는 알림 및 잠금 화면의 미디어 컨트롤을 발신자 앱에 빌드하는 데 도움이 되는 NotificationsOptions.Builder을 제공합니다. CastContext를 초기화할 때 알림 및 잠금 화면 컨트롤을 CastOptions로 사용 설정할 수 있습니다.

public CastOptions getCastOptions(Context context) {
    NotificationOptions notificationOptions = 
        new NotificationOptions.Builder()
            .setActions(Arrays.asList(
                MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK,
                MediaIntentReceiver.ACTION_STOP_CASTING), new int[]{0, 1})
            .build();
    CastMediaOptions mediaOptions = new CastMediaOptions.Builder()
             .setNotificationOptions(notificationOptions)
             .build();
    return new CastOptions.Builder()
             .setReceiverApplicationId(context.getString(R.string.app_id))
             .setCastMediaOptions(mediaOptions)
             .build();
}

CAF에서는 알림 및 잠금 화면 컨트롤이 항상 사용 설정되어 있습니다. 또한 재생/일시중지 및 전송 중지 버튼은 기본적으로 제공됩니다. CAF는 Gingerbread를 제외하고 미디어 알림을 표시할 시기를 결정하기 위해 활동의 가시성을 자동으로 추적합니다. (Gingerbread의 경우 registerLifecycleCallbacksBeforeIceCreamSandwich() 사용에 관한 이전 메모를 참고하세요. CCL의 VideoCastManager incrementUiCounterdecrementUiCounter 호출은 삭제해야 합니다.)

알림에 표시되는 버튼을 맞춤설정하려면 알림 및 잠금 화면에 미디어 컨트롤 추가 절차를 따르세요.

확장 컨트롤러

CCL은 미디어를 전송할 때 확장된 컨트롤러를 표시하도록 VideoCastControllerActivityVideoCastControllerFragment를 제공합니다.

매니페스트에서 VideoCastControllerActivity 선언을 삭제할 수 있습니다.

CAF에서는 ExpandedControllerActivity를 확장하고 전송 버튼을 추가해야 합니다.

확장 컨트롤러에 표시되는 스타일과 버튼을 맞춤설정하려면 확장 컨트롤러 맞춤설정 절차를 따릅니다.

오디오 포커스

CCL과 마찬가지로 오디오 포커스는 자동으로 관리됩니다.

볼륨 컨트롤

Gingerbread의 경우 CCL과 마찬가지로 dispatchKeyEvent가 필요합니다. ICS 이상에서는 CCL 및 CAF 볼륨 컨트롤이 모두 자동으로 처리됩니다.

CAF를 사용하면 앱 활동 내 휴대전화의 하드 볼륨 버튼을 통해 전송 볼륨을 제어할 수 있으며 지원되는 버전에서 전송할 때 시각적 볼륨 막대도 표시됩니다. CAF는 또한 앱이 전면에 있지 않거나 잠겨 있거나 화면이 꺼져 있어도 하드 볼륨의 볼륨 변경을 처리합니다.

자막

Android KitKat 이상에서는 설정 > 접근성에서 자막 설정을 통해 자막을 맞춤설정할 수 있습니다. 그러나 Android의 이전 버전에는 이 기능이 없습니다. CCL은 이전 버전의 맞춤 설정을 제공하고 KitKat 이상의 시스템 설정을 위임하여 이를 처리합니다.

CAF에서는 자막 환경설정을 변경하는 맞춤 설정을 제공하지 않습니다. 매니페스트와 환경설정 XML에서 CaptionsPreferenceActivity 참조를 삭제해야 합니다.

자막 컨트롤러 변경이 확장된 컨트롤러 UI에 의해 처리되므로 CCL의 TracksChooserDialog는 더 이상 필요하지 않습니다.

CAF의 선택형 자막 API는 v2와 유사합니다.

디버그 로깅

CAF는 디버그 로깅 설정을 제공하지 않습니다.

기타

다음 CCL 기능은 CAF에서 지원되지 않습니다.

  • 재생하기 전에 MediaAuthService를 제공하여 승인 가져오기
  • 구성 가능한 UI 메시지

샘플 앱

Android용 범용 음악 플레이어 (amp) 샘플 앱을 CCL에서 CAF로 이전하기 위한 차이점을 살펴보세요.

CAF를 사용하는 Codelab 튜토리얼샘플 앱도 있습니다.