開始使用 ExoPlayer IMA 擴充功能

ExoPlayer 是 應用程式層級的媒體播放器本指南說明如何使用 ExoPlayer IMA 擴充功能 來納入 IMA DAI SDK,以便請求及播放媒體串流 廣告與內容

以下是擴充功能的幾項優點:

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

ExoPlayer IMA 擴充功能支援 HLS 和 DASH 串流通訊協定。請參考 摘要:

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

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

本指南是以 ExoPlayer 模型為基礎 指南和節目 如何建立完整應用程式並整合擴充功能。詳情請參閱 ExoPlayerExample,來源: GitHub,如需 完整的範例應用程式

必要條件

建立新的 Android Studio 專案

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

  • 啟動 Android Studio。
  • 選取「Start a new Android Studio project」(啟動新的 Android Studio 專案)
  • 在「Choose your project」(選擇專案) 頁面中,選取「No Activity」(無活動) 範本。
  • 點選「下一步」。
  • 在「Configure your 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.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 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 範例串流 範例串流頁面 測試專案。另請參閱 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;

...

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 物件

此外,如果應用程式的方法計數和 minSdkVersion 要求提供 Multidex,也請一併啟用 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 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.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);
  }
}

新增方法來釋放播放器

新增依照以下順序釋放播放器的方法:

  • 將玩家參照設為空值,並釋出玩家的資源。
  • 釋出 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 = "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 擴充功能。查看 Android DAI 範例: 前往 GitHub