告别CocoaPods!Cocos Creator iOS项目手动集成AdMob SDK 8.9.0的保姆级教程

告别CocoaPods!Cocos Creator iOS项目手动集成AdMob SDK 8.9.0的保姆级教程 Cocos Creator iOS项目手动集成AdMob SDK 8.9.0全流程解析在移动游戏开发中广告变现是不可或缺的一环。对于使用Cocos Creator的开发者来说如何在iOS平台上绕过CocoaPods直接手动集成AdMob SDK是一个既实用又具有挑战性的技术需求。本文将带你从零开始逐步完成整个集成过程。1. 准备工作与环境配置在开始集成之前我们需要确保开发环境已经正确配置。以下是必要的准备工作Cocos Creator版本建议使用2.4.3或更高版本Xcode版本12.0及以上macOS系统Big Sur 11.5或更新版本AdMob SDK版本8.9.0注意不同版本的SDK可能会有API差异建议始终使用官方推荐的最新稳定版本首先我们需要从Google开发者网站下载AdMob SDK。访问 AdMob iOS下载页面 选择手动下载选项。下载完成后你会得到一个包含多个框架的压缩包。2. SDK文件结构与必要组件解压下载的SDK包后你会看到以下文件结构GoogleMobileAdsFramework/ ├── GoogleMobileAds.xcframework ├── GoogleAppMeasurement.xcframework ├── GoogleUtilities.xcframework ├── nanopb.xcframework ├── PromisesObjC.xcframework └── UserMessagingPlatform.xcframework这些框架中必须包含到项目中的有GoogleMobileAds.xcframework - AdMob核心功能UserMessagingPlatform.xcframework - 用户消息平台(用于GDPR合规)GoogleUtilities.xcframework - Google工具库提示虽然其他框架在某些情况下可能不需要但为了确保功能完整性和稳定性建议全部包含3. 将SDK集成到Xcode项目现在我们将这些框架添加到Cocos Creator生成的Xcode项目中在Finder中将下载的框架文件夹拖到项目的根目录在Xcode中右键点击项目导航器中的项目名称选择Add Files to [YourProjectName]选择所有下载的.xcframework文件关键步骤确保勾选Copy items if needed选项选择Create groups然后点击Add完成这些步骤后你的项目结构应该类似于YourProject/ ├── YourProject/ ├── Frameworks/ │ ├── GoogleMobileAds.xcframework │ ├── UserMessagingPlatform.xcframework │ └── ... └── Products/4. 配置项目构建设置为了确保SDK能够正常工作我们需要对项目进行一些必要的配置4.1 链接器标志设置在Xcode中选择项目导航器中的项目选择你的target进入Build Settings标签搜索Other Linker Flags添加以下标志-ObjC$(inherited)重要这些链接器标志对于Objective-C运行时正确加载AdMob SDK的类别扩展至关重要4.2 Framework搜索路径在Build Settings中搜索Framework Search Paths添加以下路径$(SRCROOT)/Frameworks$(PROJECT_DIR)/Frameworks4.3 启用BitcodeAdMob SDK需要禁用Bitcode搜索Enable Bitcode将其设置为NO5. 配置Info.plist文件AdMob SDK需要在Info.plist中添加一些必要的配置项keyGADApplicationIdentifier/key stringca-app-pub-3940256099942544~1458002511/string keyGADIsAdManagerApp/key true/ keyNSUserTrackingUsageDescription/key string此标识符将用于向您提供更相关的广告/string对于欧盟地区的应用还需要添加keyGADDelayAppMeasurementInit/key true/注意GADApplicationIdentifier中的值是测试ID发布时应替换为你自己的AdMob应用ID6. 初始化AdMob SDK在AppController.mm文件中添加AdMob初始化代码// 在application:didFinishLaunchingWithOptions:方法中添加 [[GADMobileAds sharedInstance] startWithCompletionHandler:nil];这段代码应该在应用启动时尽早调用以确保广告系统正确初始化。7. 实现广告功能现在我们将创建几个核心类来管理不同类型的广告。首先创建一个AdMobManager单例类来集中管理广告。7.1 AdMobManager.h#import Foundation/Foundation.h #import RootViewController.h NS_ASSUME_NONNULL_BEGIN interface AdMobManager : NSObject (instancetype)sharedInstance; - (void)setRootViewController:(RootViewController *)viewController; // 广告展示方法 (void)showInterstitialAd; (void)showRewardedAd; (void)showBannerAd; // 隐私合规相关 - (void)startConsentFlow; end NS_ASSUME_NONNULL_END7.2 AdMobManager.m#import AdMobManager.h #import GoogleMobileAds/GoogleMobileAds.h #import UserMessagingPlatform/UserMessagingPlatform.h interface AdMobManager() property (nonatomic, weak) RootViewController *rootViewController; end implementation AdMobManager (instancetype)sharedInstance { static AdMobManager *sharedInstance nil; static dispatch_once_t onceToken; dispatch_once(onceToken, ^{ sharedInstance [[self alloc] init]; }); return sharedInstance; } - (void)setRootViewController:(RootViewController *)viewController { self.rootViewController viewController; } // 其他方法实现将在下面章节详细介绍 end8. 实现插页广告(Interstitial)插页广告是全屏广告通常在游戏关卡之间自然展示。8.1 创建Interstitial广告管理类// AdsInterstitial.h #import Foundation/Foundation.h #import GoogleMobileAds/GoogleMobileAds.h interface AdsInterstitial : NSObject GADFullScreenContentDelegate - (void)loadAd; - (void)showAdFromViewController:(UIViewController *)viewController; end8.2 Interstitial实现// AdsInterstitial.m #import AdsInterstitial.h interface AdsInterstitial() property (nonatomic, strong) GADInterstitialAd *interstitialAd; property (nonatomic, assign) BOOL isAdLoaded; end implementation AdsInterstitial - (void)loadAd { if (self.isAdLoaded) return; GADRequest *request [GADRequest request]; [GADInterstitialAd loadWithAdUnitID:ca-app-pub-3940256099942544/4411468910 request:request completionHandler:^(GADInterstitialAd *ad, NSError *error) { if (error) { NSLog(插页广告加载失败: %, error.localizedDescription); return; } self.interstitialAd ad; self.interstitialAd.fullScreenContentDelegate self; self.isAdLoaded YES; }]; } - (void)showAdFromViewController:(UIViewController *)viewController { if (!self.isAdLoaded) { NSLog(广告尚未加载完成); [self loadAd]; return; } [self.interstitialAd presentFromRootViewController:viewController]; } #pragma mark - GADFullScreenContentDelegate - (void)adDidPresentFullScreenContent:(idGADFullScreenPresentingAd)ad { NSLog(插页广告已展示); } - (void)ad:(idGADFullScreenPresentingAd)ad didFailToPresentFullScreenContentWithError:(NSError *)error { NSLog(插页广告展示失败: %, error.localizedDescription); self.isAdLoaded NO; } - (void)adDidDismissFullScreenContent:(idGADFullScreenPresentingAd)ad { NSLog(插页广告已关闭); self.isAdLoaded NO; // 广告关闭后重新加载 [self loadAd]; } end9. 实现激励视频广告(Rewarded)激励视频广告允许用户通过观看完整视频获得游戏内奖励。9.1 创建Rewarded广告管理类// AdsRewarded.h #import Foundation/Foundation.h #import GoogleMobileAds/GoogleMobileAds.h interface AdsRewarded : NSObject GADFullScreenContentDelegate - (void)loadAd; - (void)showAdFromViewController:(UIViewController *)viewController userDidEarnReward:(void (^)(void))rewardHandler; end9.2 Rewarded实现// AdsRewarded.m #import AdsRewarded.h interface AdsRewarded() property (nonatomic, strong) GADRewardedAd *rewardedAd; property (nonatomic, assign) BOOL isAdLoaded; property (nonatomic, copy) void (^rewardHandler)(void); end implementation AdsRewarded - (void)loadAd { if (self.isAdLoaded) return; GADRequest *request [GADRequest request]; [GADRewardedAd loadWithAdUnitID:ca-app-pub-3940256099942544/1712485313 request:request completionHandler:^(GADRewardedAd *ad, NSError *error) { if (error) { NSLog(激励视频加载失败: %, error.localizedDescription); return; } self.rewardedAd ad; self.rewardedAd.fullScreenContentDelegate self; self.isAdLoaded YES; }]; } - (void)showAdFromViewController:(UIViewController *)viewController userDidEarnReward:(void (^)(void))rewardHandler { if (!self.isAdLoaded) { NSLog(激励视频尚未加载完成); [self loadAd]; return; } self.rewardHandler rewardHandler; [self.rewardedAd presentFromRootViewController:viewController userDidEarnRewardHandler:^{ if (self.rewardHandler) { self.rewardHandler(); } }]; } #pragma mark - GADFullScreenContentDelegate - (void)adDidPresentFullScreenContent:(idGADFullScreenPresentingAd)ad { NSLog(激励视频已展示); } - (void)ad:(idGADFullScreenPresentingAd)ad didFailToPresentFullScreenContentWithError:(NSError *)error { NSLog(激励视频展示失败: %, error.localizedDescription); self.isAdLoaded NO; } - (void)adDidDismissFullScreenContent:(idGADFullScreenPresentingAd)ad { NSLog(激励视频已关闭); self.isAdLoaded NO; self.rewardHandler nil; // 广告关闭后重新加载 [self loadAd]; } end10. 实现横幅广告(Banner)横幅广告是显示在屏幕顶部或底部的小型广告。10.1 创建Banner广告管理类// AdsBanner.h #import Foundation/Foundation.h #import GoogleMobileAds/GoogleMobileAds.h interface AdsBanner : NSObject GADBannerViewDelegate - (void)loadAdWithViewController:(UIViewController *)viewController; - (void)removeAd; end10.2 Banner实现// AdsBanner.m #import AdsBanner.h interface AdsBanner() property (nonatomic, strong) GADBannerView *bannerView; property (nonatomic, weak) UIViewController *rootViewController; end implementation AdsBanner - (void)loadAdWithViewController:(UIViewController *)viewController { self.rootViewController viewController; if (self.bannerView) { [self.bannerView removeFromSuperview]; } // 这里使用标准横幅尺寸 self.bannerView [[GADBannerView alloc] initWithAdSize:GADAdSizeBanner]; self.bannerView.adUnitID ca-app-pub-3940256099942544/2934735716; self.bannerView.rootViewController viewController; self.bannerView.delegate self; GADRequest *request [GADRequest request]; [self.bannerView loadRequest:request]; } - (void)removeAd { [self.bannerView removeFromSuperview]; self.bannerView nil; } #pragma mark - GADBannerViewDelegate - (void)bannerViewDidReceiveAd:(GADBannerView *)bannerView { NSLog(横幅广告加载成功); // 将横幅广告添加到视图底部 bannerView.translatesAutoresizingMaskIntoConstraints NO; [self.rootViewController.view addSubview:bannerView]; [NSLayoutConstraint activateConstraints:[ [bannerView.bottomAnchor constraintEqualToAnchor:self.rootViewController.view.safeAreaLayoutGuide.bottomAnchor], [bannerView.centerXAnchor constraintEqualToAnchor:self.rootViewController.view.centerXAnchor] ]]; } - (void)bannerView:(GADBannerView *)bannerView didFailToReceiveAdWithError:(NSError *)error { NSLog(横幅广告加载失败: %, error.localizedDescription); } end11. 处理用户隐私与合规性随着iOS 14和隐私政策的更新正确处理用户隐私变得尤为重要。11.1 添加ATT权限请求在Info.plist中添加以下键值对keyNSUserTrackingUsageDescription/key string此标识符将用于向您提供更相关的广告/string然后创建一个类来处理权限请求// PrivacyManager.h #import Foundation/Foundation.h #import AppTrackingTransparency/AppTrackingTransparency.h interface PrivacyManager : NSObject (void)requestTrackingAuthorization; end// PrivacyManager.m #import PrivacyManager.h implementation PrivacyManager (void)requestTrackingAuthorization { if (available(iOS 14, *)) { [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) { // 根据用户选择处理后续逻辑 switch (status) { case ATTrackingManagerAuthorizationStatusAuthorized: NSLog(用户已授权广告追踪); break; case ATTrackingManagerAuthorizationStatusDenied: NSLog(用户已拒绝广告追踪); break; default: break; } }]; } } end11.2 欧盟用户消息平台(UMP)集成对于欧盟地区的用户需要实现GDPR合规// 在AdMobManager.m中添加 - (void)startConsentFlow { UMPRequestParameters *parameters [[UMPRequestParameters alloc] init]; parameters.tagForUnderAgeOfConsent NO; // 根据你的应用受众设置 [UMPConsentInformation.sharedInstance requestConsentInfoUpdateWithParameters:parameters completionHandler:^(NSError *error) { if (error) { NSLog(同意信息更新失败: %, error.localizedDescription); return; } if (UMPConsentInformation.sharedInstance.formStatus UMPFormStatusAvailable) { [self loadConsentForm]; } }]; } - (void)loadConsentForm { [UMPConsentForm loadWithCompletionHandler:^(UMPConsentForm *form, NSError *loadError) { if (loadError) { NSLog(同意表单加载失败: %, loadError.localizedDescription); return; } if (UMPConsentInformation.sharedInstance.consentStatus UMPConsentStatusRequired) { [form presentFromViewController:self.rootViewController completionHandler:^(NSError *dismissError) { if (UMPConsentInformation.sharedInstance.consentStatus UMPConsentStatusObtained) { NSLog(用户已提供同意); } }]; } }]; }12. Cocos Creator与原生代码的交互为了让Cocos Creator的JavaScript代码能够调用我们实现的原生广告功能需要建立桥接。12.1 创建桥接类// AdBridge.h #import Foundation/Foundation.h interface AdBridge : NSObject (void)showBannerAd; (void)showInterstitialAd; (void)showRewardedAd; (void)requestTrackingAuthorization; end// AdBridge.m #import AdBridge.h #import AdMobManager.h #import PrivacyManager.h implementation AdBridge (void)showBannerAd { [[AdMobManager sharedInstance] showBannerAd]; } (void)showInterstitialAd { [[AdMobManager sharedInstance] showInterstitialAd]; } (void)showRewardedAd { [[AdMobManager sharedInstance] showRewardedAd]; } (void)requestTrackingAuthorization { [PrivacyManager requestTrackingAuthorization]; } end12.2 JavaScript调用原生代码在Cocos Creator中创建一个TypeScript类来处理广告调用// AdManager.ts const {ccclass, property} cc._decorator; ccclass export default class AdManager extends cc.Component { private static _instance: AdManager null; public static get instance(): AdManager { return this._instance; } onLoad() { if (AdManager._instance null) { AdManager._instance this; cc.game.addPersistRootNode(this.node); } else { this.destroy(); return; } } showBannerAd() { if (cc.sys.os cc.sys.OS_IOS) { jsb.reflection.callStaticMethod(AdBridge, showBannerAd); } } showInterstitialAd() { if (cc.sys.os cc.sys.OS_IOS) { jsb.reflection.callStaticMethod(AdBridge, showInterstitialAd); } } showRewardedAd(successCallback: Function, failCallback?: Function) { if (cc.sys.os cc.sys.OS_IOS) { // 这里需要实现激励视频回调 jsb.reflection.callStaticMethod(AdBridge, showRewardedAd); } } requestTrackingAuthorization() { if (cc.sys.os cc.sys.OS_IOS cc.sys.hasFeature(cc.sys.Feature.APPLE_IOS_14)) { jsb.reflection.callStaticMethod(AdBridge, requestTrackingAuthorization); } } }13. 测试与验证完成集成后需要进行全面测试测试广告加载确保每种广告类型都能正确加载测试广告展示验证广告展示时游戏暂停/恢复逻辑测试回调特别是激励视频的奖励回调测试隐私合规模拟不同用户选择场景测试内存管理确保广告展示/关闭不会导致内存泄漏专业提示AdMob提供了测试广告单元ID在开发阶段应使用这些测试ID避免点击自己的广告导致账号被封14. 常见问题与解决方案在实际集成过程中可能会遇到以下问题14.1 广告加载失败可能原因网络连接问题广告单元ID错误SDK未正确初始化解决方案检查网络连接验证广告单元ID确保在AppDelegate中调用了[GADMobileAds sharedInstance] startWithCompletionHandler:nil]14.2 广告展示空白可能原因广告未完全加载就尝试展示设备处于测试模式但未添加测试设备解决方案确保在广告加载完成回调后再尝试展示在AdMob后台添加你的测试设备14.3 欧盟用户看不到广告可能原因未正确处理GDPR合规用户未提供必要同意解决方案确保实现了UMP SDK在用户未提供同意时使用非个性化广告15. 性能优化建议为了确保广告不影响游戏体验可以考虑以下优化预加载广告在游戏启动或场景加载时提前加载广告智能展示时机选择自然断点展示插页广告如关卡之间频率控制避免过于频繁地展示广告内存管理及时释放不再需要的广告对象// 示例预加载广告 - (void)preloadAds { [[AdsInterstitial sharedInstance] loadAd]; [[AdsRewarded sharedInstance] loadAd]; // 横幅广告通常不需要预加载 }16. 发布前的检查清单在将应用提交到App Store前请确认替换了所有测试广告单元ID正确处理了用户隐私和GDPR合规禁用了Bitcode包含了所有必要的框架正确设置了链接器标志Info.plist中包含所有必要配置测试了各种网络条件下的广告行为17. 高级技巧与最佳实践17.1 广告事件回调通过监听广告事件可以更好地将广告与游戏逻辑集成// 在广告管理类中添加回调属性 property (nonatomic, copy) void (^adDidDismissHandler)(void); property (nonatomic, copy) void (^adDidFailHandler)(NSError *error); // 在广告关闭时调用 if (self.adDidDismissHandler) { self.adDidDismissHandler(); }17.2 广告适配器考虑实现广告适配器模式以便未来更容易切换广告平台protocol AdNetworkAdapter NSObject - (void)showBannerAd; - (void)showInterstitialAd; - (void)showRewardedAdWithRewardHandler:(void (^)(void))handler; end // 然后为每个广告平台创建适配器实现 interface AdMobAdapter : NSObject AdNetworkAdapter end17.3 A/B测试使用AdMob的A/B测试功能优化广告策略测试不同广告展示频率测试不同广告位置测试不同广告类型组合18. 监控与优化上线后持续监控广告表现eCPM每千次展示收益填充率广告请求成功展示的比例点击率广告被点击的比例用户反馈关注用户对广告体验的评价根据数据调整广告策略找到收益与用户体验的最佳平衡点。19. 结语手动集成AdMob SDK到Cocos Creator iOS项目虽然有一定复杂性但通过本文的逐步指导你应该能够顺利完成集成并实现各种广告功能。记住良好的广告实现应该是无缝的、非侵入式的能够在不影响用户体验的前提下为开发者创造收益。