Pangolin 客户端 · 中国「岩美北京技术」→ 美国「Yanmei AI LLC」· 目标:产物与仓库无中国开发者账号任何痕迹 · 2026-09-06
com.yanmeiai.*)、全新 Team、全新证书/描述文件/公证凭据,与旧中国账号零依赖(无需清理旧 App ID)。
分三块:你做 Apple 后台建资产 + gitea 传新 secret;我做 仓库代码里 Team ID / Bundle ID / App Group / 实体名的全量替换;我做 本机钥匙串 + 公证凭据配置。
顺序很重要:先建 Apple 资产 → 我改代码 → 传 gitea → 验证首个构建。
44WULXM6SV)仓库代码(§3)已全量迁到美国身份并收敛成单一真相源 scripts/signing.env + codegen。剩下的是你在 Apple 后台建资产(§1)、本机公证凭据(§2)、gitea 换 secret(§4)、首个构建验证(§5)。建资产时把两张证书精确全名 + ASC Key 的 Key/Issuer ID 发我,我做 §2。
| 项 | 旧(中国,待清除) | 新(美国 Yanmei AI LLC) |
|---|---|---|
| Team ID | BYL4KQHMTN | 44WULXM6SV(你提供) |
| 法人实体(证书 CN 内含) | Yanmei (beijing) Technology Co., Ltd | Yanmei AI LLC |
| macOS 主 app Bundle ID | com.pangolin.pangolin | com.yanmeiai.pangolin |
| macOS 扩展 Bundle ID | com.pangolin.pangolin.PacketTunnel | com.yanmeiai.pangolin.PacketTunnel |
| iOS 主 app Bundle ID | com.pangolin.pangolinVpn | com.yanmeiai.pangolin |
| iOS 扩展 Bundle ID | com.pangolin.pangolinVpn.PacketTunnel | com.yanmeiai.pangolin.PacketTunnel |
| iOS App Group | group.com.pangolin.pangolinVpn | group.com.yanmeiai.pangolin |
macOS App Group(原生 <Team>. 格式) | BYL4KQHMTN.com.pangolin.pangolin | 44WULXM6SV.com.yanmeiai.pangolin |
macOS NEMachServiceName | BYL4KQHMTN.com.pangolin.pangolin.PacketTunnel | 44WULXM6SV.com.yanmeiai.pangolin.PacketTunnel |
iOS App Group 不含 Team ID(group. 前缀,跨账号可移植);macOS 用原生 <TeamID>.<name> 格式,Team 一换前缀必变——这也是必须改代码而非纯换证书的根本原因。旧 macOS 安装的登录态存在旧 App Group 容器里,切换后清空、用户需重登(重签本就如此,可接受)。
全部在 developer.apple.com/account(美国账号)完成。按顺序:
Membership details → Team ID → 发我。
Certificates, IDs & Profiles → Identifiers → + → App IDs → App。因 iOS/macOS 现共用同一 Bundle ID 字符串,只需 2 个唯一 App ID(各覆盖两端):
| Description | Bundle ID(Explicit) | 勾选的 Capabilities |
|---|---|---|
| Pangolin(主 app) | com.yanmeiai.pangolin | App Groups、Network Extensions、System Extension |
| Pangolin PacketTunnel(扩展) | com.yanmeiai.pangolin.PacketTunnel | App Groups、Network Extensions |
主 app 三个能力缺一不可——尤其 System Extension:macOS 主 app 靠 com.apple.developer.system-extension.install 装载 sysext,少了它 Developer ID profile 不含该权限,构建报「Provisioning profile doesn't include the System Extension capability」。改了 App ID 能力后,相关 profile 会变 Invalid,须去 Profiles 重新 Generate + Download。扩展 App ID 只需 Network Extensions + App Groups。
Identifiers → 右上下拉切到 App Groups → + → 填 group.com.yanmeiai.pangolin(Description 随意)。回到上面 4 个 App ID,编辑其 App Groups capability → Configure → 勾上这个 group。
macOS 端说明:macOS 用的是原生 44WULXM6SV.com.yanmeiai.pangolin(team 作用域容器,不带 group.),不需要在后台单独注册——只要 App ID 勾了 App Groups capability、且用该 Team 的证书签名即可生效。后台注册的 group.com.yanmeiai.pangolin 供 iOS 使用。
用「钥匙串访问 → 证书助理 → 从证书颁发机构请求证书」生成一个 CertificateSigningRequest.certSigningRequest(存到磁盘),后台上传它换证书;下载后双击导入 login 钥匙串。
developerID_application.cer。distribution.cer。导入后,两张证书的主体会是 Developer ID Application: Yanmei AI LLC (44WULXM6SV) 与 Apple Distribution: Yanmei AI LLC (44WULXM6SV)。请把这两串完整名字发我(security find-identity -v -p codesigning 可打印),我要把它们精确写进 local_test.sh。
钥匙串里分别右键两张证书(连带私钥)→ 导出为 .p12,设一个导出密码(记进 Bitwarden,别写文件)。得到 developerID.p12 与 ios_dist.p12——第 4 节转 base64 传 gitea。
Profiles → +:
| 类型 | 关联 App ID | 证书 | 用途 |
|---|---|---|---|
| Developer ID(macOS,含 Network Extensions) | com.yanmeiai.pangolin | Developer ID Application | macOS 主 app |
| Developer ID(macOS) | com.yanmeiai.pangolin.PacketTunnel | Developer ID Application | macOS sysext |
| App Store(iOS) | com.yanmeiai.pangolin | Apple Distribution | iOS 主 app |
| App Store(iOS) | com.yanmeiai.pangolin.PacketTunnel | Apple Distribution | iOS 扩展 |
各自下载 .provisionprofile(macOS)/ .mobileprovision(iOS)。CI 会用它们;本机 local_test.sh 的 macOS 流程也从固定目录读这两个 macOS profile(第 3 节代码替换里会核对路径)。
App Store Connect → Users and Access → Integrations → App Store Connect API → 生成一个 Team Key(Role: Developer 或 App Manager)→ 记下 Key ID 与 Issuer ID,下载 AuthKey_XXXX.p8(只能下一次,妥存 Bitwarden)。用于公证(notarytool)与 CI 上传。
security find-identity -v -p codesigning 核对 Developer ID Application: Yanmei AI LLC 与 Apple Distribution: Yanmei AI LLC 在列。local_test.sh 用的 pangolin-notary)——用 1.7 的 ASC Key:
xcrun notarytool store-credentials pangolin-notary \ --key AuthKey_XXXX.p8 --key-id <KEY_ID> --issuer <ISSUER_ID>这一步把凭据存进本机钥匙串,不入 git。(此命令需交互,可能由你在终端用 ! … 跑,我给你现成命令。)
… Yanmei (beijing) Technology 两张证书,避免签名时误选旧身份。已落地,且不再是「散落硬编码」。签名身份收敛成单一真相源,今后迁账号/改 Bundle ID 只改一个文件跑一次 codegen,不用再全仓找替换。
scripts/signing.envTeam ID / 实体名 / Bundle ID / App Group 全在这里(当前已是美国身份:Team 44WULXM6SV、Yanmei AI LLC、com.yanmeiai.pangolin)。三个签名脚本(local_test.sh / ci/compile-macos.sh / ci/compile-ios.sh)直接 source 它。
Xcode/Swift 侧的标识符无法 source 变量、只能字面量,故由 node scripts/gen-signing.mjs 从 signing.env 结构化回填 16 个原生文件(两端 project.pbxproj 的 DEVELOPMENT_TEAM/Bundle ID、各 *.entitlements 的 App Group/app-identifier、macOS Info.plist 的 NEMachServiceName、各 Swift 的 appGroup/subsystem/loginHelper 等)。codegen 用「形状」匹配、不含任何旧字面值——自身无痕,未来再迁仍生效。
# 迁账号/改 Bundle ID 的唯一操作: vim scripts/signing.env # 改 3 个基值 node scripts/gen-signing.mjs # 回填全部原生文件
ci/check-codegen-drift.sh 跑 gen-signing.mjs --check:若改了 signing.env 没重生成、或手改了原生标识符,即失败。与 token/l10n 同一套 codegen 单源治理。
plutil -lint 全 OK;两端 project.pbxproj xcodebuild -list 可解析,Runner build settings 解析为新 Team/Bundle。gen-signing.mjs --check 幂等 0 drift;完整 codegen drift 闸(token/l10n/proto-i18n/signing)全绿。范围说明:未动 Android 包名 com.pangolin.pangolin_vpn(Play Store 身份、自签名、非 Apple 账号痕迹,改动会破坏 Play 更新,另议)与 Windows/桌面少量元数据串。codesign 层面 Apple 产物已零中国痕迹。
gitea → 仓库 wangjia/pangolin → Settings → Actions → Secrets(注意历史经验:Apple 签名 secret 配在 用户级非仓库级,见记忆 pangolin-apple-signing-assets——按你当初配的层级更新)。名字不变,只换值:
| Secret 名 | 新值来源 |
|---|---|
DEVELOPER_ID_P12 | base64 -i developerID.p12(1.5) |
P12_PASSWORD | 导出 developerID.p12 时设的密码 |
MACOS_APP_PROVISION_PROFILE_BASE64 | macOS 主 app 的 .provisionprofile base64(1.6) |
MACOS_SYSEXT_PROVISION_PROFILE_BASE64 | macOS sysext 的 .provisionprofile base64 |
IOS_DIST_P12 | base64 -i ios_dist.p12 |
IOS_DIST_PASSWORD | 导出 ios_dist.p12 时设的密码 |
IOS_APP_PROVISIONING_PROFILE_BASE64 | iOS 主 app 的 .mobileprovision base64 |
IOS_PACKETTUNNEL_PROVISIONING_PROFILE_BASE64 | iOS 扩展的 .mobileprovision base64 |
APPSTORE_API_KEY_ID | 1.7 的 Key ID |
APPSTORE_API_ISSUER_ID | 1.7 的 Issuer ID |
APPSTORE_API_KEY_P8_BASE64 | base64 -i AuthKey_XXXX.p8 |
macOS 转 base64:base64 -i 文件(默认单行,直接粘 gitea)。Android 的 RELEASE_KEYSTORE/KEY_PASSWORD 是自签名,与 Apple 账号无关,不用动。
bash scripts/local_test.sh macos(build+签名+公证+staple+App Group 一致性闸)。bash scripts/local_test.sh ipad "<设备>"——脚本会核验签名主体,若还是旧证书会 die。client-vX.Y.Z 触发 gitea 流水线,用新 secret 构建。首次建议先跑一次看签名步骤绿。codesign -dvvv # 看 Authority / TeamIdentifier Runner.app 2>&1 | grep -E "Authority|TeamIdentifier" # 期望:Yanmei AI LLC + 44WULXM6SV,无 BYL4KQHMTN / beijing再全仓
grep -rn "BYL4KQHMTN\|beijing" client scripts .gitea 应为空。codesign -dvvv:Authority = Yanmei AI LLC、TeamIdentifier = 44WULXM6SV。grep -rn "BYL4KQHMTN" client scripts .gitea docs → 空。grep -rin "beijing\|岩美" client scripts .gitea → 空。44WULXM6SV.com.yanmeiai.pangolin*。| # | 步骤 | 谁 | 依赖 |
|---|---|---|---|
| 1 | Apple 后台建 Team/App ID/Group/证书/Profile/ASC Key(§1) | 你 | — |
| 2 | 把 Team ID + 两张证书全名 + ASC Key 信息发我 | 你 | 1 |
| 3 | 本机钥匙串核对 + 建 pangolin-notary 公证凭据(§2) | 我 | 2 |
| 4 | 仓库代码替换 → signing.env 单源 + codegen(§3)已完成 | 我 | — |
| 5 | gitea 12 个 secret 换新值(§4) | 你 | 1 |
| 6 | 本机 macOS/iOS 构建验证(§5.1–5.2) | 我 | 3,4 |
| 7 | 打 tag 触发 CI 发版 + 无痕核验(§5.3–5.4) | 我+你 | 4,5 |
相关:macOS sysext realize 排障 · iOS/iPad 支持设计 · 签名资产位置见项目记忆 pangolin-apple-signing-assets。本文随迁移推进更新。