
1. 项目概述为什么Unity游戏必须关注广告变现如果你是一名Unity游戏开发者无论是独立开发者还是身处中小型团队我相信“如何让游戏赚钱”这个问题一定在你的待办清单里占据了重要位置。在众多变现模式中广告变现尤其是激励视频广告因其对免费玩家体验的友好性和稳定的收益能力成为了许多休闲、超休闲乃至中度游戏的首选。而在国内移动广告市场穿山甲Ocean Engine无疑是一个你无法绕开的平台。它背靠庞大的流量生态提供了从开屏、信息流到激励视频、全屏视频等丰富的广告形式其填充率和eCPM每千次展示有效收益在业内也颇具竞争力。然而将穿山甲广告SDK接入到Unity项目中远不是下载一个插件、拖拽几个Prefab那么简单。这个过程涉及到Unity与Android/iOS原生平台的交互、复杂的配置流程、各种权限和依赖项的适配以及上线前后必须关注的策略与优化。网上能找到的官方文档或零散教程要么过于简略跳过了关键细节要么版本陈旧已不适用导致开发者在接入过程中频频踩坑轻则广告无法正常加载重则导致应用崩溃或审核被拒。这篇文章就是我结合多次从零到一成功接入穿山甲SDK并上线的实战经验为你梳理的一份全流程指南。我会假设你是一个对Unity熟悉但对原生平台开发和广告集成相对陌生的开发者用最直白的语言拆解每一个步骤背后的逻辑并附上那些官方文档不会告诉你的“避坑指南”。我们的目标很明确让你能跟着步骤稳扎稳打地完成接入并把那些常见的“雷”提前排掉。2. 接入前的核心准备与环境搭建在开始敲代码之前充分的准备工作能让你在后续的流程中事半功倍。这个阶段的核心是理清思路、备齐工具、创建正确的工程环境。2.1 明确你的技术栈与目标平台首先你需要明确你的开发环境和技术选型这直接决定了后续的接入路径。Unity版本穿山甲SDK对Unity版本有一定要求。通常建议使用Unity 2018.4 LTS或更高版本尤其是2021 LTS和2022 LTS是当前比较稳定且兼容性好的选择。避免使用过于前沿的预览版Alpha/Beta以免遇到未知的兼容性问题。你可以在Unity Hub中清晰地管理多个版本。目标平台国内市场主要面向Android和iOS。本文将以Android平台的接入作为主要讲解对象因为其流程更具代表性且问题通常更多。iOS的接入逻辑类似但证书、描述文件等配置是在Xcode和苹果开发者网站完成我会在关键点指出iOS的差异。开发环境Android你需要安装并配置好Android SDK和JDK。确保你的环境中JAVA_HOME和ANDROID_HOME或ANDROID_SDK_ROOT环境变量正确设置。一个常见的坑是使用Unity内置的JDK版本可能过旧建议单独安装JDK 8或JDK 11并在Unity的Preferences - External Tools中指定路径。iOS需要一台Mac电脑安装最新稳定版的Xcode并拥有有效的Apple Developer账号。2.2 获取穿山甲开发者账号与关键信息这是接入的“门票”和“身份标识”必须在编码前拿到。注册与登录访问穿山甲开发者平台使用手机号或邮箱注册账号并完成企业或个人开发者认证。个人开发者适合独立开发者但某些广告形式或更高权限可能需要企业资质。创建应用与广告位在控制台点击“创建应用”填写你的游戏名称、平台Android/iOS、包名等。这里的包名必须与你Unity项目中Player Settings里设置的Bundle IdentifierAndroid叫Package Name完全一致一个字符都不能差否则后续所有请求都会失败。应用创建后你需要为它创建“广告位”。广告位是广告请求的逻辑单元。例如你可以创建一个“激励视频广告位”用于观看奖励创建一个“插屏广告位”用于关卡结束。每个广告位都会生成一个唯一的代码位IDSlot ID或Ad Unit ID。这个ID是SDK区分在哪里展示什么广告的核心依据务必妥善保管。下载SDK在穿山甲开发者平台的文档中心找到Unity版本的SDK进行下载。建议总是下载最新稳定版的SDK。同时最好也下载一份最新的官方接入文档作为离线参考。2.3 创建与配置Unity工程一个好的工程习惯能避免很多混乱。新建或清理工程建议为一个新的广告接入测试创建一个干净的Unity工程或者在你现有工程的备份上进行操作。确保工程路径没有中文或特殊字符。设置包名与版本打开File - Build Settings - Player Settings。Android在Other Settings里找到Identification部分正确填写Package Name例如com.YourCompany.YourGame。Minimum API Level建议设置为API Level 21 (Android 5.0)或以上以覆盖绝大多数用户。Target API Level建议设置为你能编译通过的最高版本如33以满足应用商店的要求。iOS在Identification部分填写Bundle Identifier同样需要与穿山甲后台设置一致。导入SDK将下载的穿山甲Unity SDK包通常是一个.unitypackage文件直接拖入Unity的Project窗口在弹出的导入对话框中通常全选所有文件并点击Import。导入后你会在Project中看到类似PangleSDK或OceanEngine_Ads的文件夹。注意导入SDK后务必检查Unity Console是否有报错。常见的错误包括DLL冲突、AndroidManifest合并错误等。如果有报错先根据错误信息解决不要带着错误进行下一步。3. SDK核心模块解析与初始化流程成功导入SDK后我们首先要理解它的核心构成并完成最关键的初始化步骤。这一步是广告能正常工作的基石。3.1 理解穿山甲SDK的架构穿山甲Unity SDK通常采用分层设计对开发者暴露的是一个统一的C#接口层底层则通过Android的jar/aar包和iOS的framework与原生平台通信。你需要了解几个关键对象SDK 全局管理类负责SDK的初始化、权限申请、全局配置等。AdSlot 广告请求配置类。它包含了广告位ID、广告类型、尺寸、方向等所有关于“你要请求一个什么样的广告”的信息。你可以把它看作一个“广告订单模板”。激励视频广告 (RewardedVideoAd)、插屏广告 (InterstitialAd)、Banner广告 这些是具体的广告交互类。你需要为每一种广告类型创建对应的实例并为其设置监听器Listener来接收广告加载、展示、奖励发放等回调事件。这种设计模式是典型的“配置-实例-回调”模式清晰地将广告的定义、生命周期管理和事件反馈分离。3.2 编写初始化脚本初始化必须在任何广告请求之前进行通常放在游戏启动的早期例如一个启动场景的Awake或Start方法中。using UnityEngine; using Pangle; // 或具体的命名空间根据SDK版本可能为OceanEngine.Ads等 public class PangleAdManager : MonoBehaviour { private string _androidAppId 你的Android应用App ID; private string _iOSAppId 你的iOS应用App ID; private bool _isTestMode true; // 上线前务必改为 false void Start() { InitializePangleSDK(); } void InitializePangleSDK() { // 1. 设置测试模式非常重要 // 在开发阶段务必开启测试模式使用测试广告位ID避免产生无效流量导致封号。 PangleSDK.SetIsPaid(false); // 非付费应用 PangleSDK.SetTestMode(_isTestMode); // 2. 准备初始化配置 var config new PangleConfig.Builder() .AppId(GetPlatformAppId()) // 根据平台获取对应的App ID .UseTextureView(true) // Android上建议使用TextureView以获得更好的兼容性 .AllowShowNotify(true) // 是否允许通知根据游戏类型决定 .AllowShowPageWhenScreenLock(true) // 锁屏下是否展示通常为false .DebugLog(true) // 开启调试日志方便排查问题 .Build(); // 3. 执行初始化 PangleSDK.Init(config, (bool success, string message) { if (success) { Debug.Log(穿山甲SDK初始化成功); // 初始化成功后可以开始预加载广告 PreloadRewardedVideoAd(); } else { Debug.LogError($穿山甲SDK初始化失败: {message}); // 处理初始化失败可能是网络问题或App ID错误 } }); } string GetPlatformAppId() { #if UNITY_ANDROID return _androidAppId; #elif UNITY_IOS return _iOSAppId; #else return ; #endif } }关键点与避坑指南测试模式开关_isTestMode这个变量至关重要。在开发、调试、内部测试阶段必须设置为true。这会让你请求到穿山甲提供的测试广告确保功能正常同时绝对不会产生真实的广告计费和展示数据。如果你在测试阶段使用了真实的广告位ID并关闭了测试模式产生的任何展示或点击都可能被视为“开发者自刷”严重违反平台规则会导致应用ID或广告位ID被封禁。上线前记得将其改为false。App IDAndroid和iOS的应用App ID是不同的务必从各自平台的后台获取并正确填写。混淆使用会导致初始化失败。异步回调初始化是网络操作因此是异步的。你的后续逻辑比如预加载广告一定要放在初始化成功的回调里执行否则可能因为SDK未就绪而失败。权限配置初始化配置中的AllowShowNotify等选项需要根据你游戏的实际情况决定。例如如果你的游戏是全屏沉浸式体验可能不希望被通知打扰可以设置为false。4. 各类型广告的集成与实现细节初始化成功后我们就可以开始集成具体的广告形式了。激励视频是变现效率最高的形式之一我们就以它为例详细拆解从创建到展示的完整流程。4.1 激励视频广告集成全步骤激励视频广告的流程可以概括为创建广告位配置 - 加载广告 - 监听加载结果 - 检查并展示 - 处理奖励回调。public class PangleAdManager : MonoBehaviour { private string _rewardedVideoSlotId 你的激励视频广告位ID; private RewardedVideoAd _rewardedVideoAd; private bool _isRewardedVideoLoaded false; void PreloadRewardedVideoAd() { // 1. 创建广告请求配置 (AdSlot) AdSlot adSlot new AdSlot.Builder() .SetCodeId(_rewardedVideoSlotId) .SetRewardName(金币) // 奖励名称用于后台数据统计需与客户端发放的奖励对应 .SetRewardAmount(100) // 奖励数量 .SetUserID(optional_user_id) // 可选设置用户ID用于服务端验证 .SetMediaExtra(optional_extra) // 可选额外信息 .SetOrientation(AdOrientation.Vertical) // 广告方向通常竖屏 .Build(); // 2. 创建激励视频广告实例 if (_rewardedVideoAd ! null) { _rewardedVideoAd.Dispose(); // 销毁旧的实例避免内存泄漏 } _rewardedVideoAd new RewardedVideoAd(adSlot); // 3. 设置广告事件监听器 _rewardedVideoAd.SetRewardInteractionListener(new RewardInteractionListener(this)); _rewardedVideoAd.SetFullScreenVideoInteractionListener(new FullScreenInteractionListener(this)); // 4. 加载广告 _rewardedVideoAd.LoadAd(); Debug.Log(开始加载激励视频广告...); } // 提供给UI按钮调用的方法 public void ShowRewardedVideoAd() { if (_isRewardedVideoLoaded _rewardedVideoAd ! null) { // 展示广告前可以暂停游戏背景音乐、计时器等 PauseGame(); _rewardedVideoAd.ShowRewardVideoAd(); } else { Debug.LogWarning(激励视频广告尚未加载完成无法播放。); // 可以给玩家一个提示如“广告加载中请稍后” ShowToast(广告正在加载请稍候...); // 尝试重新加载 PreloadRewardedVideoAd(); } } // 内部类处理奖励互动回调 private class RewardInteractionListener : IRewardInteractionListener { private PangleAdManager _manager; public RewardInteractionListener(PangleAdManager manager) { _manager manager; } public void OnAdShow() { Debug.Log(激励视频广告开始展示。); } public void OnAdVideoBarClick() { Debug.Log(激励视频广告被点击。); } public void OnAdClose() { Debug.Log(激励视频广告关闭。); // 广告关闭后恢复游戏 _manager.ResumeGame(); // 广告关闭后无论是否获得奖励都可以开始预加载下一个广告 _manager.PreloadRewardedVideoAd(); } // 这是最关键的回调只有收到此回调才能给玩家发放奖励。 public void OnVideoComplete() { Debug.Log(激励视频播放完成。); } public void OnVideoError(string error) { Debug.LogError($激励视频播放出错: {error}); _manager.ResumeGame(); } // 服务器验证奖励有效回调需要配置服务端验证 public void OnRewardVerify(bool verify, string info) { Debug.Log($奖励验证结果: {verify}, 信息: {info}); if (verify) { _manager.GrantRewardToPlayer(); } } } // 内部类处理全屏视频交互回调如加载状态 private class FullScreenInteractionListener : IFullScreenVideoInteractionListener { private PangleAdManager _manager; public FullScreenInteractionListener(PangleAdManager manager) { _manager manager; } public void OnAdLoad(RewardedVideoAd ad, AdSlot slot) { Debug.Log(激励视频广告加载成功。); _manager._isRewardedVideoLoaded true; // 可以在这里更新UI按钮状态比如将“看广告”按钮变为可点击状态 _manager.UpdateAdButtonState(true); } public void OnAdLoadFail(int code, string message) { Debug.LogError($激励视频广告加载失败错误码: {code}, 消息: {message}); _manager._isRewardedVideoLoaded false; _manager.UpdateAdButtonState(false); // 可以记录失败原因用于分析填充率问题 } public void OnAdShow(RewardedVideoAd ad) { } public void OnAdClick(RewardedVideoAd ad) { } public void OnAdClose(RewardedVideoAd ad) { } } // 以下是游戏逻辑相关方法示例 private void PauseGame() { /* 暂停游戏逻辑、音乐 */ } private void ResumeGame() { /* 恢复游戏逻辑、音乐 */ } private void UpdateAdButtonState(bool isReady) { /* 更新UI按钮 */ } private void ShowToast(string msg) { /* 显示提示信息 */ } private void GrantRewardToPlayer() { Debug.Log(向玩家发放奖励); // 这里增加玩家的金币、道具等 // 注意强烈建议结合 OnRewardVerify 服务端验证来确保奖励发放的安全 } }避坑指南与最佳实践奖励发放时机这是最容易出错的地方。绝对不能在OnAdClose广告关闭或OnVideoComplete视频播放完成回调里直接发放奖励。因为用户可能在视频播放中途就关闭广告或者网络问题导致播放未完成。穿山甲平台要求必须在收到OnRewardVerify(验证成功)或如果未配置服务端验证在收到OnVideoComplete回调后才能发放奖励。这是防止奖励被滥用的关键。广告预加载不要在玩家点击“看广告”按钮时才去加载广告那会带来数秒的等待极大损害体验。应该在初始化成功后、或者上一个广告关闭后立即调用PreloadRewardedVideoAd预加载下一个广告。_isRewardedVideoLoaded这个状态标志位就是用来管理广告是否就绪的。实例管理每次展示广告后旧的RewardedVideoAd实例就失效了。在预加载新广告前务必调用_rewardedVideoAd.Dispose()释放旧资源再创建新的实例。否则会导致内存泄漏或加载异常。错误处理OnAdLoadFail回调会提供错误码和消息。常见的错误码如20001网络错误、30001包名/App ID不匹配、40001广告位ID错误等。你需要根据这些信息进行相应的处理或提示。4.2 插屏与Banner广告集成要点插屏广告和Banner广告的集成模式与激励视频类似但更简单。插屏广告通常用于关卡之间、暂停界面等。其加载和展示流程与激励视频几乎一致只是类名换成了InterstitialAd并且没有奖励相关的回调OnVideoComplete,OnRewardVerify。同样需要注意预加载和实例管理。Banner广告这是一种常驻的矩形广告。集成时需要额外指定广告的尺寸如320x50 300x250和位置。Banner广告通常不需要频繁加载和销毁可以在场景初始化时创建并显示在不需要时隐藏。注意Banner广告可能会遮挡游戏UI需要精心设计其摆放位置。// Banner广告简单示例 public void CreateAndShowBanner() { AdSlot bannerSlot new AdSlot.Builder() .SetCodeId(_bannerSlotId) .SetImageAcceptedSize(300, 250) // 设置期望的Banner尺寸 .Build(); _bannerAd new BannerAd(bannerSlot); _bannerAd.SetInteractionListener(new MyBannerListener()); _bannerAd.LoadAd(); // 加载成功后通过 _bannerAd.ShowBannerAd(Rect position) 在指定位置显示 }5. Android平台专项配置与打包避坑Unity项目最终需要打包成APK或AAB文件在Android平台上这一步的配置尤为复杂是问题高发区。5.1 AndroidManifest.xml 配置详解穿山甲SDK在导入时通常会自带一个AndroidManifest.xml文件并尝试通过Unity的Gradle构建系统或Manifest合并功能与你的主Manifest合并。但自动合并时常出问题手动检查和配置更稳妥。你需要找到并检查你项目中的主AndroidManifest.xml文件通常位于Assets/Plugins/Android目录下如果没有在构建时Unity会生成一个基础版本。需要确保包含以下关键元素权限穿山甲SDK需要一些基本的网络和存储权限。uses-permission android:nameandroid.permission.INTERNET / uses-permission android:nameandroid.permission.ACCESS_NETWORK_STATE / uses-permission android:nameandroid.permission.ACCESS_WIFI_STATE / !-- 如果需要下载广告素材如视频可能需要 -- uses-permission android:nameandroid.permission.WRITE_EXTERNAL_STORAGE android:maxSdkVersion28 / uses-permission android:nameandroid.permission.READ_EXTERNAL_STORAGE android:maxSdkVersion28 / !-- 对于Android 10 (API 29)及以上推荐使用Scoped Storage可能不需要上述存储权限具体看SDK要求 --Application标签内的组件SDK需要注册一些Activity、Service和Provider。这些通常由SDK自带的aar包提供但需要在Manifest中声明。重点检查是否有重复声明或冲突。例如PangleADActivity的configChanges属性必须包含orientation|keyboardHidden|screenSize。activity android:namecom.bytedance.sdk.openadsdk.activity.TTDelegateActivity android:configChangesorientation|keyboardHidden|screenSize android:exportedfalse android:themeandroid:style/Theme.Translucent.NoTitleBar / !-- 确保所有SDK声明的Activity的android:exported属性符合Android新规Android 12要求 --Queries 语句针对 Android 11/API 30如果SDK需要查询其他应用的信息例如跳转到应用商店需要添加queries标签。queries intent action android:nameandroid.intent.action.VIEW / data android:schemehttps / /intent !-- 可能还需要包名特定的查询 -- package android:namecom.android.vending / !-- Google Play Store -- /queries5.2 Gradle与依赖冲突解决Unity默认使用内建的打包系统但对于复杂的SDK集成切换到Gradle构建是更推荐且更稳定的方式。启用Gradle在File - Build Settings - Player Settings - Publishing Settings或Build System下将Build System从Internal改为**Gradle**。配置主Gradle模板勾选Custom Main Gradle Template和Custom Gradle Properties Template。这会在Assets/Plugins/Android下生成mainTemplate.gradle和gradleTemplate.properties文件让你能自定义构建配置。解决依赖冲突这是最大的坑点。穿山甲SDK可能依赖特定版本的androidx库、Gson、OkHttp等而你的项目或其他第三方插件如Firebase、Unity服务可能依赖了不同版本导致构建失败。打开mainTemplate.gradle在dependencies块中你可以看到所有引入的库。冲突通常表现为Duplicate class或Conflict with dependency错误。解决方案是统一版本号。你可以使用Gradle的强制分辨率策略。在dependencies块之前或allprojects块中添加configurations.all { resolutionStrategy { // 强制指定某个库的版本 force com.google.code.gson:gson:2.8.9 force androidx.appcompat:appcompat:1.3.1 // 排除特定模块的传递依赖 // exclude group: com.squareup.okhttp3, module: okhttp } }另一种方法是仔细检查穿山甲SDK的文档看它声明了哪些依赖然后尝试让你的其他插件与之对齐。5.3 打包、安装与真机调试构建APK/AAB配置完毕后进行构建。首次使用Gradle构建会下载大量依赖时间较长。安装到真机构建出的APK安装到测试手机上。务必使用真机测试模拟器无法正常播放广告且很多权限和功能在模拟器上行为异常。查看日志在Unity编辑器中使用adb logcat命令或者在手机上安装日志查看App过滤Pangle或TTAd等关键字是排查运行时问题的最有效手段。初始化成功、广告加载、展示失败等信息都会在日志中打印。6. 上线前必查清单与优化策略当广告功能在测试模式下运行稳定后在上线前还有一系列关乎“生死”的检查项和优化点需要完成。6.1 上线前终极检查清单对照下表逐项打勾确认检查项说明与操作不做的后果测试模式关闭将代码中_isTestMode或PangleSDK.SetTestMode参数设为false。产生无效流量导致封号。应用包名/ID核对确认Unity工程包名、穿山甲后台应用包名、代码中初始化App ID三者完全一致。广告无法加载错误码30001。广告位ID核对确认代码中使用的广告位ID与后台创建的广告位ID一致且类型匹配激励视频ID不能用于请求插屏。广告无法加载错误码40001。权限与组件检查最终的合并版AndroidManifest.xml确保权限齐全所有Activity的exported属性正确设置Android 12要求。应用在部分新机型上崩溃或无法拉起广告。混淆配置如果你启用了代码混淆ProGuard/R8必须在混淆规则文件中添加穿山甲SDK的keep规则。规则通常由SDK提供。发布包中广告相关类被混淆导致功能异常或崩溃。隐私合规确保在初始化SDK之前已经弹出了符合规范的《隐私政策》并获得了用户同意。只有在用户同意后才能调用PangleSDK.Init。违反法律法规应用可能被下架。奖励发放逻辑再次确认奖励发放逻辑严格绑定在OnRewardVerify或OnVideoComplete回调中且没有在其他地方如OnAdClose重复发放。奖励被刷造成经济损失平台判定违规。网络状态处理在请求广告前增加网络状态判断如Application.internetReachability。无网络时给予用户友好提示而不是默默失败。用户体验差可能误以为功能失效。6.2 性能与体验优化策略广告预加载策略时机在游戏启动初始化后、在非性能关键帧如加载界面、在上一个广告关闭后立即预加载下一个广告。数量对于激励视频可以预加载1-2个备用。对于插屏可以在进入可能触发插屏的场景前预加载。内存管理不展示的广告实例及时Dispose()。对于Banner广告在不需要时如进入无广告的内购界面可以调用_bannerAd.Destroy()将其移除。填充率与瀑布流优化穿山甲后台可以配置瀑布流。确保你的广告位接入了多个广告源穿山甲会默认提供并合理设置底价以最大化填充率和收益。监控穿山甲后台的数据报表关注展示率、eCPM等指标。如果某个广告位的填充率持续很低可以尝试调整广告类型、位置或用户定向策略。用户体验平衡频率控制不要过度展示广告尤其是插屏广告。设置合理的展示间隔避免引起玩家反感。展示时机激励视频的触发点要自然如“复活机会”、“双倍奖励”让玩家觉得“值得看”。插屏广告最好放在自然的断点如关卡结束、返回主菜单时。加载提示当广告未预加载好而玩家点击时给予明确的“广告加载中”提示而不是让按钮无响应。7. 疑难杂症排查与常见问题实录即使按照指南操作在实际开发中仍会遇到各种奇怪的问题。这里记录一些我踩过的坑和解决方案。问题1Unity编辑器运行正常打包到Android后广告不加载日志显示“未初始化”或“包名不匹配”。排查这是最经典的问题。99%的原因在于包名不一致。解决用反编译工具如jadx-gui打开你打出的APK查看AndroidManifest.xml中的实际包名。对比UnityPlayer Settings中的包名、穿山甲后台应用配置的包名、代码中_androidAppId对应的应用包名。必须三者一字不差。检查是否在打不同渠道包时使用了不同的包名后缀但后台只配置了一个。问题2构建时Gradle报错提示“Duplicate class”或“Conflict with dependency”。排查依赖冲突。解决在mainTemplate.gradle中使用resolutionStrategy.force统一关键库的版本如前文所述。如果冲突无法解决尝试排除冲突模块的传递依赖exclude group: xxx, module: xxx。检查穿山甲SDK的版本是否过旧与当前Unity或Android Gradle Plugin版本不兼容。尝试升级到SDK最新版。问题3广告能加载但点击播放后黑屏或闪退。排查Manifest中Activity配置错误检查所有穿山甲相关的Activity声明特别是TTVideoActivity其configChanges属性必须包含orientation|keyboardHidden|screenSize。权限问题在Android 6.0以上部分权限需要运行时申请。虽然穿山甲SDK可能会自己处理但确保你的游戏有基本的存储权限如果SDK需要。TextureView兼容性在初始化配置中尝试设置.UseTextureView(true)。某些设备或Unity版本下SurfaceView可能有问题。真机系统WebView版本过低穿山甲部分广告素材依赖系统WebView。提示用户更新系统WebView或Chrome浏览器。问题4iOS构建成功但初始化失败错误码未知。排查网络权限iOS需要在Info.plist中添加NSAppTransportSecurity设置允许任意加载或正确配置白名单。确保已添加。SKAdNetworkiOS 14要求配置SKAdNetwork以支持归因。穿山甲SDK的SKAdNetworkID列表需要添加到你的Xcode工程的Info.plist中。这个列表在穿山甲iOS SDK的下载包或文档里可以找到。IDFA如果使用了IDFA广告标识符需要在Xcode工程中勾选Advertiser ID权限并在App Store Connect的隐私问卷中如实声明。问题5激励视频播放完成后没有收到OnVideoComplete或OnRewardVerify回调。排查测试广告问题确认是否在使用测试广告位ID和测试模式。部分测试广告的行为可能与真实广告有细微差别但核心回调应该一致。回调绑定时机确保SetRewardInteractionListener是在LoadAd之前调用的。如果在加载后才设置监听器可能会错过一些回调。设备时间不准极少数情况下设备时间与网络时间不同步可能影响服务器验证回调。确保设备时间自动同步。接入广告SDK是一个细致活考验的是开发者的耐心和对细节的把控。最有效的调试方式永远是查看日志。把穿山甲SDK的调试日志打开结合Unity的Debug.Log和Android的logcat大部分问题的根源都能被定位。记住在测试阶段大胆地用测试模式把所有流程跑通在上线前严格地对照检查清单切换回正式环境。这样一套组合拳下来你的Unity游戏广告变现之路就能走得又稳又远了。