ExoPlayer IMA 확장 프로그램 시작하기

ExoPlayer는 Android용 애플리케이션 수준 미디어 플레이어입니다. 이 가이드에서는 IMA Android DAI SDK를 래핑하는 ExoPlayer IMA 확장 프로그램을 사용하여 광고와 콘텐츠가 모두 포함된 미디어 스트림을 요청하고 재생하는 방법을 보여줍니다.

확장 프로그램의 이점은 다음과 같습니다.

  • IMA와 기능을 통합하는 데 필요한 코드가 간단해집니다.
  • 새 버전의 IMA로 업데이트하는 데 필요한 개발 시간이 줄어듭니다.

ExoPlayer IMA 확장 프로그램은 HLS 및 DASH 스트리밍 프로토콜을 지원합니다. 요약하면 다음과 같습니다.

ExoPlayer-IMA 확장 프로그램 스트림 지원
라이브 스트림 VOD 스트림
HLS 체크표시 체크표시
DASH 체크표시 체크표시

DASH 라이브 스트림은 ExoPlayer-IMA 버전 1.1.0 이상에서 지원됩니다.

이 가이드는 ExoPlayer 가이드를 기반으로 하며 전체 앱을 만들고 확장 프로그램을 통합하는 방법을 보여줍니다. 전체 샘플 앱의 예시는 GitHub의 ExoPlayerExample를 참조하세요.

기본 요건

새 Android 스튜디오 프로젝트 만들기

Android 스튜디오 프로젝트를 만들려면 다음 단계를 완료하세요.

  • Android 스튜디오를 시작합니다.
  • Start a new Android Studio project를 선택합니다.
  • Choose your project 페이지에서 No Activity 템플릿을 선택합니다.
  • 다음을 클릭합니다.
  • Configure your project 페이지에서 프로젝트 이름을 지정하고 언어로 Java를 선택합니다.

  • Finish를 클릭합니다.

프로젝트에 ExoPlayer IMA 확장 프로그램 추가

확장 프로그램 가져오기를 dependencies 섹션의 애플리케이션 수준 build.gradle 파일에 추가합니다.

멀티덱스를 사용하도록 앱을 구성하고 사용 설정합니다. 이는 확장 프로그램의 크기로 인해 필요하며 minSdkVersionAndroid 4.4W (API 수준 20) 이하로 설정된 앱에 필요합니다.

예를 들면 다음과 같습니다.

app/build.gradle

android {

  ...

  defaultConfig {
      applicationId "com.google.ads.interactivemedia.v3.samples.videoplayerapp"
      minSdkVersion 19
      targetSdkVersion 34
      multiDexEnabled true
      versionCode 1
      versionName "1.0"
  }

    ...
}
dependencies {
    implementation 'androidx.multidex:multidex:2.0.1'
    implementation 'androidx.media3:media3-ui:1.1.1'
    implementation 'androidx.media3:media3-exoplayer:1.1.1'
    implementation 'androidx.media3:media3-exoplayer-hls:1.1.1'
    implementation 'androidx.media3:media3-exoplayer-dash:1.1.1'

    // Adding the ExoPlayer IMA extension for ads will also include the IMA
    // SDK as a dependency.
    implementation 'androidx.media3:media3-exoplayer-ima:1.1.1'
}

광고를 요청하기 위해 IMA SDK에서 요구하는 사용자 권한을 추가합니다.

app/src/main/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.project name">

    <!-- Required permissions for the IMA SDK -->
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

    ...

</manifest>

인텐트 선언 추가

앱이 Android 11 (API 수준 30) 이상을 타겟팅하는 경우 현재 및 최신 버전의 IMA SDK에서 웹 링크를 열려면 명시적인 인텐트 선언이 필요합니다. 광고 클릭연결을 사용 설정하려면 앱의 매니페스트 파일에 다음 스니펫을 추가합니다 (사용자가 자세히 알아보기 버튼 클릭).

  <?xml version="1.0" encoding="utf-8"?>
  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.example.project name">

      ...

    </application>

    <queries>
      <intent>
          <action android:name="android.intent.action.VIEW" />
          <data android:scheme="https" />
      </intent>
      <intent>
          <action android:name="android.intent.action.VIEW" />
          <data android:scheme="http" />
      </intent>
    </queries>
  </manifest>

