# 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.plist`、`CodeResources`、`embedded.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` 5. 绝对 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` 使用 `latest`,`package-lock.json` 实际解析为 `3.0.0-alpha.79`。首屏依赖 Wails runtime 调用后才渲染,若 bridge 不兼容,窗口可能空白且无 crash log。 2. Wails production 默认 logger 可能写入 `io.Discard`;项目未配置 Wails `Logger`、`ErrorHandler`、`WarningHandler`、`PanicHandler`。如果 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.quarantine` 或 `com.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`。