開始使用 ExoPlayer IMA 擴充功能

ExoPlayer 是 Android 的應用程式層級媒體播放器,本指南說明如何使用 ExoPlayer IMA 擴充功能 (包裝 IMA DAI SDK),請求及播放含有廣告和內容的媒體串流。

擴充功能的優點如下:

  • 簡化整合 IMA 與功能所需的程式碼。
  • 減少更新至新版 IMA 所需的開發時間。

ExoPlayer IMA 擴充功能支援 HLS 和 DASH 串流通訊協定。以下是重點摘要:

ExoPlayer-IMA 擴充功能串流支援
直播 VOD 串流
HLS 勾號 勾號
DASH 勾號 勾號

ExoPlayer-IMA 1.1.0 以上版本支援 DASH 直播。

本指南以 ExoPlayer 指南為基礎,說明如何建立完整應用程式並整合擴充功能。如需完整範例應用程式的範例,請參閱 GitHub 上的 ExoPlayerExample

必要條件

建立新的 Android Studio 專案

如要建立 Android Studio 專案,請完成下列步驟:

  • 啟動 Android Studio。
  • 選取「Start a new Android Studio project」
  • 在「選擇專案」頁面中,選取「沒有活動」範本。
  • 點選 [下一步]。
  • 在「設定專案」頁面中為專案命名,並選取 Java 做為語言。

  • 按一下「完成」

在專案中新增 ExoPlayer IMA 擴充功能

在應用程式層級的 build.gradle 檔案中,於 dependencies 區段新增擴充功能的匯入項目。

設定應用程式並啟用 Multidex。這是因為擴充功能的大小所致,且如果應用程式的 minSdkVersion 設為 Android 4.4W (API 級別 20) 以下版本,就必須這麼做。

範例如下:

app/build.gradle

android {

  ...

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

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

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

新增 IMA DAI 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 DAI SDK -->
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

    ...

</manifest>

新增意圖聲明

如果應用程式指定 Android 11 (API 級別 30) 以上版本,目前和最近版本的 IMA DAI 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 變更為 LinearLayout,建議使用 ExoPlayer IMA 擴充功能。

範例如下:

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 擴充功能的匯入陳述式。

MyActivity.java 中新增下列私有變數:

新增 Big Buck Bunny (Live) 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;
import com.google.ads.interactivemedia.v3.api.ImaSdkFactory;
import com.google.ads.interactivemedia.v3.api.ImaSdkSettings;

...

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 ImaSdkSettings imaSdkSettings;
  private ImaServerSideAdInsertionMediaSource.AdsLoader adsLoader;
  private ImaServerSideAdInsertionMediaSource.AdsLoader.State adsLoaderState;

}

建立 adsLoader 執行個體

覆寫 onCreate 方法,找出 PlayerView 並檢查已儲存的 AdsLoader.State,這可用於啟動 adsLoader 物件。

此外,如果應用程式的方法計數和 minSdkVersion 需要 Multidex,請啟用這項功能 (如步驟 2 所述)。

範例如下:

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

    // Initialize the IMA SDK as early as possible when the app starts. If your app already
    // overrides Application.onCreate(), call this method inside the onCreate() method.
    // https://developer.android.com/topic/performance/vitals/launch-time#app-creation
    ImaSdkFactory.getInstance().initialize(this, getImaSdkSettings());

    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.fromBundle(
                adsLoaderStateBundle);
      }
    }
  }

  private ImaSdkSettings getImaSdkSettings() {
    if (imaSdkSettings == null) {
      imaSdkSettings = ImaSdkFactory.getInstance().createImaSdkSettings();
      // Set any IMA SDK settings here.
    }
    return imaSdkSettings;
  }

}

新增方法來初始化播放器

新增方法來初始化播放器,並執行下列操作:

  • 建立 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
        .setImaSdkSettings(getImaSdkSettings())
        .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);
  }
}

新增釋放播放器的函式

新增方法,依序釋放播放器:

  • 將播放器參照設為空值,並釋放播放器的資源。
  • 釋出 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 以下版本,請按照下列步驟操作:

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 = "2548831";
  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 範例