
Google IMA DAI SDK Android 接入指南基于 Media3 ExoPlayer 的 ImaServerSideAdInsertionMediaSource 实战【免费下载链接】skillsAgent Skills for Google products and technologies项目地址: https://gitcode.com/GitHub_Trending/skills29/skills本文是 ima-dai-sdk 技能中 Android 平台的完整接入指南讲解如何通过 Media3 ExoPlayer IMA 扩展androidx.media3:media3-exoplayer-ima中的ImaServerSideAdInsertionMediaSource类请求并播放 Google 全托管 DAIDynamic Ad Insertion动态广告插播的直播流Livestream与点播流VOD。读完本文你将掌握从 Gradle 依赖配置、权限声明、UI 集成、SDK 早期初始化、可复用AdsLoader构建、广告事件监听到直播/VOD 流请求与资源回收的完整实现链路可直接照搬代码接入自己的 Android 播放器应用。背景为什么使用 ImaServerSideAdInsertionMediaSourceGoogle 全托管 DAI 在服务端将广告无缝拼接进内容流客户端拿到的是内容与广告合一的单一流因此播放器端不需要自行切流广告体验与内容播放完全一致。在 Android 平台上Media3 提供的ImaServerSideAdInsertionMediaSource正是承担这一职责的桥接组件它包装普通的MediaSource识别带 DAI 参数的 URI驱动 IMA DAI SDK 建立 DAI 会话stream session并让广告 UI、事件回调与ExoPlayer的播放状态保持同步。按照仓库中 SKILL.md 的定义该技能适用于以下场景应用需要加载并播放 HLS 或 DASH 格式的流Web、Android、iOS、tvOS、Cast、Roku 等多平台。应用需要基于 Google DAI 直播事件的asset key或点播的content source (CMS) ID video ID发起流请求。同时 SKILL.md 也明确了一个边界本技能不用于加载和播放 VAST/VMAP URL那是 IMA 客户端侧广告的职责见仓库中的 ima-sdk-client-side 技能。从整体流程看Android 端接入的核心工作流与其他平台一致导入 SDK → 初始化 SDK → 添加流/广告事件监听 → 处理定时元数据 → 发起流请求 → 流失败或用户离开时清理资源。下文按此主线逐步展开。1. 添加依赖Dependencies在build.gradle中引入 Media3 ExoPlayer IMA 扩展。该组件会自动导入 IMA DAI SDKapply plugin: com.android.application android { compileOptions { // IMA SDK v3.37.0 所必需 coreLibraryDesugaringEnabled true } defaultConfig { minSdkVersion(23) } } repositories { google() mavenCentral() } dependencies { implementation(androidx.media3:media3-ui) implementation(androidx.media3:media3-exoplayer) implementation(androidx.media3:media3-exoplayer-hls) implementation(androidx.media3:media3-exoplayer-dash) implementation(androidx.media3:media3-exoplayer-ima) }对各依赖模块的作用说明如下模块作用media3-ui提供PlayerView播放器视图组件用于渲染画面并承载广告 UI 元素media3-exoplayerExoPlayer 播放核心负责流的加载、解码与渲染media3-exoplayer-hlsHLSM3U8流解析支持DAI 直播/点播流默认即 HLS 格式media3-exoplayer-dashDASHMPD流解析支持当使用 DASH 格式的 DAI 流时需要media3-exoplayer-imaExoPlayer IMA 扩展提供ImaServerSideAdInsertionMediaSource并自动引入 IMA DAI SDK两个值得注意的配置项coreLibraryDesugaringEnabled trueIMA SDK v3.37.0 及以上版本使用了部分 Java 8 API需要通过核心库脱糖core library desugaring在低版本 Android 上提供这些 API。这是文档明确标注的硬性要求漏配会导致构建或运行期NoSuchMethodError之类的兼容性问题。minSdkVersion(23)即 Android 6.0。如需支持更低版本需要额外评估 IMA DAI SDK 与 Media3 的兼容范围。版本号建议使用 Media3 官方发布说明中标注的最新稳定版本保持media3-*各模块版本一致避免混用不同版本导致的不兼容。2. 声明 IMA DAI SDK 所需权限在AndroidManifest.xml中声明 IMA DAI SDK 运行所需的权限。DAI SDK 需要感知网络状态以正确处理流加载、超时与错误恢复因此至少需要网络状态访问权限uses-permission android:nameandroid.permission.ACCESS_NETWORK_STATE/如果你的应用需要直接访问网络获取流通常还应一并声明android.permission.INTERNET多数应用已有。文档明确给出的最小要求是ACCESS_NETWORK_STATE。3. UI 设置PlayerView 接入在布局中放置PlayerView它是广告 UI 渲染与播放画面展示的容器。最简单的方式是在 XML 中声明androidx.media3.ui.PlayerView android:idid/player_view /如果项目使用 Jetpack Compose则需要用AndroidView将PlayerView包装进组合函数并在工厂函数中把ExoPlayer实例绑定到PlayerViewAndroidView( factory { ctx - PlayerView(ctx).apply { player exoPlayer } }, update { playerView - playerView.player exoPlayer } )update回调用于在重组或 player 实例变化时同步最新的ExoPlayer确保 UI 与播放器生命周期一致。4. 尽早初始化 IMA SDKEarly SDK Initialization为最大程度缩短首次流的加载时间应在应用生命周期尽可能早的阶段初始化 IMA SDK例如Application.onCreate()或主Activity的onCreate()中。初始化方式为通过单例工厂ImaSdkFactory.getInstance()创建ImaSdkSettings配置对象再调用imaSdkFactory.initialize(...)完成初始化。将创建好的ImaSdkSettings保存下来供后续复用后续构建AdsLoader时仍会用到同一份配置val imaSdkFactory ImaSdkFactory.getInstance() val sharedImaSdkSettings: ImaSdkSettings imaSdkFactory.createImaSdkSettings() imaSdkFactory.initialize(this, sharedImaSdkSettings)ImaSdkSettings承载 SDK 的全局配置项例如调试开关、日志级别等统一在一处创建并贯穿 SDK 生命周期既能避免重复配置也能保证AdsLoader与初始化时使用一致的 SDK 行为。5. 创建可复用的 AdsLoaderImaServerSideAdInsertionMediaSource.AdsLoader是驱动 DAI 会话的核心对象负责发起流请求、接收广告事件并与播放器交互。构建时通过 Builder 模式提供以下要素PlayerView用于广告 UI 元素的渲染承载ImaSdkSettings复用第 4 步中初始化时创建的同一份配置。val playerView findViewById(R.id.player_view) val adsLoaderBuilder ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(this, playerView) val adsLoader adsLoaderBuilder .setAdEventListener(buildAdEventListener()) .setImaSdkSettings(sharedImaSdkSettings) .build()要点AdsLoader应当作为长生命周期对象复用而不是每次播放新建——同一个AdsLoader可以服务多次 DAI 流请求这也是本文标题中可复用reusable的含义。6. 监听流事件与广告事件通过实现AdEvent.AdEventListener处理 DAI 流生命周期中的各类事件并在构建AdsLoader时通过.setAdEventListener(...)注入。下面是一个覆盖完整事件面并避免日志刷屏的典型实现val adEventListener AdEvent.AdEventListener { event - when (event.type) { AdEvent.AdEventType.LOADED, AdEvent.AdEventType.CUEPOINTS_CHANGED, AdEvent.AdEventType.AD_BREAK_STARTED, AdEvent.AdEventType.AD_BREAK_ENDED, AdEvent.AdEventType.AD_PERIOD_STARTED, AdEvent.AdEventType.AD_PERIOD_ENDED, AdEvent.AdEventType.STARTED, AdEvent.AdEventType.FIRST_QUARTILE, AdEvent.AdEventType.MIDPOINT, AdEvent.AdEventType.THIRD_QUARTILE, AdEvent.AdEventType.COMPLETED, AdEvent.AdEventType.PAUSED, AdEvent.AdEventType.RESUMED, AdEvent.AdEventType.SKIPPABLE_STATE_CHANGED, AdEvent.AdEventType.SKIPPED, AdEvent.AdEventType.CLICKED - Log.i(LOG_TAG, Ad event: ${event.type}) AdEvent.AdEventType.AD_PROGRESS - { // 广告播放期间周期性触发的高频事件忽略以避免日志刷屏 } else - Log.i(LOG_TAG, Unhandled ad event: ${event.type}) } }各事件类型的业务含义事件含义LOADED广告已加载完成CUEPOINTS_CHANGED流中的提示点cuepoints发生变化可用于更新播放进度条中的广告标记AD_BREAK_STARTED/AD_BREAK_ENDED广告插播开始 / 结束可在此禁用 / 恢复播放控制如 seekAD_PERIOD_STARTED/AD_PERIOD_ENDED广告时段开始 / 结束流级别的事件STARTED/FIRST_QUARTILE/MIDPOINT/THIRD_QUARTILE/COMPLETED广告播放的进度里程碑开始、1/4、1/2、3/4、完成PAUSED/RESUMED广告暂停 / 恢复SKIPPABLE_STATE_CHANGED/SKIPPED广告可跳过状态变化 / 广告被用户跳过CLICKED用户点击广告通常应引导到广告落地页AD_PROGRESS广告播放期间的周期性进度事件高频触发不应在其中执行重逻辑或记录日志需要注意AD_PROGRESS在广告播放期间会以较高频率持续触发直接打日志会刷爆 Logcat 并影响性能文档中的实现特意将其单独处理为忽略。这是实践中容易踩坑的点。7. 用 SSAI MediaSource Factory 初始化 ExoPlayerImaServerSideAdInsertionMediaSource需要挂在 Media3 的 MediaSource 解析链上才能生效。组装过程分为四步创建DataSource.Factory负责底层取流网络请求基于它创建DefaultMediaSourceFactory根据 URI 自动选择对应的MediaSourceHLS/DASH/Progressive 等用AdsLoader和该工厂构建ImaServerSideAdInsertionMediaSource.Factory将 SSAI 工厂注册进DefaultMediaSourceFactory再用它构建ExoPlayer。val dataSourceFactory: DataSource.Factory DefaultDataSource.Factory(this) val mediaSourceFactory DefaultMediaSourceFactory(dataSourceFactory) val adsMediaSourceFactory ImaServerSideAdInsertionMediaSource.Factory(adsLoader, mediaSourceFactory) mediaSourceFactory.setServerSideAdInsertionMediaSourceFactory(adsMediaSourceFactory) player ExoPlayer.Builder(this) .setMediaSourceFactory(mediaSourceFactory) .build() adsLoader.setPlayer(player)这里有一条必须遵守的时序约束在调用ExoPlayer.setMediaItem()传入ImaServerSideAdInsertionUri见下一节之前必须先调用AdsLoader.setPlayer(player)将ExoPlayer实例交给AdsLoader。原因是 DAI 会话建立后AdsLoader需要与 player 保持状态同步播放进度、暂停状态、广告 UI 展示等顺序颠倒会导致 DAI 会话与播放器脱钩。从调用链看整个机制可以概括为播放器请求一个带 DAI 参数的 URI →DefaultMediaSourceFactory识别出这是 SSAI URI → 交由ImaServerSideAdInsertionMediaSource.Factory拦截 → 该工厂驱动AdsLoader发起 DAI 流请求并返回最终可播放的MediaSource。AdsLoader是整个链路的会话中枢。8. 请求直播流Livestream使用ImaServerSideAdInsertionUriBuilder构造直播流 URI需要提供network code与asset key两个参数并通过setFormat指定流的封装格式HLS 用C.CONTENT_TYPE_HLSDASH 用C.CONTENT_TYPE_DASHval liveStreamUri: Uri ImaServerSideAdInsertionUriBuilder() .setNetworkCode(NETWORK_CODE_PLACEHOLDER) .setAssetKey(ASSET_KEY_PLACEHOLDER) .setFormat(androidx.media3.common.C.CONTENT_TYPE_HLS) .build() val liveStreamMediaItem: MediaItem MediaItem.fromUri(liveStreamUri) player.setMediaItem(liveStreamMediaItem)占位参数的实际来源NETWORK_CODE_PLACEHOLDERnetwork codeGoogle Ad Manager 网络代码是广告投放单元的租户标识可从 Ad Manager 后台获取。ASSET_KEY_PLACEHOLDERasset key在 Google Ad Manager 中为直播事件livestream event配置的资产密钥用于唯一标识一个 DAI 直播会话。构造完成后将 URI 包装为MediaItem并交给 player 播放即可。整个请求、DAI 会话建立、广告拼接均由 SDK 在后台完成。点播流VODVOD 流的构建方式与直播流类似区别在于标识参数由asset key换成content source ID video IDval vodStreamUri: Uri ImaServerSideAdInsertionUriBuilder() .setNetworkCode(NETWORK_CODE_PLACEHOLDER) .setContentSourceId(CONTENT_SOURCE_ID_PLACEHOLDER) .setVideoId(VIDEO_ID_PLACEHOLDER) .setFormat(androidx.media3.common.C.CONTENT_TYPE_HLS) .build() val vodStreamItem: MediaItem MediaItem.fromUri(vodStreamUri) player.setMediaItem(vodStreamItem)VOD 参数的来源CONTENT_SOURCE_ID_PLACEHOLDERcontent source ID / CMS IDGoogle Ad Manager 中内容源的标识即 CMS ID。VIDEO_ID_PLACEHOLDERvideo ID该内容在 CMS 中的视频 ID。二者共同定位到 Ad Manager 中已配置的某一条点播内容SDK 据此为其动态插入广告。联调提示测试阶段可使用 Google Ad Manager DAI 官方文档中提供的 DAI 示例流sample streams参数进行验证无需预先配置真实内容。9. 清理 SDK 资源Clean Up当释放播放器或处理流错误时必须调用ImaServerSideAdInsertionMediaSource.AdsLoader.release()来拆除当前活动的 DAI 会话避免资源泄漏adsLoader?.setPlayer(null) adsLoaderState adsLoader?.release()两个动作的含义setPlayer(null)解除AdsLoader与当前ExoPlayer的绑定release()释放当前 DAI 会话相关资源并返回一个AdsLoader.State对象。保存返回的State对象在配置变更如屏幕旋转导致 Activity 重建时可以通过该State恢复播放器让 DAI 会话在重建过程中不中断。这是多屏幕尺寸/横竖屏适配场景下的标准做法。10. 本指南在仓库中的定位与其他平台对照本指南是 ima-dai-sdk 技能下 Android 平台的分平台参考文档与该技能的通用元数据、其他平台指南共同构成一个完整的多端接入体系平台参考文档核心 APIAndroidandroid-ImaServerSideAdInsertionMediaSource-guide.md本文ImaServerSideAdInsertionMediaSourceAdsLoaderWeb/HTML5web-StreamManager-guide.mdgoogle.ima.dai.api.StreamManagerLiveStreamRequest/VODStreamRequestChromeCastcast-StreamManager-guide.mdgoogle.ima.cast.dai.api.StreamManageriOS/tvOSios-IMAStreamRequest-guide.mdIMALiveStreamRequest/IMAVODStreamRequestAVPlayerRokuroku-StreamManager-guide.mdCreateLiveStreamRequest/CreateVodStreamRequest对比可见各平台虽然 API 形态不同Android 是 MediaSource 体系、iOS 是IMAStreamRequest、Web 是StreamManager但业务参数完全一致——直播用 network code asset key点播用 network code content source ID video ID。这与 Web 端指南中LiveStreamRequest.assetKey/networkCode、iOS 端IMALiveStreamRequest(assetKey:networkCode:...)的参数设计一一对应说明 DAI 的流标识模型是跨平台统一的。与 Web 端不同的一点是Web 指南要求开发者手动从播放器事件中提取定时元数据HLS 的 ID3 帧、DASH 的自定义事件并调用streamManager.processMetadata()交给 SDK而在 Android 端由于 DAI 能力内嵌于ImaServerSideAdInsertionMediaSource的 MediaSource 链路中定时元数据的处理由扩展随流解析自动完成接入方无需手工转发这也是选择该扩展而非裸用 IMA DAI SDK 的主要收益之一。11. 参考实现官方提供了一个完整的 Android 示例工程googleads-ima-android-dai 仓库中的ExoPlayerExample其中包含两个关键文件可直接对照ExoPlayerExample/app/src/main/res/layout/activity_my.xml布局文件展示了PlayerView在 Activity 布局中的组织方式ExoPlayerExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/MyActivity.javaActivity 实现展示了 SDK 初始化、AdsLoader构建、事件监听、直播/点播流请求与清理的完整流程。建议在集成本指南代码时将示例工程作为可运行的行为基准进行对照与验证。12. 接入要点回顾依赖完整media3-exoplayer-ima会自动引入 IMA DAI SDK但 HLS/DASH 解析模块需按流格式显式引入IMA SDK v3.37.0 要求开启coreLibraryDesugaringEnabled。尽早初始化在Application.onCreate()阶段完成ImaSdkFactory.initialize()并复用同一份ImaSdkSettings。AdsLoader 单例复用AdsLoader贯穿应用生命周期一次构建、多次服务流请求。时序敏感adsLoader.setPlayer(player)必须先于player.setMediaItem(ssaiUri)调用。事件面完整用AdEvent.AdEventListener覆盖广告全生命周期事件并单独降噪处理高频的AD_PROGRESS。参数模型统一直播 network code asset keyVOD network code content source ID video ID。必须清理释放播放器或流出错时调用adsLoader.release()并保存State以支持配置变更后的会话恢复。【免费下载链接】skillsAgent Skills for Google products and technologies项目地址: https://gitcode.com/GitHub_Trending/skills29/skills创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考