ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

iOS审核拒审排查:设备信息相关配置与构建参数全解析

iOS审核拒审排查:设备信息相关配置与构建参数全解析 做iOS开发这些年每次提审前我最怕看到的不是功能缺失类的审核反馈而是那种和设备信息沾边的拒审理由。苹果给的反馈往往就一两句话既不说清是哪段代码的问题也不指明该改哪个配置项开发者只能自己一层层排查。实际上我踩过几次坑之后发现设备信息类拒审的真正根源绝大多数不在业务代码里而是藏在Info.plist、描述文件配置和IPA构建参数这三块。这三个地方有一个共同点都是提审前容易被当成基础配置而忽略的环节。但只要其中一个和设备的兼容性、标识符或权限声明对不上审核小组在真机上做安装和功能检查时就会暴露问题。本文把我自己处理过的拒审案例和验证方法完整写出来目标是让准备提审或正在处理5.1.1相关反馈的开发者能拿着清单一步步自查而不是再靠猜。1. 先摸清方向设备信息为什么是审核重灾区1.1 审核政策里给设备信息划的红线苹果审核指南的5.1.1主要涉及数据收集和存储其中对设备信息有一条基本原则如果App采集的是与身份相关的设备数据比如设备标识符、位置、健康信息等必须先征得用户同意并在隐私政策中披露。这听起来很笼统但落实到审核执行层面苹果主要看三件事代码里是否读取了受保护标识符Info.plist声明的权限和用途是否匹配以及隐私政策链接与文案是否真实覆盖了数据收集行为。另一个需要留意的政策点是App不得使用私有API。很多设备信息类拒审就是这么来的。开发者为了做设备指纹或者统计渠道可能会用一些偏方去读取MAC地址、UDID或者私有框架里的接口这些在Xcode编译时不报错但上传App Store Connect后苹果的静态分析会扫出二进制里的关键符号一旦命中就是必拒。这个机制我在后面第4章会展开讲。1.2 被拒的直接原因和隐藏原因我处理过的设备信息拒审可以分成直接和隐藏两类。直接的比较好理解代码里用了系统早已废弃的uniqueIdentifier或者通过私有接口读取硬件UUID这类属于踩了明线收到邮件后改代码就行。但更常见的是隐藏型。比如Info.plist里的UIRequiredDeviceCapabilities多写了一个gps实际App根本不用定位审核员在真机上发现设备能力声明与功能不匹配也会被扣上设备兼容性的帽子。还有一类隐藏问题出在构建环节。之前有次CI打包Build Active Architecture Only被误设成了YES打出来的IPA只有x86_64架构上传之后审核员用真机安装直接显示App不兼容此设备。这类拒审邮件甚至不会提架构只会笼统地说App无法在当前设备上运行。所以排查范围一定要包含构建配置而不能只在代码和plist里找问题。2. Info.plist从源头管好设备的身份信息2.1 UIDeviceFamily不要拍脑袋填这个键管的是App能安装到哪些设备系列。1表示iPhone/iPod touch2表示iPad。Xcode里勾选Universal时会自动生成一个包含1和2的数组。很多老项目从单一iPhone版本改成Universal时会漏改这里但更常见的坑是反过来项目原本只声明支持iPhone审核员在iPad上用兼容模式查看发现界面错乱然后被以App未正确支持声明的设备类型退回。设备声明的范围越广你需要保证的适配范围就越广。用命令行检查也很简单进入解包后的.app目录执行plutil -p Info.plist | grep UIDeviceFamily。如果输出是数字1说明只支持iPhone如果是1和2那就得确定所有页面在iPad上都没有明显问题。这里没有中间选项原则就一条声明什么就要保证什么能跑。2.2 UIRequiredDeviceCapabilities默认值才是最安全的这个键是审核和App Store双重把关的。它直接影响应用在App Store上的可下载范围如果声明了location-services无GPS的iPod touch就无法下载。所以误声明会导致能下载的人变少而声明了实际App不用的能力又会在审核阶段被质疑设备能力与功能不匹配。常见的安全写法是只保留最基本的arm64因为所有现代iOS设备都支持arm64它不算额外能力。不要随手把accelerometer、gyroscope、still-camera这些能力填进来除非你的App确实在功能流程里强依赖这些硬件并且有正常的调起逻辑。审核员会拿设备能力声明和功能演示做对照声明了却不使用就是给对方递了一个拒审理由。如果现有工程的UIRequiredDeviceCapabilities已经包含了很多项那你需要逐条对着代码确认是否有硬件调用、是否有系统授权用途说明。没用的就删掉。删除后记得更新版本号再重新构建因为App Store会缓存同版本号的构建包直接传同版本容易出状态混淆。2.3 权限描述与隐私声明没有用途说明就是裸奔iOS很多设备数据是通过系统权限接口拿到的比如相机、定位、麦克风、通讯录。Info.plist里对应的键NSCameraUsageDescription、NSLocationWhenInUseUsageDescription等不能只是空字符串。苹果要求文案里必须讲清楚为什么需要这个权限。写得含混不清是会被拒的。一个比较实际的技巧是文案里不要写为了提供更好的用户体验这种空话而是具体到操作动作比如拍摄商品照片用于发布商品信息这样既过审也是给用户的真实交代。除了权限描述还要配置NSUserTrackingUsageDescription用于系统级的追踪授权弹窗。这个是设备广告标识符合规使用的前提。iOS 14.5以后如果代码里调用了广告标识相关接口但Info.plist缺少这个键或者弹窗被绕过直接就是审核红线。我见过有些团队想偷偷读IDFA结果被静态扫描揪出来拒审邮件里明确写了NSUserTrackingUsageDescription is missing这就非常被动了。2.4 隐私清单2024年后的硬门槛隐私清单Privacy Manifest是2024年后App Store上传的硬性要求。新建的Xcode项目会自动生成PrivacyInfo.xcprivacy老项目则要手动或通过工具补上。清单里需要声明收集的数据类型和访问的系统API及原因。设备信息相关的收集项要在这里如实填写包括设备标识符、设备型号、系统版本等类别。很多团队栽在隐私清单的不完整上。比如某个SDK内部通过NSUserDefaults存了设备状态但主工程里的Privacy Manifest没有声明对应的NSPrivacyAccessedAPICategoryUserDefaults上传后Xcode会警告严重时变成审核反馈。我的建议是把线上App用到的所有第三方SDK列一遍逐个检查它们的文档或自带清单再合并到主工程的隐私清单里。宁可多声明也不要漏声明。多声明顶多是审核员发个询问漏声明大概率是拒审。当然完全无关的隐私权限也不建议乱加避免出现新的不一致。3. 描述文件配置设备兼容性的隐藏开关3.1 一条命令看懂mobileprovision里的设备信息描述文件里最容易被忽略的就是它和设备的直接关联。严格来说描述文件.mobileprovision是苹果签发的一份授权凭证里面写了这个App能用哪些能力、能装到哪些设备上。用下面这条命令可以把签名外层剥掉直接看到明文内容security cms -D -i YourApp.app/embedded.mobileprovision输出是一个plist结构。里面重点看这几个字段ApplicationIdentifierPrefix、ExpirationDate、Platform以及Entitlements里的application-identifier、get-task-allow、aps-environment等。如果Platform不是iOS或者ExpirationDate已经过期构建产物在审核安装阶段一定会出问题。get-task-allow尤其关键App Store类型应该为false开发类型通常为true如果反了说明这个包压根不是给审核用的。3.2 开发与Ad Hoc描述文件的设备列表陷阱开发描述文件和Ad Hoc描述文件里都有ProvisionedDevices字段列着一串UDID。如果打的是Ad Hoc包设备必须在这份列表里才能安装这个很多开发知道。但真正的坑是不少人会把Ad Hoc包误当成App Store包上传到App Store Connect。有一次我排查一位朋友的App报错信息是无法安装App与当前设备不兼容。最后发现他导出时选的Method是ad-hoc描述文件带了ProvisionedDevices审核员的测试机根本不在列表里。上传完之后苹果后台显示构建版本正常可审核员一安装就失败来回折腾了快一周。解决办法很简单上传App Store审核时导出Method一定要选app-store新版Xcode叫app-store-connect对应描述文件必须是App Store类型。这种描述文件不含ProvisionedDevices表示该构建可以安装到所有符合系统要求的设备上。3.3 Entitlements和描述文件如何影响设备验证描述文件里的Entitlements字典和最终签名进App的entitlements必须一致。以推送为例如果描述文件里配了aps-environment但构建时签名用的entitlements文件缺失这个键App在真机上注册远程推送时会一直拿不到token。审核员如果测试推送功能看到这种现象反馈往往会被归类到设备信息注册失败。类似的情况还有iCloud和Access WiFi Information。这些能力不仅依赖Info.plist和代码还依赖描述文件里的授权声明。每次在开发者后台重新生成描述文件后建议做一次签名验证codesign -d --entitlements - YourApp.app对照描述文件里的Entitlements确保两边一致。这样能在提审前发现很多被系统静默忽略的配置问题。3.4 推送、iCloud等能力与设备绑定推送通知虽然不是严格意义上的设备信息但它和设备的绑定极深。审核时会实际测试通知能否到达。如果App的aps-environment环境配置成了development而提审包本身应该是生产环境审核员安装后测试推送会发现收不到通知。这个反馈也常常被描述成无法在该设备上完成通知注册。处理方法是严格区分环境本地开发用Development描述文件TestFlight和App Store审核用Production描述文件。aps-environment在App Store类型描述文件里一般就是production。提审包里的mobileprovision如果还是development类型那优先级最高的还是先改成App Store类型重新导出。这个点从Xcode的Signing Capabilities面板里就能看好别等项目大了再来回切。4. IPA构建把合规落到最终产物上4.1 架构与最低系统版本设备兼容的地基定义IPA能否在审核员设备上运行最底层因素是架构和最低系统版本。App Store审核团队使用的真机型号不固定如果最低系统版本设得比审核机型还要高或者架构不支持第一批就能被拒。Xcode工程的Release配置里Build Active Architecture Only必须设为NO确保打出所有Release架构现在主要是arm64。另外MinimumOSVersion不要为了覆盖老设备故意设得特别低。如果代码里用了iOS 16才有的API却仍然声明最低支持iOS 13那么在小版本设备上安装成功后打开闪退的风险极大。审核员只要在一台低版本测试机上复现崩溃就会以App在支持的设备上不能稳定运行为由拒绝。相比多支持几个系统版本先把声明和实际支持的版本对齐更重要。4.2 代码里的设备信息采集哪些写法会被拒如果说Info.plist和描述文件决定了配置层是否合规那么代码中的设备信息采集就决定了行为层是否合规。苹果的静态扫描对以下内容非常敏感uniqueIdentifier、MAC地址、OpenUDID、私有框架头文件引用。凡是从代码里能直接搜到的这些符号只要没有合理混淆几乎都会命中。举一个常见的例子有些第三方统计SDK旧版本会通过读取WiFi的MAC地址来生成设备唯一标识这个行为在苹果审核中是明确禁止的。真的需要跨应用识别用户的话iOS 14之后应该走IDFA并配合ATT授权如果只在同一开发者账号下的应用之间识别用户用identifierForVendor就足够了。代码中采集到的设备型号、系统版本、磁盘剩余空间等信息如果会回传服务器一定要在隐私政策里写清楚并且最好是聚合后使用避免精确定位到某台设备。4.3 IDFA与ATT广告标识的合规姿势IDFA是设备信息合规里绕不开的话题。它本意是用于广告归因但因为能跨App识别用户苹果对它的管控一直很严。代码里如果调用ASIdentifierManager相关接口就必须先过ATT弹窗用户授权后才允许读取。而且App Store Connect后台的广告标识符选项也要如实勾选声明用途是广告归因或数据分析。没有广告功能却用了IDFA是典型的拒审场景。审核反馈会直接写App uses the advertising identifier but does not include ad functionality。这种情况下要么去掉IDFA改用identifierForVendor要么在App内增加真正的广告展示并在回复里补充说明用途和对用户的价值。如果你的业务只需要统计用户行为而不做跨App投放就别碰IDFA省得后续解释成本太高。技术上省事合规上更省事。4.4 构建后自检拆开IPA看真相提审前最稳的一步是用命令行把IPA拆开把所有关键配置过一遍。下面是我自己的检查流程# 1. 解包 unzip YourApp.ipa -d ipa_check # 2. 核心字段 plutil -p ipa_check/Payload/YourApp.app/Info.plist | grep -E UIDeviceFamily|UIRequiredDeviceCapabilities|MinimumOSVersion|NSUserTrackingUsageDescription # 3. 架构 lipo -info ipa_check/Payload/YourApp.app/YourApp # 4. 签名和Entitlements codesign -d --entitlements - ipa_check/Payload/YourApp.app这几条命令基本能覆盖设备信息相关的自检点。最后再检查embedded.mobileprovision是不是App Store类型确认get-task-allow为false。如果这里全是开发模式的配置就别急着上传。整个流程十分钟内能完成比上传后等两三天被拒再返工划算得多。5. 拒审后怎么快速翻盘5.1 从拒审邮件反推问题点收到拒审邮件后先别急着写申诉。把邮件原文拆成两部分看一部分是苹果给出的政策条款引用另一部分是审核备注。政策条款告诉你违反了哪条规则审核备注才是定位问题的关键。常见的情况是备注里提到device information或advertising identifier这说明既有代码行为问题也有声明不完整问题。以一次5.1.1拒审为例邮件说Your app collects device information but does not disclose it in the privacy policy。我的处理顺序是先检查代码里所有读设备信息的位置列出采集项再看App Store Connect后台的隐私政策链接是否失效或未配置最后把采集项的用途同步到隐私政策文本中。这三个地方都对齐后在Resolution Center回复审核组说明修改点并补充相关截图。多数情况下能顺利通过。5.2 常见设备信息拒审速查表下面是我习惯用的一张速查表按类型整理了设备和设备信息最容易触发的审核反馈。遇到问题直接对着看比翻聊天记录和邮件都快。拒审反馈常见表述可能原因处理方案App无法在当前设备上运行架构缺失、Build Active Architecture Only误设改用正确Release配置重新构建App与设备不兼容描述文件类型选错、UIDeviceFamily不匹配检查mobileprovision类型并重新导出App使用了广告标识符但无广告功能代码中读取IDFA但无广告场景去掉IDFA或增加广告并回复说明权限使用说明不清晰Info.plist权限文案空泛或缺少NSUserTrackingUsageDescription修改文案说明权限具体用途隐私政策未披露设备信息收集采集设备信息但无隐私政策或政策不完整更新隐私政策并同步后台链接设备无法完成推送注册aps-environment环境配置错误使用生产描述文件重新导出5.3 提审前最后一遍自查最终定稿前我建议在团队内部走一遍清单式自查。不需要复杂的工具按顺序核对即可确认Info.plist中UIDeviceFamily声明的设备类型和支持范围一致检查UIRequiredDeviceCapabilities只保留必要项核验所有系统权限文案具体化确认隐私清单覆盖了主工程和第三方SDK用security cms -D -i查看mobileprovision类型确认导出Method为app-store或app-store-connect检查Release构建的架构和最低系统版本最后再跑一遍代码搜索确保没有uniqueIdentifier、MAC地址等敏感符号。这条清单帮我们组里把一个拖了两周的拒审问题彻底解决掉了之后基本没再因为设备信息的事被打回过。最后说点我自己的体会设备信息相关的拒审90%都不是开发完成后才暴露的而是提审前配置阶段就埋下的雷。Info.plist、描述文件、构建参数这三样东西看起来各管一摊实际上是一条链上的。审核员拿到的是最终IPA他们不看你过程多辛苦只看产物是否满足能在测试设备上稳定运行、没有越权采集、声明和实际一致这三条。我现在的习惯是把自检脚本写进CI流程每次打提审包都自动跑一遍省得靠人肉盯。如果你们团队的提审频率高这个投入非常划算。
返回列表