Unity + easyAR 跨平台 AR 发布与录屏避坑指南
发布时间:2026/10/15 22:43:37 锦皓数字建站

做 AR 项目到现在我最大的体会是新手期最怕的不是算法也不是模型而是好不容易把功能跑通到了打包发布环节Android 和 iOS 各给你来一闷棍。这篇记录的完整项目就是基于 Unity easyAR 开发的一个图片识别 AR 应用目标很朴素——Android 和 iOS 双端发布最终还要把识别和互动过程通过 easyAR 自带的录屏功能录制下来。结果从选 SDK 版本、配 License Key到 Android 混淆、iOS 权限描述再到录屏黑屏、无声、文件损坏问题清单拉出来一大串。如果你正准备用 easyAR 做跨平台 AR 项目或是需要把“录屏”这种看似简单的功能加进去这篇应该能帮你少走很多弯路。文中涉及截图的部分我会用文字说明对应面板和菜单位置各位对照自己工程里的窗口找一下就行。1. 先别急着写代码easyAR 选型与激活阶段的三笔账很多教程一上来就讲识别、跟踪、坐标转换但实际项目的第一个坑往往出现在开始动工之前。我用一句话总结easyAR 项目 80% 的发布问题在选 SDK 版本、填 License Key 和规划资源加载方式时就已经埋下了。1.1 版本选型新 SDK 和老教程怎么取舍easyAR 的 SDK 更新节奏不算慢早期 3.x 的教程、博客、视频在搜索时能翻出一大堆而新版 SDK 的 API 和授权模式都变了不少。我见过不少开发者照着 3.x 的旧帖子去用新版 SDK结果发现接口对不上、授权不通过、渲染管线冲突最后绕了一大圈才明白是版本代差问题。我的建议很直接新项目默认用厂商当前主推的 Sense 版本和配套的 Unity 包不要因为“网上的教程多”去选旧版。同时Unity 版本也不要太激进先对照 SDK 官方文档里写明支持的 Unity 版本范围。比如某个 SDK 版本明确支持 Unity 2021/2022那就别为了尝鲜用 Unity 2023 的预览版否则构建时出现的渲染底层变化会把你的排查方向带偏。实测下来Unity 2021 LTS 当前主推 easyAR 版本是我试过最稳的组合。LTS 版本的工具链、IL2CPP 行为和 Gradle 版本都比较成熟不会因为 Unity 本身的问题干扰你判断 AR 功能的 Bug。1.2 License Key包名、激活与缓存机制easyAR 的授权机制是我在很多项目里见过最容易被忽视的环节。申请 Key 的时候你要填应用的包名这个包名必须和你最终发布到商店的包名完全一致。Android 看 applicationIdiOS 看 Bundle Identifier。很多人前期用默认包名后期要上架才改一改 Key 就失效运行时报错提示不匹配还得重新申请等审核白白耽误时间。激活方式也值得留意。首次联网激活成功之后SDK 会在本地缓存激活信息后续可以离线使用。但如果在没有网络的开发环境里首次初始化就会一直卡在激活失败状态。我的习惯是工程建好后的第一件事把正式包名先定下来然后在联网状态跑一次空场景完成激活后面就踏实了。1.3 素材加载方式StreamingAssets 还是 AssetBundleAR 项目里不只是识别图还有模型、视频、音频、配置表。素材放哪里会直接影响到双端发布和录屏体验。我一开始图省事所有东西都丢 StreamingAssets简单直接但 APK 和 IPA 的体积一下就上去了而且需要网络下载更新内容的场景也没法做。后来换成了本地 StreamingAssets 放一部分基础资源和识别图远程加载放 AssetBundle 或 Addressables。这里踩过的坑是AssetBundle 加载时机没有处理好导致用户相机已经识别到图模型还没加载出来画面上出现一段空窗期。正确做法是在进入 AR 场景前预热资源或者在识别成功回调触发时才异步加载并按需实例化至少给个加载提示否则体验很差。1.4 为什么要认真对待基础准备工作这三件事看起来都是“配置”类工作但处理不好后面排查问题时你会反复怀疑代码写错了实际上从源头就是版本组合和资源策略出了问题。跨平台 AR 项目的本质是环境工程不是纯粹的业务开发。把最底层的 SDK 关系理清楚后面 Android 和 iOS 的问题会少一大半。2. Android 端的发布链路环境、清单、权限一个都跑不掉Android 发布遇到的坑比 iOS 更“配置向”主要集中在构建环境、Manifest 合并和运行时权限三个层面。每一个都有典型的报错特征和排查路径。2.1 Gradle 构建失败先看 wrapper 再看 AGP 版本用 Unity 直接 Build Android 时最常遇见的报错是Gradle task assembleRelease failed with exit code 1。这个报错信息特别模糊真正的原因要看日志里更靠前的部分。我在项目中排查时发现绝大多数情况是 Gradle 版本、Android Gradle PluginAGP版本和编译 SDK 版本不匹配。我的排查顺序很固定先在工程的gradle-wrapper.properties里看distributionUrl指向的 Gradle 版本再去看自定义 Gradle 模板里声明的 AGP 版本。Unity 自带的构建脚本对两者有隐藏的兼容范围一旦用了过新或过旧的版本就会出现类似Minimum supported Gradle version is 6.7.1的提示。遇到这种直接回退到官方模板对应的默认版本就好别自己硬改。另外如果你的项目接入了第三方 Android 原生插件还要确认这些 AAR 要求的 minSdkVersion 和 targetSdkVersion 不能高于工程设置的版本否则编译时会报Manifest merger failed。2.2 Manifest 合并冲突provider 和命名空间是重灾区当工程里同时存在 easyAR 和录屏、分享、统计之类的插件时AndroidManifest 合并冲突几乎是必然的。典型报错是Manifest merger failed : Attribute applicationname value(... ) from AndroidManifest.xml或者Suggestion: add tools:replaceandroid:name。原因通常很简单多个插件都在清单里声明了同一个android:name的 provider 或 service。解决办法是在主工程Assets/Plugins/Android/AndroidManifest.xml的根节点加上xmlns:tools然后在对应冲突属性上用tools:replace指定覆盖。-keep class 你的easyAR包名.** { *; } -keepclassmembers class 你的easyAR包名.** { native methods; }这种 keep 规则要放在项目自己的 proguard 文件里并在 Player Settings 中开启 Minify 时引用。实测下来不开混淆的版本在 Debug 包上没问题但 Release 包一混淆就报UnsatisfiedLinkError所以规则一定要验证到位。2.3 运行时授权白屏把初始化放到权限回调之后Android 6.0 以后相机和麦克风都是运行时权限。AR 应用首启时会弹出系统权限对话框但 Unity 场景的Start()方法在权限弹窗出现之前就已经执行了。如果代码在Start()里直接初始化 easyAR 并打开相机第一帧就是黑屏或白屏用户要切后台再回来才能恢复预览。我之前在这个问题上卡了很久后来换成了授权遮罩方案进入 AR 场景前先检测权限未授权时弹一个半透明页面解释用途等用户授权回调成功后再创建 AR 场景并初始化 SDK。这样既解决了首帧白屏也避免了用户习惯性拒绝后 App 毫无反应的问题。2.4 生命周期回调退后台、回前台、相机被占用的连锁反应Android 端还有一个隐蔽问题应用退后台再恢复时相机预览偶尔会卡死或花屏。这多半是因为没有正确处理 easyAR 的生命周期SDK 底层引擎在后台被系统挂起回到前台后没有恢复渲染。我的做法是在 MonoBehaviour 的OnApplicationPause和OnApplicationFocus里做对应处理暂停时让 AR 引擎暂停渲染并释放相机预览继续时重新恢复。这里要注意OnApplicationPause(true)和OnApplicationFocus(false)在 Android 上会先后触发不要重复调用同一接口导致状态错乱。3. iOS 端的发布链路权限描述、ATS 与构建产物iOS 端的问题风格和 Android 完全不同。Android 大多是构建和合并配置iOS 则主要集中在权限描述、网络策略和 Xcode 构建产物上。一个共同点是报错信息都不够直观需要靠日志和日常经验预判。3.1 证书、描述文件与测试机轮换从 Unity 构建出 Xcode 工程后第一关是签名。新手最常遇到的报错是No profiles for ... were found或者Provisioning profile does not support ...。这不是 Unity 的问题而是描述文件里的设备 UDID 没有包含当前测试的 iPhone。我的流程是先在开发者后台把测试机 UDID 加进描述文件下载更新后的描述文件装到本机再让 Xcode 自动签名。这个步骤做对了Unity 侧不需要额外设置构建产物直接打开就能跑。需要强调一点签名这块保持简单别手动指定太具体的 profile交给自动签名更省心。3.2 权限描述缺失一碰就闪退日志还没有明显错误iOS 对权限描述是“硬约束”如果Info.plist里没有对应用途描述调用相机、麦克风或保存到相册时 App 会直接闪退而且在 Xcode 控制台里只有非常笼统的异常信息。这个问题的可怕之处在于它不报错名新手很难联想到是权限描述缺失。我的做法是提前把几个描述一次补齐。在Info.plist里增加keyNSCameraUsageDescription/key string需要使用相机进行AR识别/string keyNSMicrophoneUsageDescription/key string需要在录制视频时采集声音/string keyNSPhotoLibraryAddUsageDescription/key string需要保存录制的视频到相册/string即使当前版本只用了相机麦克风和相册描述也建议先写上去因为录屏功能很可能会用到其中一项等你人已经在用户手里了才发现描述缺失补丁和审核周期会很难受。3.3 ATS 限制HTTP 资源被拦截easyAR 项目里经常要加载远程识别图、模型或云端配置。如果这些资源地址没有使用 HTTPSiOS 会直接拦截控制台报错写着App Transport Security has blocked a cleartext HTTP。测试阶段可以用例外配置在Info.plist里加keyNSAppTransportSecurity/key dict keyNSAllowsArbitraryLoads/key true/ /dict但我不建议正式包全局放开 ATS。更稳妥的做法是给特定的测试域名加例外生产环境全部改用 HTTPS 资源。这个习惯在 Android 侧也要注意Android 9 以后默认禁止明文 HTTP需要单独配置networkSecurityConfig。3.4 Framework、Bitcode 与系统版本策略旧的 Unity 工程在构建 iOS 时会默认开启 Bitcode而现在的新 Xcode 对 Bitcode 支持已经逐步收紧构建很容易报警告甚至错误。到 SDK 相关插件的 Framework 不一定带 Bitcode 符号所以建议直接在 Unity 构建导出的 Xcode 工程里把Enable Bitcode设为 NO。渲染方面easyAR 在 Metal 环境下表现更稳旧设备偶尔出现MTLTexture cannot be used这类问题多半和 iOS 版本太低有关。我的做法是把最低系统版本设置在能稳定支持 Metal 的版本以上并避免使用 OpenGLES 作为备用渲染后端。真机上预览和录屏的表现都更正常。4. easyAR recording 录屏接入从能用到一个一个坑录屏是这次项目里耗时最长、问题最“丰富”的模块。easyAR SDK 提供的录屏功能和系统录屏不一样它是面向 AR 相机画面的视频编码能力你可以设置分辨率、码率、帧率、是否采集麦克风并把相机画面和渲染内容合成为视频文件。理解这一点是避坑的基础。4.1 基础用法把“相机画面”而不是“屏幕”给录制器录屏组件的核心逻辑类似这样初始化录制器设置输出参数把 AR 相机渲染到的 RenderTexture 持续传给录制器开始和结束录制最后拿到文件路径。我一开始误以为录屏会自动包含所有 UI 层结果录出来的视频里只有 AR 模型和相机画面界面上的按钮和提示一个都没有。后来才意识到渲染到屏幕上的东西和送进编码器的纹理是两条管线。如果你需要 UI 也出现在视频里必须把 UI 单独渲染到同一张 RenderTexture或者用额外的叠加层。这个容易忽略导致返工。4.2 黑屏、绿屏和花屏纹理格式与分辨率是关键录屏最常见的问题是输出文件黑屏。我排查后发现原因是录制纹理格式和编码器要求不匹配或者没有在正确的渲染回调时机把纹理填进去。建议固定使用 RGBA 格式的 RenderTexture并在渲染管线里确认纹理指针在每一帧都被正确更新。还有一个容易踩的坑是宽高必须是偶数。Android 的硬件编码器对奇数分辨率支持不稳定1281x721 这种尺寸就会绿屏或花屏改成 1280x720 就正常了。如果你的识别区域比例比较特殊先做裁剪或加黑边保证送入编码器的尺寸合法。4.3 录完没有声音麦克风权限和采样率设置录屏没有声音时第一反应不应该是去找音频 API而是先查权限。Android 端要在开始录制之前动态申请RECORD_AUDIO等授权成功后再启动录制否则编码器会静默地只录画面。iOS 端则要确认NSMicrophoneUsageDescription已配置并且用户首次授权弹窗没有被拒绝。如果用户之前误拒了不会自动再弹需要在界面里引导跳系统设置重新开启权限。音画不同步问题也不少见。编码器的音频采样率如果和采集端不一致时间越长偏移越明显。固定采样率比如统一用 48kHz同时录制过程中不要频繁切换音频设备基本能解决。4.4 竖屏录出横屏旋转元数据不可靠竖屏的 AR 应用录出来的视频在部分播放器里会横过来或方向错乱。视频文件的旋转信息是通过元数据保存的但 Android 很多播放器并不尊重这个元数据。最可靠的办法不是在事后旋转视频而是在录制时就把方向设置正确。如果 SDK 的录制器提供了方向参数就显式传入竖屏方向如果没有建议把 RenderTexture 渲染阶段就按目标方向处理避免依赖播放器行为。iOS 端相对好一些但也要检查AVAsset的输出方向是否符合预期。4.5 录制中断导致文件损坏生命周期要管住录制过程中用户切后台、接电话、锁屏录制器如果继续写文件产出的视频经常是损坏的无法播放。我的处理方式是在OnApplicationPause(true)回调里立即停止录制并关闭输出同时记录一个“录制被中断”的状态回前台后提示用户并允许重新录制。停止录制的时机也要注意调用停止接口后文件可能还在收尾写入不要马上读取文件大小或路径去分享等录制器的状态回调确认已经进入停止完成状态后再操作。4.6 Android 与 iOS 保存相册的两条链路录制完的视频默认存在应用私有目录要保存到系统相册Android 和 iOS 做法完全不同。Android 上可以用MediaStore插入一条视频记录老版本设备则用MediaScannerConnection.scanFile触发相册扫描。iOS 上要先申请相册权限再用PHPhotoLibrary执行保存注意保存完成回调是异步的需要更新界面时不要在主线程阻塞。5. 识别率与跟踪稳定性从本地图到真实世界的光线战争录屏搞定后识别率又成了另一个战场。easyAR 的图片识别本质是特征点匹配很多“识别的效果差”的反馈到最后都发现是识别图选择不当或环境因素干扰而不是代码 Bug。5.1 识别图选图对比度、非对称、避免大面积重复选识别图的艺术在于让算法有足够多的、稳定的特征点可抓。纯色背景、大面积模糊区域、上下完全对称的图案识别率都很低。最优的是高对比、纹理丰富、非对称的图比如杂志封面、带文字的墙贴、有明显几何结构的产品包装。打印机打出来的实体图测试时要注意纸张反光。真机的自动白平衡和强光反射会让特征点的亮度和颜色发生变化导致在编辑器里明明识别很快真机上却半天没反应。给实体识别图加哑光覆膜比换算法参数更有效。5.2 本地加载与远程下发数据库重建不能频繁触发识别图的加载有两种方式本地随包打包和远程下发。本地加载简单稳定但换图必须发版远程下发灵活但要处理网络失败、缓存、版本同步。我在项目里采用本地基础图集加远程增量图集的方式启动时先加载本地再在后台异步拉取云端列表并逐个加入数据库。这里有一个很隐蔽的坑频繁向数据库添加或移除识别图会导致短暂的追踪卡顿因为算法在重建索引。正确做法是批量操作并且不要在 AR 场景进行过程中持续增删尽量在启动阶段或切场景阶段一次性完成。5.3 多目标同时跟踪性能预算要提前做同时识别多张图时的性能开销不是简单线性增加。设备不同可用的同时跟踪数量差异很大。我在中低端 Android 机上测试过同时跟踪 4 张图以上时帧率下降明显。如果要保证流畅度我的做法是限制同时跟踪数量对距离最近的 1 到 2 个目标做高精度渲染其余目标只维持识别状态不实例化复杂模型。UI 层也可以通过目标列表选择的方式引导用户聚焦到某一个 AR 内容。5.4 跟踪丢失与恢复平滑过渡避免画面跳变相机大幅度晃动、遮挡目标超过半秒、光线剧烈变化跟踪都会丢失。代码上要监听跟踪状态从“正在跟踪”变成“丢失”再变回“重新跟踪”的整个过程。如果每次重新识别都重新刷新模型位置AR 物体会明显跳动或者角度突变。我用缓存位置和朝向的方式做平滑过渡在跟踪丢失期间隐藏物体或淡出重新命中后从缓存姿态附近逐步靠拢体验自然很多。6. 我的排查套路与顺手工具给后来者抄作业到这里整个项目的核心问题基本都踩完了。最后一节想聊聊排错方法论因为我发现很多人卡住不是因为问题复杂而是排查方向太散一会在渲染上找原因一会去查算法参数最后什么都没解决。6.1 三路日志一起看Unity 控制台之外的信息Unity 控制台只显示 C# 层的输出很多底层错误需要看系统日志。Android 上用 adb logcat过滤关键字比如EasyAR、Unity、Camera、Recorder按时间戳对齐到 Unity 日志的帧号能快速判断问题是出在渲染、生命周期还是权限。iOS 上直接连 Xcode 控制台同样过滤关键词注意设备日志和控制台日志要区分开。多插件的工程里日志中最容易误导人的是第三方 SDK 的干扰性报错先确认报错来自哪个模块再去工程里定位。6.2 最小复现工程把变量降到最少遇到诡异问题时我习惯立刻新建一个空场景只保留相机、一个识别图、一个录制器其他插件全部移除先看问题是否复现。能复现说明问题出在 easyAR 本身或我的用法上不能复现就说明第三者插件污染了上下文比如提前改掉了 OpenGL 状态或抢占了麦克风。这个方法救过我很多次尤其适合录屏黑屏这类现象型问题。别指望靠读代码就能想明白渲染层面的干扰跑一个干净场景出的结论比任何推理都可靠。6.3 打包体检表每次记录版本组合和测试机型跨平台问题里最容易让人觉得“莫名其妙”的是版本组合。我后来养成了一个习惯每次打包都在表格里记录 Unity 版本、easyAR 版本、Gradle 模板是否自定义、目标平台、测试机型、系统版本。问题出现时回退某一项组件基本能锁定元凶。Unity: 2021.3.20f1 easyAR: 4.x Android SDK: 33 Gradle: 6.7.1 机型: 某中端Android / iPhone 12这个表格看着简单实际排查中能节省大量时间。6.4 真机永远比编辑器更接近真相编辑器里的识别率、帧率、录屏效果仅供功能测试参考真机上的相机白平衡、自动对焦、陀螺仪数据都会影响 AR 表现。我建议拿到测试机后先做三件事基础识别测试、光线变化测试、录屏完整流程测试。这三条过了再谈后续优化每一条不过按上面对应的章节去查链路清晰很多。最后再分享一个小技巧我在工程里内置了一个自检测面板把 easyAR 初始化、权限申请、识别图加载、录屏开始和停止分别用日志点标记线上用户反馈问题时靠上报的日志点能快速判断卡在哪一步。跨平台 AR 发布本质上是环境差异的博弈把每个环节的可观测性做到位再乱的坑也能一个个填平。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。