ExoPlayer의 UI 설정

ExoPlayer에서 사용할 PlayerView 객체를 만듭니다.

androidx.constraintlayout.widget.ConstraintLayout를 ExoPlayer IMA 확장 프로그램에 권장되는 LinearLayout로 변경합니다.

예를 들면 다음과 같습니다.

app/src/main/res/layout/activity_my.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:background="@android:color/black"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MyActivity"
    tools:ignore="MergeRootFrame">

    <androidx.media3.ui.PlayerView
        android:id="@+id/player_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

스트림 매개변수 추가

프로젝트를 테스트하는 샘플 스트림 애셋은 IMA 샘플 스트림 페이지를 참고하세요. 자체 스트림 설정에 관한 자세한 내용은 DAI의 Ad Manager 섹션도 참고하세요.

이 단계에서는 라이브 스트림을 설정하는 방법을 보여주지만 ExoPlayer IMA 확장 프로그램은 DAI VOD 스트림도 지원합니다. 앱에서 VOD 스트림을 처리하는 데 필요한 변경사항을 확인하려면 VOD 스트림 단계를 참조하세요.

ExoPlayer IMA 확장 프로그램 가져오기

ExoPlayer 확장 프로그램의 import 문을 추가합니다.

다음 비공개 변수를 MyActivity.java에 추가합니다.

Big Buck Bunny (실시간) HLS 스트림의 애셋 키를 추가하여 이 스트림으로 테스트합니다. IMA의 샘플 스트림 페이지에서 더 많은 스트림을 테스트할 수 있습니다.

KEY_ADS_LOADER_STATE 상수를 만들어 AdsLoader 상태를 저장하고 가져옵니다.

예를 들면 다음과 같습니다.

app/src/main/java/com/example/project name/MyActivity.java


import static androidx.media3.common.C.CONTENT_TYPE_HLS;

import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.annotation.OptIn;
import androidx.media3.common.MediaItem;
import androidx.media3.common.util.Util;
import androidx.media3.datasource.DataSource;
import androidx.media3.datasource.DefaultDataSource;
import androidx.media3.exoplayer.ExoPlayer;
import androidx.media3.exoplayer.ima.ImaServerSideAdInsertionMediaSource;
import androidx.media3.exoplayer.ima.ImaServerSideAdInsertionUriBuilder;
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory;
import androidx.media3.exoplayer.util.EventLogger;
import androidx.media3.ui.PlayerView;
import androidx.multidex.MultiDex;

...

public class MyActivity extends Activity {

  private static final String KEY_ADS_LOADER_STATE = "ads_loader_state";
  private static final String SAMPLE_ASSET_KEY = "c-rArva4ShKVIAkNfy6HUQ";

  private PlayerView playerView;
  private ExoPlayer player;
  private ImaServerSideAdInsertionMediaSource.AdsLoader adsLoader;
  private ImaServerSideAdInsertionMediaSource.AdsLoader.State adsLoaderState;

}

adsLoader 인스턴스 만들기

onCreate 메서드를 덮어쓰기하여 PlayerView를 찾고 저장된 AdsLoader.State를 확인합니다. 이는 adsLoader 객체를 시작할 때 사용할 수 있습니다.

또한 2단계에 설명된 대로 앱의 메서드 수 및 minSdkVersion에 필요한 경우 멀티덱스를 사용 설정합니다.

예를 들면 다음과 같습니다.

app/src/main/java/com/example/project name/MyActivity.java

...

public class MyActivity extends Activity {

  private static final String KEY_ADS_LOADER_STATE = "ads_loader_state";
  private static final String SAMPLE_ASSET_KEY = "c-rArva4ShKVIAkNfy6HUQ";

