定制侠 iOS 提审冲刺纪要:原生苹果登录落地、隐私协议打假与 iPhone-only 之路(10-23 ~ 10-25)

xiezitai · 2026-10-25 18:23 · 5 次阅读

定制侠 iOS 提审冲刺纪要(2026-10-23 ~ 10-25)

三天时间,把定制侠 iOS 从「TestFlight 能装上」推到「提审材料基本齐活」。本文按时间线记录四件事:后端原生苹果登录落地、一个 Hibernate 7 的部署阻塞、一次隐私协议「打假」,以及不靠 iPad 截图过审的 iPhone-only 方案。

一、起点:TestFlight 里苹果登录是坏的

v1.0.0 上传 TestFlight 后实测,苹果账号登录直接报「苹果登录失败,请重试」。前端先做了错误分三类(后端不可用带 HTTP 码 / 业务拒绝透传 / 网络异常),但根因在后端:POST /api/auth/apple/{appId}/native 这个端点根本不存在,请求命中 Spring 默认 404(无 message 字段),客户端兜底文案就成了用户看到的「失败请重试」。

二、后端:原生 SIWA 端点落地

在 zhangtian 后端新增 AppleNativeLoginRequestDTO 与 AppleAuthController 的 POST /{appId}/native,组装 AppleLoginRequestDTO 后复用既有 appleUserService.loginByRequest——JWKS 验签、aud 同时放行 ServicesID 与 BundleID、nonce 可空,这些既有能力直接继承,没有重复造轮子。

一个细节:苹果授权页的 fullName 是按「末空格」拆 Given/Family 的,需要转成苹果 user JSON 结构再交给既有服务。返回扁平 JSON(token/userId/expireTime/isNewUser/nickname),对齐前端 saveSession 的字段约定。

验证方式值得一提:本地起不来完整环境(无 H2、不能连生产库),改用字节码级验证——javap 反编译确认 @PostMapping("/{appId}/native") 注解真实存在于 jar 中的类文件。

三、部署阻塞:Hibernate 7 把 MySQL8Dialect 删了

端点编进 jar 后卡在启动:application.yml 里配了 database-platform: org.hibernate.dialect.MySQL8Dialect,而这个类在 Hibernate 7 已被移除,启动即 ClassNotFound。

解法干净利落:删掉该行。Hibernate 7 会依据 JDBC 连接(MySQL Connector/J 8.0.33)自动识别方言,MySQL8Dialect 本来就是多余配置。遗留的 hibernate.dialect.storage_engine: innodb 属性不受影响。改完重新打包,解压 jar 校验 BOOT-INF/classes/application.yml 确认无残留,BUILD SUCCESS。

四、意外收获:沙箱禁 cmd 后的 Java 构建链

这次排障还撞上一个环境级变化:Bash 和 PowerShell 都禁止调 cmd.exe 了,原来的 build.bat(JDK25 + IntelliJ 内置 maven3)直接报废。替代方案是绕过 shell,用 Python subprocess 直起 java 进程,通过 classworlds 启动 maven3:

java -Dmaven.multiModuleProjectDirectory=<项目根> \
     -Dmaven.home=<maven3目录> \
     -Dclassworlds.conf=<maven3>/bin/m2.conf \
     -classpath <maven3>/boot/plexus-classworlds-2.7.0.jar \
     org.codehaus.plexus.classworlds.launcher.Launcher -o -f pom.xml package

两个坑:① maven.multiModuleProjectDirectory 必须放在 java -D 上,放 maven 参数位置无效;② PowerShell 给原生命令传带空格路径的参数会被拆散(-Dmaven.home="$var" 断裂),必须走 Python 列表传参。脚本化后 9.4 秒 BUILD SUCCESS,比原来的 bat 还快。

五、隐私协议「打假」:线上政策页和 App 实际行为对不上

这是三天里最危险的发现。准备 ASC 提审材料时打开隐私政策 URL https://www.dingzhixia.com/privacy.html,发现页面套的是微信小程序/直播商城模板,声明收集一堆 App 根本没有的东西:

为什么危险:苹果审核员一定会点开隐私政策 URL 对照 App 实际行为。政策说收身份证、App 却不收——这不只是「不实陈述」,还等于主动把审核员视线引到最敏感的字段上。

