edit | blame | history | raw

2026-06-13 App Store 三审驳回

用户目标

确认 App Store Connect 再次驳回 PrivateVoice Dictation 2.1.28 (20260611.1907) 的原因,并引入两个独立代码审核员交叉检查,避免继续遗漏发布级问题。

Apple 驳回信息

  • 审核结果:Rejected
  • 版本:2.1.28 (20260611.1907)
  • Guideline:2.1(a) Performance - App Completeness
  • Bug description:unable to launch the app, no crash log
  • 审核设备:MacBook Pro (14-inch, Nov 2024)
  • 审核系统:macOS 26.5
  • 结论:这不是上传校验失败,也不是旧的 quarantine / provisioning profile 证书不匹配问题;这是 Apple 审核环境启动 App 时无法确认可启动或可操作。

三方审查结论

包与签名审查

  1. 最终 .pkg payload 含 17 个 AppleDouble ._* 条目,涉及主程序、dylib、Info.plistCodeResourcesembedded.provisionprofile 等关键文件。
  2. pkgutil --expand-full 后可见对应 com.apple.provenance 扩展属性。
  3. 当前 verify-macappstore-pkg-macos.sh 对 AppleDouble 只打印 WARN,最后仍放行。
  4. 主可执行文件保留构建机绝对 LC_RPATH
  • /Users/ar/go/pkg/mod/github.com/k2-fsa/sherpa-onnx-go-macos@v1.13.2/lib/x86_64-apple-darwin
  • /Users/ar/go/pkg/mod/github.com/k2-fsa/sherpa-onnx-go-macos@v1.13.2/lib/aarch64-apple-darwin
  1. 绝对 rpath 来源是 sherpa-onnx-go-macos 的 cgo LDFLAGS;构建脚本只追加 @executable_path/../Frameworks,没有删除旧 rpath。

启动链路审查

  1. Info.plist 固定 LSUIElement=true,默认配置 HideDockIcon=true,启动后没有 Dock 图标。
  2. 虽然 settings window 设置 Hidden=false,但启动后没有稳定显式 Show/Focus/activate
  3. 单实例锁失败直接 os.Exit(0);如果第一次启动不可见,审核员再次点击会看到新进程静默退出且无 crash log。
  4. hotkey listener 在首屏稳定前创建,macOS 端可能触发 Accessibility/TCC 权限请求;权限弹窗不应成为首屏。
  5. pkg 不内置模型;无模型时应进入可操作 UI,而不能让自动下载或 loading 成为唯一路径。

第二轮查漏补缺

  1. Wails Go 与前端 runtime 版本不一致:Go 端为 github.com/wailsapp/wails/v3 v3.0.0-alpha.71,前端 @wailsio/runtime 使用 latestpackage-lock.json 实际解析为 3.0.0-alpha.79。首屏依赖 Wails runtime 调用后才渲染,若 bridge 不兼容,窗口可能空白且无 crash log。
  2. Wails production 默认 logger 可能写入 io.Discard;项目未配置 Wails LoggerErrorHandlerWarningHandlerPanicHandler。如果 Wails/WebKit/asset server 在首屏前 fatal,Apple 可能只看到无窗口或进程退出,项目日志也没有根因。
  3. 包声明最低 macOS 13.4,但 libonnxruntime.1.24.4.dylib 的 x86_64 slice LC_BUILD_VERSION minos 15.5,arm64 slice minos 14.0。这不解释 Apple 的 macOS 26.5 审核机,但会让 App 在声明支持范围内的部分 Intel 系统启动失败。
  4. Onboarding 无模型时自动下载,下载失败后没有“重试 / 跳过 / 打开设置 / 选择模型”的可恢复路径。
  5. 默认中文模型首选 URL 和自更新版本检查 URL 使用明文 HTTP。
  6. App Store build 仍注册 UpdaterService,而 PerformUpdate() 会尝试替换当前 executable;Mac App Store 沙盒/签名 App 不应暴露自更新路径。
  7. 模型下载使用 http.DefaultClient.Do(req),没有显式 timeout;审核网络环境慢或阻断时可能长时间挂住。
  8. audio.NewRecorder() 在窗口创建前初始化 malgo context,音频系统/TCC 边界发生在首屏稳定前。
  9. 默认热键是右 Alt/Option,但 README 等公开说明中仍存在右 Command 说法,可能误导审核复现。

必须整改

  1. App Store 包必须清零 AppleDouble / .DS_Store / com.apple.provenance / com.apple.quarantine
  2. 主程序与 dylib 必须清零构建机绝对 rpath,只允许 bundle 相对路径和系统路径。
  3. App Store build 首启必须有明确可见、前台、可交互窗口;不能默认隐藏 Dock 到用户或审核员找不到。
  4. 二次启动必须唤醒已有实例并显示设置窗口,不能静默 exit 0
  5. 首屏稳定后再触发 Accessibility/Input Monitoring 等权限请求。
  6. 无模型、断网场景下首屏也必须可操作,不能空白或静默后台。
  7. Wails Go 与前端 runtime 必须锁到兼容版本,不能使用 latest
  8. Wails fatal/panic/error/warning 必须接入项目日志。
  9. App 声明的最低系统版本必须不低于所有 Mach-O slice 的 LC_BUILD_VERSION minos,或更换支持更低系统的 dylib。
  10. App Store build 必须移除或禁用自更新服务和 UI。
  11. 模型下载必须改为 HTTPS 优先并设置超时;失败后提供可恢复 UI。
  12. 音频和权限相关初始化应延后到首屏稳定之后或用户动作之后。

必须新增发布闸门

  1. pkgutil --payload-files 中出现 ._*.DS_Store 必须失败。
  2. 展开最终 .pkg 后,发现 com.apple.quarantinecom.apple.provenance 必须失败。
  3. 对最终 pkg payload 内所有 Mach-O 执行 otool -l / otool -L,出现 /Users//private//var//tmp/GOMODCACHE、worktree/build root、/opt/homebrew/usr/local 等非系统绝对路径必须失败。
  4. 从最终 pkg 安装后执行真实 launch smoke:5 秒内进程存在、日志写入当前版本构建号、至少一个可见窗口或明确可见菜单栏入口。
  5. 二次启动 smoke:已有实例运行时再次启动必须唤醒/聚焦设置窗口。
  6. TCC 首启矩阵:重置权限后先看到 App UI,再触发权限请求。
  7. 无模型/断网首启矩阵:清空模型并阻断网络后仍显示可操作 UI。
  8. Wails 版本一致性检查:Go module 与前端 runtime 不允许跨 alpha 版本。
  9. 启动日志检查:Wails fatal/panic/error 必须落盘。
  10. Mach-O 最低系统版本检查:所有 slice 的 minos 不得高于 App 声明的最低系统版本。
  11. App Store build 扫描:不得暴露自更新服务,不得包含明文 HTTP 默认下载 URL。
  12. 首屏 DOM/像素检查:窗口不能空白,必须出现关键可见文本。

当前状态

本轮只读审查,未修改产品代码、构建脚本或 App Store Connect。下一步需要先确认整改范围,再生成新 build,不能复用 20260611.1907