開始使用 ExoPlayer IMA 擴充功能

透過集合功能整理內容 你可以依據偏好儲存及分類內容。

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

以下是這項擴充功能的一些優點:

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

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

ExoPlayer-IMA 擴充功能串流支援
直播 VOD 串流
HTTP 即時串流 勾號 勾號
資訊主頁 Red-X 勾號

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

必要條件

建立新的 Android Studio 專案

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

  • 啟動 Android Studio。
  • 選取 [啟動新的 Android Studio 專案]。
  • 在「Choose your project」(選擇專案) 頁面中,選取 [No Activity] (無活動) 範本。
  • 按一下「繼續」
  • 在「Configure your project」(設定專案) 頁面中為專案命名,然後選取 Java 做為語言。

  • 按一下「Finish」

將 ExoPlayer IMA 擴充功能新增至專案

將擴充功能的匯入新增至 dependencies 區段中的應用程式層級 build.gradle 檔案。

將應用程式設為啟用並啟用 multidex。由於擴充功能的尺寸,因此這是必要項目。對於 minSdkVersion 設為 Android 4.4W (API 級別 20) 以下版本的應用程式而言,這是必要步驟。

範例如下:

app/build.gradle

android {

  ...

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

    ...
}
dependencies {
    implementation 'androidx.multidex:multidex:2.0.1'
    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'androidx.media3:media3-ui:1.0.0-beta02'
    implementation 'androidx.media3:media3-exoplayer:1.0.0-beta02'
    implementation 'androidx.media3:media3-exoplayer-hls:1.0.0-beta02'
    implementation 'androidx.media3:media3-exoplayer-dash:1.0.0-beta02'

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

新增 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>

設定 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;

...

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 (如步驟 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.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);
  }
}

新增釋出播放器的方法

新增可依此順序推出播放器的方法:

  • 將播放器的參照設定為空值,並釋出播放器的資源。
  • 釋出 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 以上版本:

為了支援 24 以下版本的 Android SDK: - 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 範例以取得完整程式碼。