重写前先按代码核实真实行为,而不是凭印象:

核实项 方法 结论
定位 AndroidManifest 权限清单 + iOS Info.plist 用途描述 无定位权限、无 NSLocation 声明 → 不收集
照片 image_picker + 相机/相册用途描述 仅用户主动上传定制图时收集
收货信息 order.dart 字段(receiverName/receiverPhone/省市区/addressDetail) 收集,用于配送
诊断日志 cloud_log_service 上传内容(错误堆栈+操作记录+userId) 收集,用于排障
剪贴板 全库 grep Clipboard 只有 setData 写入(复制邀请码/订单号),从不读取

然后三处同步重写:线上 privacy.html、App 内 privacy_policy_screen.dart、agreement_page.dart 的 privacy 分支。新版结构:真实收集清单(手机号/收货信息/照片/第三方登录昵称头像/用户 ID+设备标识/诊断日志/订单备注)+「我们不收集的信息」章节(位置、身份证、通讯录、麦克风、不读剪贴板)+ 真实 SDK 清单(微信登录支付、支付宝、QQ、B站、华为、Apple)+ App 内注销路径(符合 5.1.1(v))。

六、App 隐私标签:11 类砍到 8 类

ASC 的 App 隐私问卷默认列了 11 个数据类型,逐个按代码事实判定:

数据类型 收集? 用途 关联身份 追踪
姓名 是 App 功能 是 否
电话号码 是 App 功能 是 否
实际地址 是 App 功能 是 否
照片或视频 是 App 功能 是 否
用户 ID 是 App 功能 是 否
设备 ID 是 App 功能 否 否
崩溃数据 是 分析 否 否
其他诊断数据 是 分析 否 否
精确位置 删 — — —
粗略位置 删 — — —
性能数据 删 — — —

删三项的依据:无定位权限、无性能埋点。声明了却没收集一样会被打回——隐私标签的核心原则是「与事实一致」,多填和少填都是错。

七、iPhone-only:不做 iPad 截图的正解

ASC 要求「13 英寸 iPad 截屏」的前提是构建声明支持 iPad。我一开始以为后台有「支持设备」开关,找了一圈发现根本没有——设备支持由上传的构建二进制里的 UIDeviceFamily 决定(源自 Xcode 的 TARGETED_DEVICE_FAMILY),Flutter 模板默认 "1,2"(iPhone + iPad)。

正解:ios/Runner.xcodeproj/project.pbxproj 三处配置(Debug/Release/Profile)"1,2" → "1",重新打包。两个事实支撑这个选择:

另外确认了 CI 转换脚本只注入 DEVELOPMENT_TEAM、不碰设备族,改动能安全带进 GitHub Actions 构建。

八、ASC 文案与合规清单

文案三件套(都按字符上限校验过):

合规项:主要类别「购物」+ 次类别「生活」;定价选免费(实体商品走支付宝/微信,不需要 IAP,免费 App 也无需税务协议);内容版权填「2026 北京醉么信息技术有限公司」(不带 © 符号、不能填网址或 N/A);内容版权声明选「否」(用户上传的定制照片属 UGC,不构成 App 包含第三方内容);DSA 交易商声明选「是」——公司主体开发的商业 App 按欧盟标准就是 trader,且即使不在欧盟分发,提审新 App 时也会被要求披露。

九、v1.0.1 发布

cf4cb5c 推送 main → v1.0.1 tag 触发两条工作流,双双全绿:

本版内容:iPhone-only 设备族 + App 内隐私协议修正(真图标 v1.0.0 已带)。

十、遗留与下一步

  1. 后端含 native 端点的 jar 部署到生产(方言阻塞已除,部署即可用);
  2. ASC 演示账号——App 启动即登录页,审核员没账号进不去,需要注册一个测试手机号填到「App 审核信息 → 登录信息」;
  3. 微信 iOS URL Scheme + Universal Link(CI 已桩化优雅降级,不影响提审)。

结语

三天下来最大的感触:提审材料的敌人不是功能缺失,而是「文档与事实不一致」。一份套错模板的隐私政策页、一组凭感觉勾选的隐私标签,比任何 bug 都更容易让审核进行不下去。所有合规项都按代码事实逐个核实过——这才是这次冲刺真正做完的事。

评论

还没有评论,登录后来说两句。