  private PlayerView playerView;
  private ExoPlayer player;
  private ImaServerSideAdInsertionMediaSource.AdsLoader adsLoader;
  private ImaServerSideAdInsertionMediaSource.AdsLoader.State adsLoaderState;

  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my);
    MultiDex.install(this);

    playerView = findViewById(R.id.player_view);

    // Checks if there is a saved AdsLoader state to be used later when
    // initiating the AdsLoader.
    if (savedInstanceState != null) {
      Bundle adsLoaderStateBundle = savedInstanceState.getBundle(KEY_ADS_LOADER_STATE);
      if (adsLoaderStateBundle != null) {
        adsLoaderState =
            ImaServerSideAdInsertionMediaSource.AdsLoader.State.CREATOR.fromBundle(
                adsLoaderStateBundle);
      }
    }
  }

}

플레이어 초기화 메서드 추가

플레이어를 초기화하는 메서드를 추가하고 다음 작업을 실행합니다.

  • AdsLoader 인스턴스를 만듭니다.
  • ExoPlayer을 만듭니다.
  • 실시간 스트림의 애셋 키로 MediaItem를 만듭니다.
  • MediaItem를 플레이어로 설정합니다.

예를 들면 다음과 같습니다.

app/src/main/java/com/example/project name/MyActivity.java

public class MyActivity extends Activity {

  ...

  
  // Create a server side ad insertion (SSAI) AdsLoader.
  private ImaServerSideAdInsertionMediaSource.AdsLoader createAdsLoader() {
    ImaServerSideAdInsertionMediaSource.AdsLoader.Builder adsLoaderBuilder =
        new ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(this, playerView);

    // Attempt to set the AdsLoader state if available from a previous session.
    if (adsLoaderState != null) {
      adsLoaderBuilder.setAdsLoaderState(adsLoaderState);
    }

    return adsLoaderBuilder.build();
  }

  private void initializePlayer() {
    adsLoader = createAdsLoader();

    // Set up the factory for media sources, passing the ads loader.
    DataSource.Factory dataSourceFactory = new DefaultDataSource.Factory(this);
    DefaultMediaSourceFactory mediaSourceFactory = new DefaultMediaSourceFactory(dataSourceFactory);

    // MediaSource.Factory to create the ad sources for the current player.
    ImaServerSideAdInsertionMediaSource.Factory adsMediaSourceFactory =
        new ImaServerSideAdInsertionMediaSource.Factory(adsLoader, mediaSourceFactory);

    // 'mediaSourceFactory' is an ExoPlayer component for the DefaultMediaSourceFactory.
    // 'adsMediaSourceFactory' is an ExoPlayer component for a MediaSource factory for IMA server
    // side inserted ad streams.
    mediaSourceFactory.setServerSideAdInsertionMediaSourceFactory(adsMediaSourceFactory);

    // Create an ExoPlayer and set it as the player for content and ads.
    player = new ExoPlayer.Builder(this).setMediaSourceFactory(mediaSourceFactory).build();
    playerView.setPlayer(player);
    adsLoader.setPlayer(player);

    // Build an IMA SSAI media item to prepare the player with.
    Uri ssaiLiveUri =
        new ImaServerSideAdInsertionUriBuilder()
            .setAssetKey(SAMPLE_ASSET_KEY)
            .setFormat(CONTENT_TYPE_HLS) // Use CONTENT_TYPE_DASH for dash streams.
            .build();

    // Create the MediaItem to play, specifying the stream URI.
    MediaItem ssaiMediaItem = MediaItem.fromUri(ssaiLiveUri);

    // Prepare the content and ad to be played with the ExoPlayer.
    player.setMediaItem(ssaiMediaItem);
    player.prepare();

    // Set PlayWhenReady. If true, content and ads will autoplay.
    player.setPlayWhenReady(false);
  }
}

플레이어를 해제하는 메서드 추가

다음 순서로 플레이어를 해제하는 메서드를 추가합니다.

  • 플레이어 참조를 null로 설정하고 플레이어의 리소스를 해제합니다.
  • adsLoader의 상태를 해제합니다.

