做跨平台游戏这几年,我最大的感受是:在 Cocos Creator 里做游戏是一回事,把它真正变成 iPhone 上能下载的 App 又是一回事。刚入行时我以为引擎里点一下 Build,再用 Xcode 点一次 Run,就能直接拿去上架 App Store,结果光是理清开发者证书和发布签名的关系就折腾了半个月,后面还被苹果审核连拒三次。跑完整个流程之后回头再看,其实 Cocos Creator 打包 iOS 游戏并上架这件事并不复杂,但链条特别长,中间任何一环出错,反馈都不直观。
这篇东西不是官方文档的复述,而是我自己在 Creator 2.x 老项目、Creator 3.x 新项目里反复跑过 iOS 包之后攒下来的实操记录。适合第一次接触 iOS 打包的 Cocos 开发者,也适合已经上架过其他平台、但第一次被 iOS 工程和 Xcode 弄到头疼的人。我会按真实流程走一遍:构建前的工程配置、Creator 导出原生工程、Xcode 签名与真机调试、Archive 打包上传、TestFlight 测试,再到 App Store 审核时碰到的常见问题。每一步我都会把“为什么要这么做”讲清楚,因为只告诉你点哪里,下一次换个项目照样卡住。
1. 先理清 Cocos 到 iOS 的完整链路
1.1 为什么“点一下构建”不等于已经出包
Cocos Creator 的构建按钮很容易让人产生误会。尤其你以前只做过 Android 包,习惯了在编辑器里一键出 APK,到 iOS 这里会发现,Creator 构建完并没有直接生成一个可以上架的 .ipa,而是生成了一个原生 Xcode 工程。
这个工程才是真正能被苹果工具链识别的东西。后续的编译、签名、打包、上传,全部要交给 Xcode 或命令行工具处理。也就是说,上架 iOS 是一段“双构建”流程:第一段是 Cocos Creator 把你的游戏资源和脚本按原生工程需要的格式整理出来,第二段是 Xcode 读取这些内容,链接 Cocos 引擎库和系统框架,最终编译成 iOS App。
所以你在 Creator 面板里看到的“构建完成”,只代表第一段结束了。打开生成的目录,你会看到一堆 .h、.mm、.swift 文件,还有 ios 目录下的 xcodeproj 工程文件,后面所有原生操作都围绕这些东西展开。连 Android 都不需要依赖 Android Studio 的人,到 iOS 这一步也必须接受:Xcode 不是可选项,是必经环节。
1.2 Creator 2.x 和 3.x 在 iOS 构建上的差异
如果你的项目还是 Creator 2.4.x,构建 iOS 插件会直接生成一个可用的 .xcodeproj,位置通常在 build 目录下。这个工程相对简单,双击就能打开。Creator 3.x 之后,原生构建逻辑变化很大,工程改走 CMake 组织流程,很多原生存量代码都被收敛到引擎的 native 目录里。生成的工程路径一般是 build/ios/proj,但可执行的名字会根据你填的包名变化,别习惯性地只找固定名称。
在 3.x 里要特别注意,构建选项里有一项叫“生成 Xcode 工程”,它和“生成资源”有时是分开的。资源生成慢,工程生成快,如果你只点了构建资源,发现目录里没有 xcodeproj 别奇怪,回到构建任务里把生成工程的任务补上就好。
版本之间的另一个差异是原生插件的接入方式。2.x 时代很多国内 SDK 组件都有成熟的 OC 或者 JS 绑定方案,3.x 初期因为原生目录结构大改,不少第三方插件一度没跟上,导致很多人卡在“引擎升级后原生不能编译”这一步。如果你要上架的是一款包含登录、支付、统计等原生能力的游戏,建议先确认你依赖的 SDK 明确支持当前 Creator 版本,而不是先写完游戏逻辑再去踩原生兼容性的坑。
1.3 你需要准备哪些账号和工具
打包 iOS 不能绕开的硬性条件是开发者账号。个人开发者账号或公司开发者账号都能上架 App Store,区别主要在 Team 名称、团队成员管理和 App 的归属主体上。个人做小游戏,个人账号完全够用。
账号里几个角色要说清楚:Account Holder 是账号所有者,拥有最高权限;Admin 能管理证书、设备和 App;App Manager 能管理 App 的元数据和用户,但证书方面权限有限;Developer 只能真机调试。Cocos 属于引擎层,不需要参与开发者账号管理,但你有合作伙伴或外包团队协作时,记得角色分配会影响谁能提交审核版本。
除了开发者账号,你还需要几样东西:一台能装 Xcode 的 Mac、Xcode 本体、Cocos Dashboard 对应版本的 Creator、可用的 Apple ID。Xcode 版本最好和系统版本配套,别拿最新系统配老版 Xcode,打包时会遇到一堆签名工具链的兼容报错。
提示:首次准备环境时,别把时间花在“装哪个模拟器”上。模拟器 Runtime 可以后续按需下载,但 Xcode 必须装完。Cocos 游戏上架前必须用真机验证,模拟器只适合快速看 UI 或粗略功能,很多原生 API 行为和性能数据在模拟器上不准。
2. 构建前要检查的基础配置
2.1 包名、版本号、构建号,一个都不能随意
Cocos Creator 项目里有个地方叫“项目设置”,其中“包名”这一项几乎决定了 iOS 上架的世界里 App 的身份证号。苹果生态里它叫 Bundle Identifier,规则是反向域名格式,比如 com.mycompany.matchgame,只能包含字母、数字、点和连字符,不能有下划线。
包名是项目创建后最不该改的东西。一旦你用这个包名在某个渠道出过包、接过后台数据、注册过推送,后面再改包名,所有关联关系全部断裂,甚至会出现“设备上覆盖安装不成功”“支付回调校验不过”这种历史遗留问题。所以项目初始化时,一定先想清楚最终要上架的主体域名和产品名,一次性填好。
另一方面,iOS 有 Version 和 Build 两个容易搞混的概念。Version 是对用户展示的版本号,比如 1.0.0;Build 是内部递增的构建号,用户看不到,但每次上传都必须大于上一次,否则 App Store Connect 会提示“构建版本号非法”。我的习惯是:版本号只在功能迭代时手动加,Build 号则直接用一个脚本或者变量在构建时递增,避免每次手动改还容易漏。
很多人在 Creator 项目设置里只填一次版本号,后续每次打包都用同一个值,等到上传 App Store 就会卡在“Build 已存在”这个异常上。正确做法是上一版 Build 为 1,下一个出包至少是 2,哪怕 Version 还是 1.0.0 也可以;等正式发新功能时再把 Version 改成 1.0.1,Build 重新从 1 开始。
2.2 图标和启动屏,最容易拖慢进度的地方
iOS App 图标有一套比较老的尺寸规范,不同设备会用到从 20pt 到 1024pt 的多种规格。好在你把图标上传到 App Store Connect 后台时,系统会根据你提供的 1024x1024 无透明通道大图自动生成各尺寸图标,Xcode 工程里其实也会用 Asset Catalog 来自动处理,不需要手做十几个 png。
但 Cocos 游戏工程的图标和 Launch Screen(启动屏)仍需要在 Creator 里配置。Creator 的“项目设置”里如果提供了图标,构建时引擎会把它写入原生资产目录。我第一次做的时候,只改了桌面的 1024 大图,忘了看“竖屏/横屏”的启动图方向,结果安装到手机上,启动瞬间有一块黑边或拉伸变形,观感非常业余。
Launch Screen 的推荐做法是固定颜色 + 居中的 Logo,不要搞复杂的动画。苹果后台审核时,如果启动屏图片显得过于简陋或者比例错乱,不影响功能,但确实会在“视觉设计”这一层被扣分。还有一点经常被忽略:游戏如果支持横竖屏切换,启动屏也要提供多方向的适配,或者直接设定只支持某一种方向,避免提交后用户在系统设置里强制旋转出现布局异常。
2.3 iOS 权限声明,写多了不行,写少了会崩溃
游戏经常是到真机测试阶段才暴露权限问题。比如你的游戏接了某个广告 SDK,SDK 内部需要访问用户相册来保存一张分享图,但你的 Info.plist 里没有写任何相册用途描述。真机上 SDK 一旦调用相册接口,App 就会直接闪退,控制台会输出类似“This app has crashed because it attempted to access privacy-sensitive data without a usage description”的日志。
Cocos 引擎自带的编辑器不会主动帮你生成所有权限文案,它默认只是在资源层做了一个最小配置。你需要根据游戏实际用到的能力,在原生工程的 Info.plist 里加对应键值。常见的有:相机权限 NSCameraUsageDescription、相册权限 NSPhotoLibraryUsageDescription、麦克风权限 NSMicrophoneUsageDescription、位置权限 NSLocationWhenInUseUsageDescription。
反过来,也不要盲目地把所有权限字符串都写进 plist。苹果审核时有静态扫描机制,如果你的 App 其实没有调用相机功能,Info.plist 却存在相机权限描述,审核人员可能会追问理由。第一次过审时,我因为批量拷贝别人的权限模板,平白无故被要求解释为什么要用摄像头,最后只能发个新版去掉多余描述才过审。
2.4 隐私政策、ATT 弹窗,这些不是小事
如果只是开发一个单机休闲游戏,你可能觉得隐私政策完全没必要。但 App Store 上架时,几乎所有需要收集用户数据的 App 都必须提供隐私政策链接,且链接必须在你提审前填到 App Store Connect 的对应字段里。即使你的游戏完全不上报数据,苹果也默认你需要解释数据收集情况。
对于 Cocos 游戏来说,真正常见的坑是广告归因。接了 AdMob、Meta 广告或者一些国内聚合广告 SDK 后,SDK 可能会读取 IDFA(广告标识符),此时必须遵守 App Tracking Transparency 规则。简单说,你要在 Info.plist 里配置 NSUserTrackingUsageDescription,并在 App 启动后弹 ATT 权限框,用户同意后才能追踪。
如果一个功能确实没有用到 IDFA,我建议直接不要碰广告 SDK 的追踪开关,并且提审时在后台的数据收集栏中如实选择。苹果的机器审核会探测代码里是否包含获取 IDFA 的逻辑,如果探测到但后台隐私声明没写对应用途,大概率会被打回重审。见过不少团队因为“明明没做追踪,但 SDK 默认带了”而被拒,排查起来极其被动。
另一个经常被提审备注要求说明的是:你的游戏是否需要用户登录,是否支持删除账号。如果游戏有账号体系但 App 内找不到“删除账号”入口,苹果会以 5.1.1(v) 的 App 账号删除条款拒绝。这一点对很多休闲游戏是没有影响的,但如果你的游戏接入了第三方社交登录,就一定要设计好账号注销逻辑。
3. 从 Creator 导出原生工程:操作与避坑
3.1 构建面板的关键选项怎么选
Cocos Creator 顶部菜单找到“项目”->“构建发布”,弹出构建窗口后,先点击“新建构建任务”。平台选择 iOS,这里不要选成“iOS 模拟器”或“Mac”,除非你想本地调试。
在构建选项里,包名先用刚才在项目设置里确认好的那个 Bundle Identifier,其他几个常用项值得逐一说清。
MD5 Cache 建议开启,它会让资源文件名变成基于内容的哈希值,好处是热更新时能有效避免老资源缓存残留。缺点是每次更改资源后构建出来的文件名不同,如果你还接了自己写的资源服务器,需要认真对待资源版本表,否则新旧客户端会加载混乱。
Polyfills 和脚本压缩,默认开启就好。iOS 的 JavaScriptCore 对 ES6+ 的支持这些年越来越强,但引擎内部的运行环境和浏览器不完全一致,保留 polyfill 可以避免莫名其妙的 API 报错。
纹理压缩格式保持默认或选择支持 iOS 的 PVRTC / ASTC。iOS 设备从 A13 以后对 ASTC 支持很好,如果你的游戏用了大量高清图,资源体积精简约 30% 是完全可能的。注意如果你在 Android 上已经选了 ETC2,到 iOS 构建时不要照搬同一套配置,否则可能出现非标准纹理。
构建完成后,Creator 窗口会显示出输出目录。3.x 项目打开 build/ios/proj 下的 xcodeproj,2.x 的构建目录一般是 build/ios 或 build/ios/proj,按实际情况找。
3.2 Xcode 工程打开后先改什么
很多新手拿到 xcodeproj 后的第一反应是立刻点 Run,结果报错说签名不对。先别急着改签名,你需要先确认工程里的 Base Bundle Identifier 和刚才 Creator 里的包名一致。Creator 构建时通常会把包名写入,但不排除 Cocos 的版本缓存导致少数项目出现旧值,尤其是从老工程升级过来的,出现一个后缀为 .ios 的奇怪包名并不罕见。
按习惯,我打开 Xcode 后先检查两处:Target 里的 General 页签下的 Bundle Identifier;Signing & Capabilities 里的 Team 是否为空。Cocos 生成的工程默认使用手动签名,你要在 Signing 里把 Automatically manage signing 勾上,然后在 Team 下拉栏选择你的开发者团队。如果没有设置签名,后面真机跑不起来,Archive 也会在导出阶段直接报 missing signing identity 之类。
如果团队下拉列表是空的,多半是 Xcode 里还没登录 Apple ID。打开 Xcode 的 Settings -> Accounts,添加你的开发者 Apple ID。这里只负责账号登录,真正签名的证书会由 Xcode 在勾选自动签名后自动创建并下载到本机钥匙串。
3.3 真机调试前,先把签名和设备配对搞明白
游戏在模拟器上能转是一回事,iPhone 真机能不能稳定 60 帧是另一回事。尤其 Cocos 游戏涉及引擎渲染、内存纹理占用、iPhone 发热降频这些变量,必须上真机验证。
真机调试的第一步是让 Xcode 认识你的设备。用数据线连接 iPhone,手机端会提示“是否信任此电脑”,点击信任后再到手机的“设置 -> 隐私与安全性 -> 开发者模式”里打开开发者模式。这一步在新版 iOS 里是必须的,很多人在 Xcode 里看到设备但点 Install 失败,原因就是没开开发者模式。
然后打开 Xcode 菜单 Window -> Devices and Simulators,左侧列表中能看到你的设备。如果设备旁边有黄色感叹号,点击它,系统会提示 Register Device。注册设备这一步会把你的 iPhone UDID 加入到开发者账号名下。
在 Automatically manage signing 开启时,Xcode 会自动在开发者后台创建包含你这个设备的 Development Provisioning Profile,不需要手动去网页端操作。如果你硬要选择手动配置文件,又没在后台把当前设备加进证书,那大概率会出现“no devices registered”之类的提示。
真机跑起来后,首包会比较慢。Cocos 3.x 首次启动需要在 Xcode 里继承并编译一半引擎静态库,长则十几分钟都是正常的。图标首次出现在手机桌面并显示“未受信任的开发者”时,进设置去信任一下就好。这是个人开发者签名的老惯例,不是你的包有问题。
3.4 原生工程和第三方 SDK 的兼容性问题
纯 Cocos 官方能力构建出来的 iOS 原生工程,在 Xcode 中一般能直接编译通过。但只要是接入了统计、广告、登录、支付之类第三方原生 SDK 的游戏,原生编译环节一定是最容易翻车的。
常见问题之一是库或源码只支持真机架构,不带模拟器 x86_64/arm64 slice。你在模拟器上 Build 时报错,可能不是代码问题,而是 SDK 本身限制了模拟器运行。解决方法是尽量用真机调试;如果确实需要模拟器,就去确认该 SDK 是否有模拟器版本。
另一个常见问题是重复符号(duplicate symbol)。Cocos 工程里可能因为原生插件配置重复,集成了两个相同底层库的不同编译产物。遇到这类问题别急着改 Build Settings,先检查 Cocos 项目里的“原生插件配置”有没有重复引用。
还有一类更容易被忽略:Cocos 3.x 的原生工程使用了 CMake 来组织第三方原生代码,如果你的 SDK 是通过 CocoaPods 引入的,可能出现 Podfile 与工程签名 Target 冲突。此时在工程目录下执行 pod install,然后重新打开 .xcworkspace 而不是 xcodeproj。很多人看到 Cocos 默认生成 xcodeproj 就一直打开它,完全没意识到 Pods 项目没有被加载进来,导致所有通过 Pod 集成的 SDK 方法都找不到。
我在一个广告聚合项目中就碰到过这种问题,Xcode 报Undefined symbols,按网上教程一顿清理 DerivedData 也没用,最后发现是项目自从某次 Creator 升级后,构建脚本不再默认执行 pod install,手动装一次 Pods 才恢复正常。
4. Xcode 正式打包与 TestFlight
4.1 Archive 前必须做的检查清单
当你确认游戏在真机上已经能稳定运行、性能不掉帧、资源没有明显缺失以后,就可以进入正式打包环节了。Xcode 顶部菜单里的设备要先选择“Any iOS Device (arm64)”或“Generic iOS Device”,而不是一根真机。只有选择了通用设备,菜单里的 Product -> Archive 按钮才会亮起。
Archive 就是归档,它会生成一个带签名的 .xcarchive 文件,里面是发布用的完整应用产物。点入 Archive 之前,我建议你按下面的清单再检查一遍,任何一项漏了,都会延长 debug 时间:
- Current Project Version 下 Build 号不小于上一次上传的构建号;
- Target 的 Deployment Target 是否和你的最低支持版本一致,很多第三方 SDK 对最低版本有要求;
- 是否开启了 bitcode。老版本 Xcode 里常见 bitcode 选项,新版已废弃,如果你因为老工程遇到 bitcode 编译错误,直接关掉即可;
- 签名 Team 是否正确选择为 Distribution 对应的团队;
- Info.plist 中的版本号和 App Store Connect 后台准备提交的版本号一致。
Archive 的编译通常需要几分钟到十几分钟。编完后 Xcode 会自动弹出 Organizer 窗口,左边列表里能看到刚生成的归档。此时先别急着上传,可以顺手点窗口右侧的“Distribute App”,或右键归档导出,但在导出方式上要选 App Store Connect(而不是 Development 或 Ad Hoc)。
看日志时如果出现 File was built for archive which is not the architecture being linked,说明某静态库不支持当前架构,通常是你工程里混入了只有模拟器架构的调试库,重新拉取发布版 SDK 即可。
4.2 上传到 App Store Connect:后台也要先建好“空壳”
Xcode 上传其实很简单,但它有一个前置条件:你必须在 App Store Connect 后台已经创建了一条 App 记录,并且 Bundle ID 要跟工程里的完全一致。
后台创建的入口是“我的 App”里左上角的加号,选择“新建 App”,取一个在 App Store 上展示用的名称、主语言,再选包 ID。如果你在这个界面里搜索不到刚才那个 Bundle ID,说明开发者账号里还没有注册相应的 App ID,需要先去 Certificates, Identifiers & Profiles 页面把 Identifiers 注册出来。
常见错误发生在后台根本没建 App,就急着用 Xcode 的 Distribute App,上传到一半报 “No suitable application records were found.” 这时不是重新签名的问题,而是后台没有对应记录可以接收这个上传包。
App Store Connect 后台需要填的信息非常多,但必须一次性填对的是“App 信息”页签的内容:描述、分类、年龄分级、隐私政策 URL。描述建议精确说明“这是什么类型游戏、玩家要做什么、是否有内购”。分类一旦填错,会影响推荐位,早期不建议反复修改,因为审核对话里可能会留下记录。
提交到 Xcode 后,上传的方式有两种:一种是在 Organizer 里点 Distribute App,Xcode 会直接把构建传到后台;另一种是用 Xcode 自带的 Transporter 工具上传 .ipa。Transporter 更稳定,适合网络不好的场景,因为可以断点续传。第一次上传时如果你看到上传进度槽长时间停在 90% 之后报网络错误,先看看系统代理是否有干扰,或者换 Transporter 试试。
4.3 TestFlight:不等于审核通过,但能暴露 80% 的坑
上传成功后在 App Store Connect 后台“TestFlight”页签里,你会看到这个构建开始“处理”。处理时间有时只需几分钟,有时会长达半小时,取决于服务器负载。构建状态变成“可供测试”后,就可以添加内部测试员或外部测试员。
内部测试员其实就是你开发者账号里的成员,不需要经过审核,添加后对方直接会在 TestFlight App 里看到这个版本。外部测试员需要邮箱邀请,首次提交外部测试时苹果会做一次 Beta App Review,不是完整审核,但会检查明显违规点,通常几小时到一天内会出结果。
我的建议是:把“内部测试”当成在真实 iOS 设备上进行全流程测试的最后机会,至少安排 3~5 名不同机型的测试者。因为 Cocos Creator 在不同 iOS 版本上的 WebView、字体、本地存储行为都有差异,只在自己的一台 iPhone 上测,很难发现老 iPhone 内存不足、刘海屏安全区遮挡按钮这类问题。
TestFlight 版和最终审核版在功能上几乎一样,审核团队下载的也是类似版本。如果在 TestFlight 上出现“启动就崩溃”“资源加载不出来”,千万不要期待正式审核能蒙混过关。苹果审核员拿到 App 后会先做基础启动测试,启动崩溃是最常见也最严重的拒绝理由。
5. 提审前与审核后的高频问题实录
5.1 4.3 被拒,App 撞脸了怎么办
4.3 Spam 是中文开发者圈里的网红条款。苹果审核文案一般比较模式化:“We noticed your app shares a similar binary, metadata and/or concept as apps submitted by another developer.”
如果是一手打造的原创游戏,但使用了大量第三方商店购买“模板”,那被 4.3 命中非常正常。审核系统会把类似的二进制结构、界面布局和资源素材聚合到一个签名体系里。比如 A 开发者提交了 10 个长得一样、只换皮肤的球球游戏,苹果机器审核直接会快速筛出相同点。
如果你的游戏确实包含原创玩法和视觉,但依然被判 4.3,先别在论坛搜“如何过 4.3”这种旁门左道。最可靠的做法是回 Apple 的 App Review 信息里提交一条申诉说明,解释玩法差异点,并附上视频链接。注意,这个视频不能是录屏然后拼接演示,而应该在真机上从启动开始,逐步展示核心玩法,最好带上可交互过程。
另外一个更容易做到的调整是:审视你在 App Store Connect 填的分类、截图、文案是否和别的模板 App 太接近。如果你选择“娱乐”分类,但截图第一张和竞品一样是礼包弹窗,更容易被判定为相似引用。把截图改到玩法实际场景,每张截图上标注一句功能说明,这在机器审核眼里是很强的差异化信号。
5.2 5.1.1 隐私问题,为什么改了权限还不行
隐私相关被拒的具体描述往往很长,核心其实是几类:缺少隐私政策 URL、权限用途文案不清、数据收集说明与代码行为不一致。
第一次做中轻度休闲游戏时,我的隐私政策是从某个开源源码仓库里复制的一份通用文本,只改了 App 名称。上传后审核人员指出我没有说明第三方广告 SDK 会收集哪些数据。后来我只能回后台逐项核对项目里每个 SDK 的能力,写明数据用途,比如“AdMob:用于广告投放,可能收集设备信息”,才算通过。
如果你采用了“用户点击不同意隐私政策就退出 App”的做法,请在提审备注里解释清楚。这在国内应用市场很常见,在 iOS 上也是允许的,但需要注意点是:隐私弹窗文案必须明确说明收集数据的类型和用途,不能只写“优化用户体验”这种模糊描述。
关于 IDFA,有 Cocos 开发者把 ATT 弹窗文字写得过于宽泛,比如“用于广告个性化推荐”,但你的游戏并没有投放个性化广告能力。审核人员会在隐私详情里核对,写得太宽反而会带来麻烦。按真实用途写就好。
5.3 需要登录的游戏,没给测试账号会被打回
如果你的游戏包含账号登录、排行榜、好友对战等需要联网服务的功能,审核人员必须要一个有效测试账号才能完整体验游戏。很多开发者只把精力放在包体上,忘了在提审备注里写账号密码,结果审核员无法进入游戏,直接以“无法完成审核”为由拒绝。
提供测试账号时注意不要给真实充值过的账号,也别给后台权限过高的管理员账号。审核员会使用测试账号体验核心玩法,如果你给了管理员账号,对方可能误触后台界面并认为 App 包含未注明的后台管理功能。
使用“通过 Apple 登录”的合规性同样值得关注。如果游戏提供微信/QQ/Google 等第三方登录,并且 iOS 审计师要求,你必须同时提供“通过 Apple 登录”作为等价选项。Cocos 项目如果只做中国大陆发行且没有第三方登录,就不受影响;一旦接海外账号体系,这一条尽量提前做,免得提审后打回再补,来回浪费好几天。
5.4 由 WebView 引发的误判
Cocos 游戏内部嵌入 WebView 很常见,比如用来加载用户协议、活动页面或广告。但苹果对“单纯包了一个网页”的行为极度反感,审核员看到 App 内显示大面积网页内容时会怀疑你是不是把网页套壳成 App 提交。
为了减少这种误判,你的核心玩法一定要在原生渲染的 Cocos 场景里体现,不要让 WebView 成为游戏打开后的第一个界面。更不要做成“进入 App 默认先跳到一个 H5 活动页”的逻辑,苹果审核员对这种模式相当敏感。我之前调整过策略:启动后只短暂判断一个开关,如果网络超时则直接进入离线主界面,不让审核员长时间停留在 WebView。
WebView 在 iOS 上的内存使用也要小心。Cocos 3.x 的 iOS WebView 渲染背后是 WKWebView,加载复杂 H5 页面时内存占用增长明显。有些 iPhone 老机型会因此触发系统强杀。如果你发现 App 在真机上跑一会儿闪退,但日志里又看不到明显异常,建议先看是不是 WebView 页面频繁重定向导致的内存激增。
5.5 高频审核与被拒问题的速查表
网上案例五花八门,但 Cocos 游戏被拒最集中的区域往往都围绕这么几个点。我把平时做技术支持和答疑时最高频的问题整理成一个速查表,提审前后可以对照自查。
| 现象 | 常见原因 | 解决建议 |
|---|---|---|
| 启动后直接闪退 | 资源加密或热更新路径问题、Info.plist 权限缺失 | 用 TestFlight 复现,看 crash log 是 ObjC/C++ 崩点还是 JS 层崩溃 |
| 上传报 ITMS-90167 | Bundle ID 与后台不一致 | 后台 Identifiers 和工程 Target 逐个比对 |
| 上传后后台长时间没有 Build 显示 | 构建号为 0 / 重复 / 上传不完整 | Build 号改为正整数,重新 Archive,或换 Transporter |
| 4.3 被拒 | 模板资源、同质玩法和文案 | 提供核心玩法视频申诉,修改截图与文案,强化原创证据 |
| 5.1.1 被拒 | 隐私政策 URL 不可访问 / 数据收集说明不一致 | 补充合法可访问的隐私政策页,后台 App 隐私栏如实填写 |
| 1.2 被压到无法安装 / 审核无法打开 App | 证书异常导致“未受信任开发者” | 测试设备信任证书后再提审;发行包用 Distribution 签名 |
| 访问相册/摄像头时崩溃 | 缺 NSPhotoLibraryUsageDescription 等键值 | 在 Info.plist 中补权限描述 |
这里没有写“百分之百能过审”的加速器,因为审核本来就是个规则判断过程。你把属于自己产品的每一环都做干净,审核失败的几率自然会降低。
6. 上架之后还想说几句
6.1 更新版本时要同步哪些信息
第一次上架成功后,很多人觉得流程结束了,但游戏只要在运营,版本更新是注定要面对的。iOS 的更新流程和首次上架稍有区别,难点在于“同步信息”而不是“重新提交”。
新版本在 Creator 里构建时,如果你是同一套 Bundle ID,签名逻辑不用重来。Version 号从 1.0.0 改成 1.1.0,Build 号随便从 1 开始或延续之前的递增都可以,但必须大于上一次构建号。App Store Connect 里新建一个版本后,等上传构建处理完,把它选择到对应版本上,再走一次提交审核。
另一个容易漏掉的是“隐私信息”栏目的变化。新版本如果新增了申请相机权限用于拍照、新增了统计 SDK、新增了账号删除功能,记得回到 App Store Connect 的 App 隐私部分更新,否则就可能因“App Privacy 标签与 App 实际行为不符”被打回。这块很多人理所当然觉得只有第一次填写时才做,实际上每次变更都该检查。
6.2 崩溃日志和原生问题的排查方法
上下架之后,游戏在用户 iPhone 上出现崩溃,你是看不到代码异常堆栈的,只有用户的描述和后台的崩溃日志。这时需要一位能看懂 Xcode Organizer 或者 App Store Connect “崩溃”栏的人去定位问题。
Cocos 游戏的崩溃日志通常分成两种。如果你在 JS 层写代码,比如空指针调用、TypeError,Xcode 日志里往往只有一行“JavascriptCore”异常入口,看起来像原生崩溃,但真正错误还得靠你在引擎里开启日志穿透,或者用 Cocos 的报错信息捕获来定位。如果是原生层崩溃,比如纹理内存爆了、音频底层出错,日志会直接显示某个 .mm/.cpp 文件的行号。
我有个印象很深的项目:上线两周后用户反馈某张地图频繁闪退,但本地和 TestFlight 测试都没有问题。后来通过崩溃日志发现,崩溃集中在 iPhone 8 以下机型,并且发生在纹理上传的 GPU 接口处。排查之后发现是场景里有一张不带 mipmap 的超大图,在高分辨率设备上加载正常,在老设备上纹理内存超限被系统强制杀掉。解决办法很简单,把资源拆分为小图或启用 mipmap,但如果没有崩溃日志和真机内存观测,这类问题真的要靠猜。
所以上架后不要只在后台看下载量和收入,开发者的核心工作是把这套“版本发布 - 线上监控 - 崩溃定位 - 下版修复”的节奏跑顺。打包上架不是终点,游戏能持续稳定地被玩家玩下去,才是一款产品真正活着的开始。