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
- AndroidX Media3 ExoPlayer 1.0.0 以上版本,支援 DAI。
建立新的 Android Studio 專案
如要建立 Android Studio 專案,請按照下列步驟操作:
- 啟動 Android Studio。
- 選取「Start a new Android Studio project」。
- 在「選擇專案」頁面中,選取「沒有活動」範本。
- 點選 [下一步]。
- 在「設定專案」頁面中,為專案命名並選取「Java」做為語言。 注意:IMA DAI SDK 適用於 Kotlin,但本指南使用 Java 範例。
- 按一下「完成」。
在專案中新增 ExoPlayer IMA 擴充功能
如要新增 ExoPlayer IMA 擴充功能,請按照下列步驟操作:
在應用程式
build.gradle檔案的dependencies區段中,加入下列匯入項目:dependencies { def media3_version = "1.8.0" implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.8.0")) implementation 'androidx.appcompat:appcompat:1.7.1' implementation "androidx.media3:media3-ui:$media3_version" implementation "androidx.media3:media3-exoplayer:$media3_version" implementation "androidx.media3:media3-exoplayer-hls:$media3_version" implementation "androidx.media3:media3-exoplayer-dash:$media3_version" // The library adds the IMA ExoPlayer integration for ads. implementation "androidx.media3:media3-exoplayer-ima:$media3_version" }新增 IMA DAI SDK 請求廣告時所需的使用者權限:
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
設定 ExoPlayer UI
如要設定 ExoPlayer UI,請按照下列步驟操作:
為 ExoPlayer 建立
PlayerView物件。將
androidx.constraintlayout.widget.ConstraintLayout檢視畫面變更為LinearLayout檢視畫面,如 ExoPlayer IMA 擴充功能建議:<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" 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:fitsSystemWindows="true" android:layout_width="match_parent" android:layout_height="wrap_content" /> <!-- UI element for viewing SDK event log --> <TextView android:id="@+id/logText" android:gravity="bottom" android:layout_width="match_parent" android:layout_height="wrap_content" android:maxLines="100" android:scrollbars="vertical" android:textSize="@dimen/font_size"> </TextView> </LinearLayout>
新增串流參數
如要測試專案,請參閱 IMA 範例串流頁面,取得範例串流資產。如要設定自己的串流,請參閱動態廣告插播的 Ad Manager 專區。
這個步驟會設定直播。ExoPlayer IMA 擴充功能也支援動態廣告插播 VOD 串流。如要瞭解應用程式需要進行哪些變更才能支援隨選影片串流,請參閱隨選影片串流的步驟。
匯入 ExoPlayer IMA 擴充功能
新增 ExoPlayer 擴充功能的下列匯入陳述式:
import static androidx.media3.common.C.CONTENT_TYPE_HLS; import android.annotation.SuppressLint; import android.app.Activity; import android.net.Uri; import android.os.Bundle; import android.text.method.ScrollingMovementMethod; import android.util.Log; import android.widget.TextView; 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.ui.PlayerView; import com.google.ads.interactivemedia.v3.api.AdEvent; import com.google.ads.interactivemedia.v3.api.ImaSdkFactory; import com.google.ads.interactivemedia.v3.api.ImaSdkSettings; import java.util.HashMap; import java.util.Map;在
MyActivity.java中新增下列私有變數:PlayerViewExoPlayerImaServerSideAdInsertionMediaSource.AdsLoaderImaServerSideAdInsertionMediaSource.AdsLoader.State
如要使用 Big Buck Bunny (Live) HLS 串流進行測試,請新增素材資源金鑰。 如要測試更多串流,請前往 IMA 的範例串流頁面。
建立
KEY_ADS_LOADER_STATE常數,儲存及擷取AdsLoader狀態:/** Main Activity. */ @SuppressLint("UnsafeOptInUsageError") /* @SuppressLint is needed for new media3 APIs. */ 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 LOG_TAG = "ImaExoPlayerExample"; private PlayerView playerView; private TextView logText; private ExoPlayer player; private ImaServerSideAdInsertionMediaSource.AdsLoader adsLoader; private ImaServerSideAdInsertionMediaSource.AdsLoader.State adsLoaderState; private ImaSdkSettings imaSdkSettings;
建立 adsLoader 執行個體
覆寫 onCreate 方法。在該檔案中找出 PlayerView,並檢查是否有已儲存的 AdsLoader.State。
初始化 adsLoader 物件時,可以使用這個狀態。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
// 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。
// Create a server side ad insertion (SSAI) AdsLoader.
private ImaServerSideAdInsertionMediaSource.AdsLoader createAdsLoader() {
ImaServerSideAdInsertionMediaSource.AdsLoader.Builder adsLoaderBuilder =
new ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(this, playerView);
// Attempts to set the AdsLoader state if available from a previous session.
if (adsLoaderState != null) {
adsLoaderBuilder.setAdsLoaderState(adsLoaderState);
}
return adsLoaderBuilder
.setAdEventListener(buildAdEventListener())
.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 a SimpleExoPlayer and set it as the player for content and ads.
player = new ExoPlayer.Builder(this).setMediaSourceFactory(mediaSourceFactory).build();
playerView.setPlayer(player);
adsLoader.setPlayer(player);
// Create the MediaItem to play, specifying the stream URI.
Uri ssaiUri = buildLiveStreamUri(SAMPLE_ASSET_KEY, CONTENT_TYPE_HLS);
MediaItem ssaiMediaItem = MediaItem.fromUri(ssaiUri);
// 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);
}
/**
* Builds an IMA SSAI live stream URI for the given asset key and format.
*
* @param assetKey The asset key of the live stream.
* @param format The format of the live stream request, either {@code CONTENT_TYPE_HLS} or {@code
* CONTENT_TYPE_DASH}.
* @return The URI of the live stream.
*/
public Uri buildLiveStreamUri(String assetKey, int format) {
Map<String, String> adTagParams = new HashMap<String, String>();
// Update the adTagParams map with any parameters.
// For more information, see https://support.google.com/admanager/answer/7320899
return new ImaServerSideAdInsertionUriBuilder()
.setAssetKey(assetKey)
.setFormat(format)
.setAdTagParameters(adTagParams)
.build();
}
新增釋放播放器的方法
新增釋放播放器的方法。這個方法必須依序執行下列動作:
- 將播放器參照設為空值,並釋放播放器的資源。
- 釋出
adsLoader狀態。
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 API 級別 24 以上,請使用下列方法:
如果是 Android API 級別 24 之前的版本,請使用下列方法:
onStart() 和 onResume() 方法會對應至 playerView.onResume(),而 onStop() 和 onPause() 則會對應至 playerView.onPause()。
這個步驟也會使用
onSaveInstanceState()
事件儲存 adsLoaderState。
@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 串流新增
CMS ID和Video ID。 如要進行測試,請使用下列串流參數:- CMS ID:
"2548831" - 影片 ID:
"tears-of-steel"
- CMS ID:
使用
ImaServerSideAdInsertionUriBuilder()方法建立 SSAI VOD URI:/** * Builds an IMA SSAI VOD stream URI for the given CMS ID, video ID, and format. * * @param cmsId The CMS ID of the VOD stream. * @param videoId The video ID of the VOD stream. * @param format The format of the VOD stream request, either {@code CONTENT_TYPE_HLS} or {@code * CONTENT_TYPE_DASH}. * @return The URI of the VOD stream. */ public Uri buildVodStreamUri(String cmsId, String videoId, int format) { Map<String, String> adTagParams = new HashMap<String, String>(); // Update the adTagParams map with any parameters. // For more information, see https://support.google.com/admanager/answer/7320899 return new ImaServerSideAdInsertionUriBuilder() .setContentSourceId(cmsId) .setVideoId(videoId) .setFormat(format) .setAdTagParameters(adTagParams) .build(); }使用
MediaItem.fromUri()方法,將新的 VOD 串流 URI 設為播放器的媒體項目。
如果成功,您可以使用 ExoPlayer IMA 擴充功能要求及播放媒體串流。如需完整範例,請參閱 GitHub 上的 Android DAI 範例。