app/src/main/java/com/example/project name/MyActivity.java

public class MyActivity extends Activity {

  ...

  private void releasePlayer() {
    // Set the player references to null and release the player's resources.
    playerView.setPlayer(null);
    player.release();
    player = null;

    // Release the adsLoader state so that it can be initiated again.
    adsLoaderState = adsLoader.release();
  }

플레이어 이벤트 처리

마지막으로 활동의 수명 주기 이벤트에 관한 콜백을 만들어 스트림 재생을 처리합니다.

Android SDK 버전 24 이상을 지원하려면 다음을 실행합니다.

Android SDK 버전 24 미만을 지원하려면 다음을 실행합니다. - onResume() - onPause()

onStart()onResume()playerView.onResume()에 매핑되고 onStop()onPause()playerView.onPause()에 매핑됩니다.

또한 이 단계에서는 onSaveInstanceState() 이벤트를 사용하여 adsLoaderState를 저장하려고 시도합니다.

app/src/main/java/com/example/project name/MyActivity.java

public class MyActivity extends Activity {

  ...

  @Override
  public void onStart() {
    super.onStart();
    if (Util.SDK_INT > 23) {
      initializePlayer();
      if (playerView != null) {
        playerView.onResume();
      }
    }
  }

  @Override
  public void onResume() {
    super.onResume();
    if (Util.SDK_INT <= 23 || player == null) {
      initializePlayer();
      if (playerView != null) {
        playerView.onResume();
      }
    }
  }

  @Override
  public void onPause() {
    super.onPause();
    if (Util.SDK_INT <= 23) {
      if (playerView != null) {
        playerView.onPause();
      }
      releasePlayer();
    }
  }

  @Override
  public void onStop() {
    super.onStop();
    if (Util.SDK_INT > 23) {
      if (playerView != null) {
        playerView.onPause();
      }
      releasePlayer();
    }
  }

  @Override
  public void onSaveInstanceState(Bundle outState) {
    // Attempts to save the AdsLoader state to handle app backgrounding.
    if (adsLoaderState != null) {
      outState.putBundle(KEY_ADS_LOADER_STATE, adsLoaderState.toBundle());
    }
  }

  ...

}

VOD 스트림 설정 (선택사항)

앱에서 광고가 포함된 VOD 콘텐츠를 재생해야 하는 경우 다음을 수행해야 합니다.

  1. VOD 테스트 스트림에 CMS IDVideo ID를 추가합니다.
  2. ImaServerSideAdInsertionUriBuilder()를 사용하여 SSAI VOD URI를 만듭니다.
  3. 이 새 URI를 플레이어의 미디어 항목으로 사용합니다.

app/src/main/java/com/example/project name/MyActivity.java

public class MyActivity extends Activity {

  private static final String KEY_ADS_LOADER_STATE = "ads_loader_state";
  private static final String SAMPLE_ASSET_KEY = "c-rArva4ShKVIAkNfy6HUQ";
  private static final String SAMPLE_CMS_ID = "2528370";
  private static final String SAMPLE_VIDEO_ID = "tears-of-steel";

  ...

  private void initializePlayer() {

     ...

    Uri ssaiVodUri =
        new ImaServerSideAdInsertionUriBuilder()
            .setContentSourceId(SAMPLE_CMS_ID)
            .setVideoId(SAMPLE_VIDEO_ID)
            .setFormat(CONTENT_TYPE_HLS)
            .build();

    // Create the MediaItem to play, specifying the stream URI.
    MediaItem ssaiMediaItem = MediaItem.fromUri(ssaiVodUri);

    // Prepare the content and ad to be played with the ExoPlayer.
    player.setMediaItem(ssaiMediaItem);
    player.prepare();

    // Set PlayWhenReady. If true, content and ads will autoplay.
    player.setPlayWhenReady(false);
  }

작업이 끝났습니다. 이제 ExoPlayer IMA 확장 프로그램을 사용하여 미디어 스트림을 요청하고 재생합니다. 전체 코드는 GitHub의 Android DAI 샘플에서 확인하세요.