
interactive_media_ads 插件架构解析与贡献指南从委托模式到 Pigeon SDK 封装【免费下载链接】packagesA collection of useful packages maintained by the Flutter team项目地址: https://gitcode.com/GitHub_Trending/pac/packages本指南以 Flutter 官方维护的interactive_media_ads插件IMA SDK 的 Flutter 封装见 README为对象围绕其 CONTRIBUTING.md 展开深入讲解该插件类联邦式federated-style单仓插件的架构设计、平台接口的类类型约定、基于 Pigeon 的 SDK Wrapper 更新流程以及为插件新增功能的推荐工作流。读完本文你将掌握如何阅读、测试并安全地为该插件扩展 Android / iOS 原生广告能力。一、插件整体架构类联邦式单仓插件interactive_media_ads的结构与 Flutter 生态中的 联邦式插件federated plugin 相似即同样划分为平台接口platform interface、各平台实现platform implementations与面向应用的接口app-facing interface三部分区别在于所有部分的代码都维护在同一个插件内而不是拆分为多个独立包。这种单仓结构带来一个直接好处如果你熟悉在flutter/packages仓库中修改联邦式插件的流程在这里流程几乎一致唯一差别是不需要运行将依赖改为 path 形式的脚本——因为不存在跨包的依赖切换问题。从 pubspec.yaml 可以直观看到这种一个插件承载两端实现的布局flutter: plugin: platforms: android: package: dev.flutter.packages.interactive_media_ads pluginClass: InteractiveMediaAdsPlugin dartPluginClass: AndroidInteractiveMediaAds ios: pluginClass: InteractiveMediaAdsPlugin dartPluginClass: IOSInteractiveMediaAds两个平台通过各自的原生 pluginClass 与 Dart 侧的dartPluginClassAndroidInteractiveMediaAds/IOSInteractiveMediaAds配对Dart 层入口统一收敛在 lib/interactive_media_ads.dart。1.1 设计原则尽量贴近原生 SDK API插件底层直接使用 Android / iOS 的原生 IMA SDK而这两个平台 SDK 的 API 相对相似因此插件刻意维持了一套与原生 SDK 相近的接口。对使用者而言熟悉 IMA 原生 API 的开发者可以几乎零成本迁移到 Flutter 侧。1.2 委托模式Delegation面向应用的接口通过**委托delegation**与底层平台实现交互因此平台接口与面向应用接口在形态上高度相似。大多数面向应用的类会持有一个platform字段用于把处理转发给平台实现// App-facing class used by apps class AdsLoader { AdsLoader.fromPlatform(this.platform); final PlatformAdsLoader platform; Futurevoid requestAds(AdsRequest request) { return platform.requestAds(request); } } // Platform interface class implemented by each platform abstract base class PlatformAdsLoader { Futurevoid requestAds(AdsRequest request); }这段代码在 lib/src/ads_loader.dart 中有完整落地AdsLoader暴露给应用内部final PlatformAdsLoader platform负责真正的调用而AdsLoader的三个构造函数默认构造、fromPlatformCreationParams、fromPlatform正好对应文档中可用平台实现或创建参数实例化的两种路径。platform变量同时被用作访问平台特有方法或平台特有创建参数的入口final AdsLoader loader AdsLoader(); (loader.platform as AndroidAdsLoader).callAndroidSpecificMethod();在 ads_loader.dart 的类注释中同样给出了按InteractiveMediaAdsPlatform.instance的实际类型做is IOSInteractiveMediaAdsPlatform/is AndroidInteractiveMediaAdsPlatform判断、再强转访问平台实现的标准写法。面向应用接口中的其余类与枚举通常会从平台接口直接导出——数据类data class就是最典型的例子这保证了应用侧与平台侧共享同一份数据结构定义。二、平台接口Platform Interface平台接口代码位于lib/src/platform_interface/它声明了每个平台要想被面向应用接口支持所必须实现的契约。2.1 接口设计的三条优先原则在 interactive_media_ads_platform.dart 中InteractiveMediaAdsPlatform被定义为abstract base class并持有唯一静态入口static InteractiveMediaAdsPlatform? instance;该抽象基类声明的全部方法都是创建型方法统一返回对应的平台类实例createPlatformAdsLoader(PlatformAdsLoaderCreationParams params)createPlatformAdsManagerDelegate(PlatformAdsManagerDelegateCreationParams params)createPlatformAdDisplayContainer(PlatformAdDisplayContainerCreationParams params)createPlatformContentProgressProvider(PlatformContentProgressProviderCreationParams params)createPlatformAdsRenderingSettings(PlatformAdsRenderingSettingsCreationParams params)createPlatformCompanionAdSlot(PlatformCompanionAdSlotCreationParams params)createPlatformImaSettings(PlatformImaSettingsCreationParams params)设计时需优先考虑三点最小化新增特性时发生破坏性变更breaking change的概率允许平台实现轻松添加平台特有功能易于编写单元测试。每个平台实现InteractiveMediaAdsPlatform的子类并通过InteractiveMediaAdsPlatform.instance ...注册自己为当前平台实现。若未注册就使用PlatformAdsLoader的工厂构造会通过assert直接给出明确提示见 platform_ads_loader.dart单元测试时可自行向instance注入测试实现。2.2 平台接口的类类型约定平台接口里的类分为几类各有明确的约定。Delegate Platform Class委托平台类这类类对应面向应用接口需要把处理委托给平台实现的场景通常以Platform为前缀命名。根据对应应用侧类能否由应用实例化分为三种情况应用侧类可由应用直接实例化如AdsLoader平台类应通过InteractiveMediaAdsPlatform.instance在工厂构造中实例化正确平台实现并以创建参数类creation params class作为唯一构造参数。PlatformAdsLoader正是如此——它的工厂构造从InteractiveMediaAdsPlatform.instance!.createPlatformAdsLoader(params)取得实现并暴露protected的PlatformAdsLoader.implementation(this.params)供平台实现继承使用。应用侧类不能由应用实例化如AdsManager平台类应只包含一个受保护的构造。见 platform_ads_manager.dartPlatformAdsManager的构造为protected PlatformAdsManager({required this.adCuePoints})并且AdsManager在应用侧通过私有的AdsManager._fromPlatform(this.platform)创建ads_loader.dart。应用侧类需要是Widget如AdDisplayContainer遵循可由应用实例化的相同模式但额外要求只包含一个方法Widget build(BuildContext)。关键约定Note平台接口中每个方法最多只能有一个参数。这正是单参数方法约定——它允许平台接口与平台实现在未来新增特性时通过给创建参数类加可选字段来演进而无需修改既有方法签名从而避免破坏性变更。从PlatformAdsManager的方法列表可以验证这一约定init({settings})、start(AdsManagerStartParams params)、setAdsManagerDelegate(delegate)等要么单参数要么通过参数对象聚合。Data Classes数据类数据类只包含字段、不包含方法且每个数据类都应标记为immutable。仓库中大量存在此类约定例如PlatformOnAdsLoadedData、AdsLoadErrorDataplatform_ads_loader.dart以及immutable base class PlatformAdsLoaderCreationParams——后者还演示了如何通过子类化扩展平台特有创建参数且额外字段应允许null或提供默认值以兼容既有代码。三、平台实现Platform Implementations平台实现代码位于Androidlib/src/android/iOSlib/src/ios/每个平台实现创建InteractiveMediaAdsPlatform的子类并实现该基类返回的所有平台类。从文件列表可以看到两端高度对称的实现族android_ads_loader.dart/ios_ads_loader.dart、android_ad_display_container.dart/ios_ad_display_container.dart、android_ads_manager.dart/ios_ads_manager.dart等一一对应平台接口中的每个Platform*类。3.1 SDK Wrapper用 Pigeon 包装原生 SDK平台实现使用原生 SDK 的 Dart 封装封装通过pigeon包生成。插件在 pubspec.yaml 中将pigeon: ^27.3.2列为 dev_dependency。两端封装对应的 Pigeon 源文件为Androidpigeons/interactive_media_ads_android.dartiOSpigeons/interactive_media_ads_ios.dart以 pigeons/interactive_media_ads_android.dart 为例文件头部即声明了生成产物的输出位置与 Kotlin 包名ConfigurePigeon( PigeonOptions( copyrightHeader: pigeons/copyright.txt, dartOut: lib/src/android/interactive_media_ads.g.dart, kotlinOut: android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/InteractiveMediaAdsLibrary.g.kt, kotlinOptions: KotlinOptions(package: dev.flutter.packages.interactive_media_ads), ), )生成的文件位于Androidlib/src/android/interactive_media_ads.g.dartandroid/src/main/kotlin/dev/flutter/packages/interactive_media_ads/InteractiveMediaAdsLibrary.g.ktiOSlib/src/ios/interactive_media_ads.g.dartios/interactive_media_ads/Sources/interactive_media_ads/InteractiveMediaAdsLibrary.g.swift注意文档特别说明生成 iOS 封装的相关代码当时仍在评审中因此插件的 pubspec 需要以 git 依赖的方式引用 pigeon本仓库中 pubspec.yaml 使用的是已发布的pigeon: ^27.3.2版本约束。3.2 更新某一平台的 Wrapper四步流程当需要跟随原生 IMA SDK 增加新能力时按以下步骤更新对应平台的封装步骤 1确保项目至少构建过一次Android在example/下运行flutter build apk --debugiOS在example/下运行flutter build ios --simulator步骤 2修改与原生 SDK 匹配的 Pigeon 文件Android更新pigeons/interactive_media_ads_android.dart对照原生 Android IMA SDK 的 API 包com.google.ads.interactivemedia.v3.api等iOS更新pigeons/interactive_media_ads_ios.dart对照原生 iOS IMA SDK 的类文件修改完成后运行 pigeon 命令重新生成代码。步骤 3更新原生侧生成的 API再次运行步骤 1 的flutter build编译错误会指出原生侧需要补充的实现或者直接用平台 IDE 修改原生代码更直观Android将example/android/作为独立项目用 Android Studio 打开iOS用 Xcode 打开example/ios/步骤 4编写 API 测试如果原生 wrapper 新增了非静态方法或构造函数则必须补充原生测试Android 原生测试位置android/src/test/kotlin/dev/flutter/packages/interactive_media_ads/iOS 原生测试位置example/ios/RunnerTests/3.3 Dart 单元测试Mockito 生成 mock 对象平台实现的测试使用mockito为原生 Dart wrapper 生成 mock 对象mockito: ^5.4.4同样声明在 pubspec.yaml 的 dev_dependencies 中。测试目录test/下的用例覆盖了两端实现与面向应用接口ads_loader_test.dart、ads_manager_test.dart、ads_manager_delegate_test.dartad_display_container_test.dart、content_progress_provider_test.dart、companion_ad_slot_test.dart、ima_settings_test.dartandroid/与ios/子目录平台实现专用测试test_stubs.dart测试桩与version_test.dart版本一致性校验生成 mock 对象的方式是在test/目录运行 mockito 生成命令。由于 mock 对象由生成器产出修改 wrapper 接口后需要同步重新生成再补充或调整对应测试。四、面向应用接口App-facing Interface面向应用接口位于lib/src/结构与平台接口一致同样通过委托把处理转发给平台实现。与平台接口相比存在两处刻意差异构造函数和方法可以包含多个参数例如AdsLoader的默认构造接收container、onAdsLoaded、onAdsLoadError、settings多个参数见 ads_loader.dart平台类可以通过平台实现或对应平台接口类的创建参数来实例化——即AdsLoader.fromPlatform与AdsLoader.fromPlatformCreationParams两条路径。这种宽松的应用侧 严格单参数的平台侧组合既保证应用侧 API 直观易用又保证平台契约可平滑演进。五、为插件新增功能的推荐流程当需要为插件增加新特性时文档给出四个标准步骤在flutter/flutter仓库创建 feature request issue使用 feature request 模板提交。在该 issue 中列出每个平台所需的原生类/方法分别对照 Android IMA SDK 与 iOS IMA SDK 的参考文档若某特性只存在于单一平台需特别注明。给出设计方案说明该特性如何加入平台接口与面向应用接口若只支持单一平台则说明应加在哪个平台实现中。开始实现或等待 Flutter 维护者反馈如果希望获得官方评审意见可以先等待。结合前三节内容实际实现路径通常是更新 Pigeon 源文件 → 重新生成 Dart/原生代码 → 补平台实现与原生测试 → 补 Dart 单元测试mockito→ 面向应用接口暴露新 API。六、小结interactive_media_ads通过类联邦式单仓插件结构在单一插件内完成了平台接口、双端实现与应用接口的闭环架构核心是委托模式 InteractiveMediaAdsPlatform.instance注册制配合平台类单参数方法 创建参数类可扩展的设计将破坏性变更风险降至最低原生能力接入依赖 Pigeon 生成 SDK wrapper两端生成产物有固定的源文件与输出位置更新流程为构建一次 → 改 pigeon 文件 → 生成 → 补原生代码与测试质量保障分为两层原生测试Android Kotlin / iOS RunnerTests与 Dart 单元测试mockito 生成 mock共同守护原生 wrapper 与应用接口的行为一致性。对希望为该插件贡献代码的开发者遵循文档中的平台接口类类型约定委托类、数据类、Widget 类与每个方法至多一个参数的硬性规则是保证 API 稳定演进的关键对只想在业务中集成 IMA 广告的开发者则可在 example/lib 的完整示例基础上按 README 的接入步骤Android Manifest 权限、Gradle desugaring、AdDisplayContainerAdsLoaderAdsManager组合快速起步。【免费下载链接】packagesA collection of useful packages maintained by the Flutter team项目地址: https://gitcode.com/GitHub_Trending/pac/packages创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考