refactor(signing): 原生侧签名标识符改由 signing.env codegen 生成(单一真相源)
承接 scripts/signing.env(shell 单源):Xcode/Swift 侧的 Team ID/Bundle ID/App Group 等无法 source 变量、只能字面量,故用 codegen 保持单源。 - 新增 scripts/gen-signing.mjs:从 signing.env 读 3 基值,用**结构化正则**(匹配 `DEVELOPMENT_TEAM = X`/app group 形状等,不含任何旧字面值)回填 16 个原生文件的 标识符;--check 为 drift 模式。因不含旧值,codegen 自身无痕、未来再迁账号仍生效。 - ci/check-codegen-drift.sh 追加签名 drift 闸(gen-signing.mjs --check)。 - 全量迁到美国身份:Team 44WULXM6SV / 实体 Yanmei AI LLC / Bundle com.yanmeiai.pangolin (+.PacketTunnel)/ App Group macOS 原生 44WULXM6SV.com.yanmeiai.pangolin、iOS group.com.yanmeiai.pangolin。清理注释/ORGANIZATIONNAME 等 Apple 侧残留痕迹。 - CLAUDE.md 同步新身份 + 指向 signing.env 单源。 验证:plutil lint 6 份 entitlements/plist 全 OK;macOS/iOS 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 身份、自签、非 Apple 账号痕迹, 改动影响大另议)与 Windows/桌面少量元数据串。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
This commit is contained in:
@@ -183,9 +183,10 @@ cd web/website && npm run gen:tokens
|
||||
|
||||
**系统扩展能被 realize 的硬性要求**(缺一即 `code=4` / 静默拒)
|
||||
- **自包含**:`PacketTunnel` target 设 `OTHER_LDFLAGS = ""`(切断继承项目级 CocoaPods 链接标志,否则会把 `flutter_secure_storage` 链进扩展);`Libbox.xcframework` **只 Link 不 Embed**(它是静态库)。验证:`otool -L` 扩展二进制应**零 `@rpath` 外部依赖**。
|
||||
- **bundle 名 = 标识符**:`PRODUCT_NAME = com.pangolin.pangolin.PacketTunnel`。
|
||||
- **bundle 名 = 标识符**:`PRODUCT_NAME = com.yanmeiai.pangolin.PacketTunnel`。
|
||||
- 扩展 `Info.plist` 必须有 **`NSSystemExtensionUsageDescription`**(网络扩展类别强制,主 app 的不顶用)。
|
||||
- **App Group 用 macOS 原生格式 `<TeamID>.<name>`**(`BYL4KQHMTN.com.pangolin.pangolin`,非 iOS 的 `group.` 前缀);`NEMachServiceName` 以其为前缀。
|
||||
- **App Group 用 macOS 原生格式 `<TeamID>.<name>`**(`44WULXM6SV.com.yanmeiai.pangolin`,非 iOS 的 `group.` 前缀);`NEMachServiceName` 以其为前缀。
|
||||
- **签名身份单一真相源 `scripts/signing.env`**(Team ID / 实体名 / Bundle ID / App Group)。shell 脚本 source 它;原生文件(pbxproj/entitlements/plist/swift)的字面量由 `node scripts/gen-signing.mjs` 从它回填(**勿手改这些标识符**),`ci/check-codegen-drift.sh` 有 drift 闸。迁账号/改 Bundle ID 只改 signing.env 跑一次 codegen。详见 `docs/apple-account-migration-runbook.html`。
|
||||
- 沙箱扩展补 `network.client` / `network.server`;`get-task-allow=false` + 签名加 `--timestamp`。
|
||||
|
||||
**libbox / NetworkExtension 集成铁律**(改 `PacketTunnelProvider.swift` 注意)
|
||||
@@ -206,7 +207,7 @@ cd web/website && npm run gen:tokens
|
||||
|
||||
同样内嵌 libbox,与 macOS 同「CommandServer 模型」,但形态/打包不同:
|
||||
|
||||
- **iOS/iPad**:`NEPacketTunnelProvider` 扩展(`client/ios/PacketTunnel/`),经 `NETunnelProviderManager` 管理(非 sysext);App Group 用 **iOS 的 `group.` 前缀**(`group.com.pangolin.pangolinVpn`)。`ctl_info`/`sockaddr_ctl` iOS SDK 不发,靠 `PacketTunnel-Bridging-Header.h` 手写声明。
|
||||
- **iOS/iPad**:`NEPacketTunnelProvider` 扩展(`client/ios/PacketTunnel/`),经 `NETunnelProviderManager` 管理(非 sysext);App Group 用 **iOS 的 `group.` 前缀**(`group.com.yanmeiai.pangolin`)。`ctl_info`/`sockaddr_ctl` iOS SDK 不发,靠 `PacketTunnel-Bridging-Header.h` 手写声明。
|
||||
- **Android**:`PangolinVpnService`(`client/android/.../PangolinVpnService.kt`),VpnService + libbox **同进程**;明文联调 API 需 manifest `usesCleartextTraffic`(Android 9+ 默认禁 http)。
|
||||
- iOS/Android 与 macOS 同走 Dart `VpnNativeBridge`,所以 Dart 侧修复(状态/统计流)四端共享。
|
||||
|
||||
@@ -216,7 +217,7 @@ cd web/website && npm run gen:tokens
|
||||
- ⚠️ **Android libbox Java 包名是 `io.nekohasekai.libbox`**(不是 `libbox`),Kotlin import 用前者。
|
||||
|
||||
**真机装机(老忘——有现成脚本,别手搓 xcodebuild/签名)**:
|
||||
- **iOS**:`API_URL=https://api.yanmeiai.com bash scripts/local_test.sh ipad "<设备名/id>"`(`local_test.sh ios-devices` 列已连设备)。脚本自动:flutter build ipa(**公司分发证书** Apple Distribution: Yanmei / Team `BYL4KQHMTN`,ad-hoc)→ 核验签名主体(防无声退回个人证书)→ `xcrun devicectl` 装机。`API_URL` 决定客户端连哪个控制面(prod = `https://api.yanmeiai.com`)。
|
||||
- **iOS**:`API_URL=https://api.yanmeiai.com bash scripts/local_test.sh ipad "<设备名/id>"`(`local_test.sh ios-devices` 列已连设备)。脚本自动:flutter build ipa(**公司分发证书** Apple Distribution: Yanmei AI LLC / Team `44WULXM6SV`,ad-hoc)→ 核验签名主体(防无声退回个人证书)→ `xcrun devicectl` 装机。`API_URL` 决定客户端连哪个控制面(prod = `https://api.yanmeiai.com`)。
|
||||
- iOS libbox 是 **gitignore 产物**,新 worktree 常缺 → 从主仓拷免重建:`cp -R /Users/wangjia/code/pangolin/client/ios/Frameworks/Libbox.xcframework client/ios/Frameworks/`(routing 等功能不碰 libbox 接口,主仓那份兼容)。
|
||||
- 新设备首次装报 `0xe8008012`(描述文件不含 UDID)→ 需 xcodebuild `-allowProvisioningUpdates -allowProvisioningDeviceRegistration`(脚本 die 里给了兜底命令);chen 的设备(chen-macbook/chen-iphone)已注册。装机走**公司**分发证书,禁个人开发证书(记忆 `ios-install-team-cert`)。
|
||||
|
||||
|
||||
@@ -58,3 +58,10 @@ fi
|
||||
echo "→ 校验原型 data-i18n key 全 resolve (check-proto-i18n.mjs) ..."
|
||||
node design/prototype/tools/check-proto-i18n.mjs
|
||||
echo "✅ 原型 i18n 无漂移:I18N 块与单源一致、data-i18n 全 resolve。"
|
||||
|
||||
# ── 签名身份单源:scripts/signing.env → 原生文件字面量(pbxproj/entitlements/plist/swift) ──
|
||||
# 迁账号/改 Bundle ID 只改 signing.env,跑 gen-signing.mjs 回填;此闸防「改了 env 没重生成」
|
||||
# 或「手改了原生里的 Team/Bundle/App Group」导致签名标识符与单源分叉。
|
||||
echo "→ 校验签名标识符与 scripts/signing.env 一致 (scripts/gen-signing.mjs --check) ..."
|
||||
node scripts/gen-signing.mjs --check
|
||||
echo "✅ 签名标识符无漂移:原生字面量与 signing.env 单源一致。"
|
||||
|
||||
@@ -40,7 +40,7 @@ final class MemoryMonitor {
|
||||
|
||||
// ── 状态 ────────────────────────────────────────────────────
|
||||
private var timer: DispatchSourceTimer?
|
||||
private let queue = DispatchQueue(label: "com.pangolin.memory-monitor", qos: .utility)
|
||||
private let queue = DispatchQueue(label: "com.yanmeiai.pangolin.memory-monitor", qos: .utility)
|
||||
private(set) var peakResidentBytes: UInt64 = 0
|
||||
private(set) var minAvailableBytes: UInt64 = UInt64.max
|
||||
private(set) var sampleCount: Int = 0
|
||||
@@ -48,7 +48,7 @@ final class MemoryMonitor {
|
||||
init(
|
||||
interval: TimeInterval = 10,
|
||||
warningThreshold: UInt64 = 5 * 1024 * 1024,
|
||||
subsystem: String = "com.pangolin.pangolinVpn.PacketTunnel"
|
||||
subsystem: String = "com.yanmeiai.pangolin.PacketTunnel"
|
||||
) {
|
||||
self.interval = interval
|
||||
self.warningThreshold = warningThreshold
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<!--
|
||||
PacketTunnel.entitlements — PacketTunnel Extension Target Entitlements
|
||||
Bundle ID: com.pangolin.pangolinVpn.PacketTunnel
|
||||
Bundle ID: com.yanmeiai.pangolin.PacketTunnel
|
||||
|
||||
申请说明:
|
||||
1. com.apple.developer.networking.networkextension
|
||||
→ Extension Bundle ID 须单独在 Apple 开发者后台注册并开启:
|
||||
developer.apple.com → Identifiers → com.pangolin.pangolinVpn.PacketTunnel
|
||||
developer.apple.com → Identifiers → com.yanmeiai.pangolin.PacketTunnel
|
||||
→ Network Extensions → Packet Tunnel Provider(勾选)
|
||||
2. com.apple.security.application-groups
|
||||
→ 与主 App 使用相同 Group(group.com.pangolin.pangolinVpn)。
|
||||
→ 与主 App 使用相同 Group(group.com.yanmeiai.pangolin)。
|
||||
Extension 通过 UserDefaults(suiteName:) 写入最新 stats/status,
|
||||
主 App 在下次启动时读取(异常崩溃恢复场景)。
|
||||
-->
|
||||
@@ -25,7 +25,7 @@
|
||||
<!-- App Group:与主 App 共享 UserDefaults / 文件容器 -->
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.com.pangolin.pangolinVpn</string>
|
||||
<string>group.com.yanmeiai.pangolin</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -15,9 +15,9 @@ import Network
|
||||
import NetworkExtension
|
||||
import os
|
||||
|
||||
private let log = Logger(subsystem: "com.pangolin.pangolinVpn.PacketTunnel", category: "provider")
|
||||
private let log = Logger(subsystem: "com.yanmeiai.pangolin.PacketTunnel", category: "provider")
|
||||
// iOS App Group 用 group. 前缀(非 macOS 的 <TeamID>. 前缀)。
|
||||
private let appGroup = "group.com.pangolin.pangolinVpn"
|
||||
private let appGroup = "group.com.yanmeiai.pangolin"
|
||||
|
||||
final class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
private var commandServer: LibboxCommandServer?
|
||||
|
||||
@@ -265,7 +265,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1510;
|
||||
ORGANIZATIONNAME = com.pangolin;
|
||||
ORGANIZATIONNAME = "Yanmei AI LLC";
|
||||
TargetAttributes = {
|
||||
97C146ED1CF9000F007C117D = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
@@ -481,14 +481,14 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = BYL4KQHMTN;
|
||||
DEVELOPMENT_TEAM = 44WULXM6SV;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.pangolin.pangolinVpn;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.yanmeiai.pangolin;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
@@ -610,14 +610,14 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = BYL4KQHMTN;
|
||||
DEVELOPMENT_TEAM = 44WULXM6SV;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.pangolin.pangolinVpn;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.yanmeiai.pangolin;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
@@ -634,14 +634,14 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = BYL4KQHMTN;
|
||||
DEVELOPMENT_TEAM = 44WULXM6SV;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.pangolin.pangolinVpn;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.yanmeiai.pangolin;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
@@ -657,7 +657,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = PacketTunnel/PacketTunnel.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = BYL4KQHMTN;
|
||||
DEVELOPMENT_TEAM = 44WULXM6SV;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Frameworks",
|
||||
@@ -670,7 +670,7 @@
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
OTHER_LDFLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.pangolin.pangolinVpn.PacketTunnel;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.yanmeiai.pangolin.PacketTunnel;
|
||||
PRODUCT_NAME = PacketTunnel;
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
@@ -689,7 +689,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = PacketTunnel/PacketTunnel.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = BYL4KQHMTN;
|
||||
DEVELOPMENT_TEAM = 44WULXM6SV;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Frameworks",
|
||||
@@ -702,7 +702,7 @@
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
OTHER_LDFLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.pangolin.pangolinVpn.PacketTunnel;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.yanmeiai.pangolin.PacketTunnel;
|
||||
PRODUCT_NAME = PacketTunnel;
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
@@ -721,7 +721,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = PacketTunnel/PacketTunnel.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = BYL4KQHMTN;
|
||||
DEVELOPMENT_TEAM = 44WULXM6SV;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Frameworks",
|
||||
@@ -734,7 +734,7 @@
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
OTHER_LDFLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.pangolin.pangolinVpn.PacketTunnel;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.yanmeiai.pangolin.PacketTunnel;
|
||||
PRODUCT_NAME = PacketTunnel;
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<!--
|
||||
Runner.entitlements — 主 App Target Entitlements
|
||||
Bundle ID: com.pangolin.pangolinVpn
|
||||
Bundle ID: com.yanmeiai.pangolin
|
||||
|
||||
申请说明:
|
||||
1. com.apple.developer.networking.networkextension
|
||||
→ "packet-tunnel-provider" 须在 Apple 开发者后台显式申请。
|
||||
申请路径:developer.apple.com → Certificates, IDs & Profiles
|
||||
→ Identifiers → com.pangolin.pangolinVpn → Capabilities
|
||||
→ Identifiers → com.yanmeiai.pangolin → Capabilities
|
||||
→ Network Extensions → Packet Tunnel Provider(勾选)
|
||||
2. com.apple.security.application-groups
|
||||
→ group.com.pangolin.pangolinVpn 须在 App Groups 注册。
|
||||
→ group.com.yanmeiai.pangolin 须在 App Groups 注册。
|
||||
主 App 与 PacketTunnel extension 共享同一 Group,
|
||||
用于 UserDefaults(suiteName:) / FileManager containerURL(forSecurityApplicationGroupIdentifier:)
|
||||
传递少量共享状态(上次节点 tag、连接时间戳等)。
|
||||
@@ -27,7 +27,7 @@
|
||||
<!-- App Group:主 App ↔ PacketTunnel extension 共享容器 -->
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.com.pangolin.pangolinVpn</string>
|
||||
<string>group.com.yanmeiai.pangolin</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -65,9 +65,9 @@ class VpnManager: NSObject {
|
||||
private var tunnelManager: NETunnelProviderManager?
|
||||
|
||||
// Bundle ID 与 PacketTunnel target PRODUCT_BUNDLE_IDENTIFIER 保持同步
|
||||
private let extensionBundleId = "com.pangolin.pangolinVpn.PacketTunnel"
|
||||
private let extensionBundleId = "com.yanmeiai.pangolin.PacketTunnel"
|
||||
// App Group:与 PacketTunnel extension 共享 UserDefaults 容器
|
||||
private let appGroup = "group.com.pangolin.pangolinVpn"
|
||||
private let appGroup = "group.com.yanmeiai.pangolin"
|
||||
|
||||
private var statusObserver: NSObjectProtocol?
|
||||
|
||||
|
||||
@@ -12,11 +12,11 @@
|
||||
<key>NetworkExtension</key>
|
||||
<dict>
|
||||
<!-- NEMachServiceName 必须以扩展所属的某个 App Group 为前缀(Apple 规则)。
|
||||
App Group 用 macOS 原生格式 BYL4KQHMTN.com.pangolin.pangolin,mach 名 = 该 group
|
||||
App Group 用 macOS 原生格式 44WULXM6SV.com.yanmeiai.pangolin,mach 名 = 该 group
|
||||
+ .PacketTunnel。参照可工作的 Tailscale:group=<Team>.io.tailscale.ipn.macsys、
|
||||
mach=该 group + .network-extension。 -->
|
||||
<key>NEMachServiceName</key>
|
||||
<string>BYL4KQHMTN.com.pangolin.pangolin.PacketTunnel</string>
|
||||
<string>44WULXM6SV.com.yanmeiai.pangolin.PacketTunnel</string>
|
||||
<key>NEProviderClasses</key>
|
||||
<dict>
|
||||
<key>com.apple.networkextension.packet-tunnel</key>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
非 iOS 的 group. 前缀——sysextd realize 前校验请求方/扩展时要求此格式。 -->
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>BYL4KQHMTN.com.pangolin.pangolin</string>
|
||||
<string>44WULXM6SV.com.yanmeiai.pangolin</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -14,10 +14,10 @@ import Network
|
||||
import NetworkExtension
|
||||
import os
|
||||
|
||||
private let log = Logger(subsystem: "com.pangolin.pangolin.PacketTunnel", category: "provider")
|
||||
private let log = Logger(subsystem: "com.yanmeiai.pangolin.PacketTunnel", category: "provider")
|
||||
// macOS 原生 App Group 格式 <TeamID>.<name>(非 iOS 的 group. 前缀)。
|
||||
// sysextd 校验请求方 app 时要求此格式;用 group. 式会在 realize 暂存前被拒。
|
||||
private let appGroup = "BYL4KQHMTN.com.pangolin.pangolin"
|
||||
private let appGroup = "44WULXM6SV.com.yanmeiai.pangolin"
|
||||
|
||||
final class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
private var commandServer: LibboxCommandServer?
|
||||
|
||||
@@ -662,7 +662,7 @@
|
||||
CURRENT_PROJECT_VERSION = 55;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.pangolin.pangolin.RunnerTests;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.yanmeiai.pangolin.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/pangolin_vpn.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/pangolin_vpn";
|
||||
@@ -677,7 +677,7 @@
|
||||
CURRENT_PROJECT_VERSION = 55;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.pangolin.pangolin.RunnerTests;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.yanmeiai.pangolin.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/pangolin_vpn.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/pangolin_vpn";
|
||||
@@ -692,7 +692,7 @@
|
||||
CURRENT_PROJECT_VERSION = 55;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.pangolin.pangolin.RunnerTests;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.yanmeiai.pangolin.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/pangolin_vpn.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/pangolin_vpn";
|
||||
@@ -758,7 +758,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = BYL4KQHMTN;
|
||||
DEVELOPMENT_TEAM = 44WULXM6SV;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
@@ -893,7 +893,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = BYL4KQHMTN;
|
||||
DEVELOPMENT_TEAM = 44WULXM6SV;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
@@ -916,7 +916,7 @@
|
||||
CODE_SIGN_IDENTITY = "Developer ID Application";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = BYL4KQHMTN;
|
||||
DEVELOPMENT_TEAM = 44WULXM6SV;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
@@ -961,7 +961,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 55;
|
||||
DEVELOPMENT_TEAM = BYL4KQHMTN;
|
||||
DEVELOPMENT_TEAM = 44WULXM6SV;
|
||||
ENABLE_APP_SANDBOX = YES;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
@@ -982,8 +982,8 @@
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
OTHER_LDFLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.pangolin.pangolin.PacketTunnel;
|
||||
PRODUCT_NAME = com.pangolin.pangolin.PacketTunnel;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.yanmeiai.pangolin.PacketTunnel;
|
||||
PRODUCT_NAME = com.yanmeiai.pangolin.PacketTunnel;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SKIP_INSTALL = YES;
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||
@@ -1011,7 +1011,7 @@
|
||||
CODE_SIGN_IDENTITY = "Developer ID Application";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 55;
|
||||
DEVELOPMENT_TEAM = BYL4KQHMTN;
|
||||
DEVELOPMENT_TEAM = 44WULXM6SV;
|
||||
ENABLE_APP_SANDBOX = YES;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
@@ -1032,8 +1032,8 @@
|
||||
MTL_FAST_MATH = YES;
|
||||
OTHER_CODE_SIGN_FLAGS = "--timestamp";
|
||||
OTHER_LDFLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.pangolin.pangolin.PacketTunnel;
|
||||
PRODUCT_NAME = com.pangolin.pangolin.PacketTunnel;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.yanmeiai.pangolin.PacketTunnel;
|
||||
PRODUCT_NAME = com.yanmeiai.pangolin.PacketTunnel;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "Pangolin PacketTunnel DevID";
|
||||
SKIP_INSTALL = YES;
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||
@@ -1060,7 +1060,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 55;
|
||||
DEVELOPMENT_TEAM = BYL4KQHMTN;
|
||||
DEVELOPMENT_TEAM = 44WULXM6SV;
|
||||
ENABLE_APP_SANDBOX = YES;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
@@ -1079,8 +1079,8 @@
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.pangolin.pangolin.PacketTunnel;
|
||||
PRODUCT_NAME = com.pangolin.pangolin.PacketTunnel;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.yanmeiai.pangolin.PacketTunnel;
|
||||
PRODUCT_NAME = com.yanmeiai.pangolin.PacketTunnel;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SKIP_INSTALL = YES;
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
PRODUCT_NAME = pangolin_vpn
|
||||
|
||||
// The application's bundle identifier
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.pangolin.pangolin
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.yanmeiai.pangolin
|
||||
|
||||
// The copyright displayed in application information
|
||||
PRODUCT_COPYRIGHT = Copyright © 2026 com.pangolin. All rights reserved.
|
||||
PRODUCT_COPYRIGHT = Copyright © 2026 Yanmei AI LLC. All rights reserved.
|
||||
|
||||
@@ -21,12 +21,12 @@
|
||||
<!-- flutter_secure_storage: Data Protection Keychain 需要此 entitlement,否则返回 -34018 -->
|
||||
<key>keychain-access-groups</key>
|
||||
<array>
|
||||
<string>$(AppIdentifierPrefix)com.pangolin.pangolin</string>
|
||||
<string>$(AppIdentifierPrefix)com.yanmeiai.pangolin</string>
|
||||
</array>
|
||||
<!-- P1 方案B:接 System Extension 时在此加(注册 App Group 后,见 p1-macos-system-extension.md §3):
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.com.pangolin.pangolin</string>
|
||||
<string>group.com.yanmeiai.pangolin</string>
|
||||
</array>
|
||||
-->
|
||||
</dict>
|
||||
|
||||
@@ -5,7 +5,7 @@ import ServiceManagement
|
||||
class MainFlutterWindow: NSWindow {
|
||||
// launch_at_startup 插件在 macOS 没自带实现,需宿主接 MethodChannel。学 Tailscale 用
|
||||
// SMAppService.loginItem 注册内置的 PangolinLoginHelper(登录时它带 --autostart 拉起主 app)。
|
||||
private let loginHelperID = "com.pangolin.pangolin.LoginHelper"
|
||||
private let loginHelperID = "com.yanmeiai.pangolin.LoginHelper"
|
||||
|
||||
override func awakeFromNib() {
|
||||
let flutterViewController = FlutterViewController()
|
||||
|
||||
@@ -21,14 +21,14 @@
|
||||
<!-- flutter_secure_storage: Data Protection Keychain 需要此 entitlement,否则返回 -34018 -->
|
||||
<key>keychain-access-groups</key>
|
||||
<array>
|
||||
<string>$(AppIdentifierPrefix)com.pangolin.pangolin</string>
|
||||
<string>$(AppIdentifierPrefix)com.yanmeiai.pangolin</string>
|
||||
</array>
|
||||
<!-- 与 PacketTunnel sysext 共享 App Group。必须用 macOS 原生格式 <TeamID>.<name>
|
||||
(BYL4KQHMTN.com.pangolin.pangolin),非 iOS 的 group. 前缀——否则 sysextd 在 realize
|
||||
(44WULXM6SV.com.yanmeiai.pangolin),非 iOS 的 group. 前缀——否则 sysextd 在 realize
|
||||
暂存前校验请求方 app 时认定 app group 非法而拒绝(参照可工作的 Tailscale)。 -->
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>BYL4KQHMTN.com.pangolin.pangolin</string>
|
||||
<string>44WULXM6SV.com.yanmeiai.pangolin</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -17,15 +17,15 @@ import os.log
|
||||
|
||||
// os_log + %{public} —— 让日志在 Console.app / `log show` 里可见(NSLog 的 %@ 参数会被
|
||||
// 系统 redact 成 <private>,排障时看不到内容)。os_log(C API)自 macOS 10.12 起可用,
|
||||
// 兼容 Runner 的 10.15 部署目标。过滤:`log show --predicate 'subsystem == "com.pangolin.pangolin"'`。
|
||||
private let vpnLogObj = OSLog(subsystem: "com.pangolin.pangolin", category: "vpn")
|
||||
// 兼容 Runner 的 10.15 部署目标。过滤:`log show --predicate 'subsystem == "com.yanmeiai.pangolin"'`。
|
||||
private let vpnLogObj = OSLog(subsystem: "com.yanmeiai.pangolin", category: "vpn")
|
||||
private func vpnLog(_ message: String) {
|
||||
os_log("%{public}@", log: vpnLogObj, type: .default, message)
|
||||
NSLog("[pangolin/vpn] %@", message) // 同时进 stderr,flutter run 控制台也能看到
|
||||
}
|
||||
|
||||
final class VpnChannel: NSObject {
|
||||
private static let tunnelBundleId = "com.pangolin.pangolin.PacketTunnel"
|
||||
private static let tunnelBundleId = "com.yanmeiai.pangolin.PacketTunnel"
|
||||
|
||||
private var statusSink: FlutterEventSink?
|
||||
private var statsSink: FlutterEventSink?
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
set -euo pipefail
|
||||
|
||||
HELPER_NAME="PangolinLoginHelper"
|
||||
HELPER_ID="com.pangolin.pangolin.LoginHelper"
|
||||
HELPER_ID="com.yanmeiai.pangolin.LoginHelper"
|
||||
SRC="${SRCROOT}/login_helper/main.swift"
|
||||
DEST="${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/Library/LoginItems/${HELPER_NAME}.app"
|
||||
WORK="${DERIVED_FILE_DIR}/login_helper"
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
#!/usr/bin/env node
|
||||
// gen-signing.mjs — 从 scripts/signing.env(单一真相源)回填所有原生文件里的
|
||||
// Apple 签名标识符(Team ID / Bundle ID / App Group / 签名主体)。
|
||||
//
|
||||
// 为什么用 codegen 而非硬编码:Apple 工具链要求这些值以字面量出现在 pbxproj /
|
||||
// entitlements / plist / swift 里,无法像 shell 那样 source 一个变量;又分散在
|
||||
// 十几处,迁账号极易漏。本脚本让 signing.env 成为唯一手改点,一键回填全部字面量。
|
||||
//
|
||||
// 关键设计:所有匹配都是**结构化正则**(匹配 `DEVELOPMENT_TEAM = X`、native app
|
||||
// group 形状等),**不含任何旧的具体值**——所以①本脚本自身无「中国账号痕迹」;
|
||||
// ②未来再迁账号(改 signing.env 里的值)仍能正确回填,不依赖旧字面量。
|
||||
//
|
||||
// 用法:
|
||||
// node scripts/gen-signing.mjs 回填(就地改文件)
|
||||
// node scripts/gen-signing.mjs --check drift 闸:若有文件会被改动则退出 1(不改文件)
|
||||
//
|
||||
// 注:源码注释里遗留的旧标识符是内部字符串、不进产物;本脚本只管功能性字面量
|
||||
// (会被编译/签名进产物的),注释去痕由一次性清理处理。
|
||||
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname, join } from 'node:path';
|
||||
|
||||
const HERE = dirname(fileURLToPath(import.meta.url));
|
||||
const ROOT = join(HERE, '..');
|
||||
const CLIENT = join(ROOT, 'client');
|
||||
|
||||
// ── 读 signing.env 的 3 个基值(去引号),派生其余 ───────────────────────────
|
||||
function readEnv() {
|
||||
const txt = readFileSync(join(HERE, 'signing.env'), 'utf8');
|
||||
const pick = (k) => {
|
||||
const m = txt.match(new RegExp('^' + k + '="?([^"\\n]+)"?\\s*$', 'm'));
|
||||
if (!m) throw new Error(`signing.env 缺 ${k}`);
|
||||
return m[1].trim();
|
||||
};
|
||||
const TEAM = pick('SIGNING_TEAM_ID');
|
||||
const ENTITY = pick('SIGNING_ENTITY');
|
||||
const APP = pick('SIGNING_APP_BUNDLE_ID');
|
||||
return {
|
||||
TEAM, ENTITY, APP,
|
||||
EXT: `${APP}.PacketTunnel`,
|
||||
MAC_GROUP: `${TEAM}.${APP}`,
|
||||
IOS_GROUP: `group.${APP}`,
|
||||
};
|
||||
}
|
||||
|
||||
const V = readEnv();
|
||||
|
||||
// ── 每文件的结构化替换表(路径相对 client/)──────────────────────────────────
|
||||
// 每条 [正则, 替换串]。正则只描述「形状」,替换用派生值填入。
|
||||
const TABLE = {
|
||||
// ---- 通用:两个 pbxproj 的 Team + Bundle ID(按后缀区分 app/ext/tests)----
|
||||
'macos/Runner.xcodeproj/project.pbxproj': [
|
||||
[/DEVELOPMENT_TEAM = [A-Za-z0-9]+;/g, `DEVELOPMENT_TEAM = ${V.TEAM};`],
|
||||
[/PRODUCT_BUNDLE_IDENTIFIER = [\w.]+\.PacketTunnel;/g, `PRODUCT_BUNDLE_IDENTIFIER = ${V.EXT};`],
|
||||
[/PRODUCT_NAME = [\w.]+\.PacketTunnel;/g, `PRODUCT_NAME = ${V.EXT};`],
|
||||
[/PRODUCT_BUNDLE_IDENTIFIER = [\w.]+\.RunnerTests;/g, `PRODUCT_BUNDLE_IDENTIFIER = ${V.APP}.RunnerTests;`],
|
||||
],
|
||||
'ios/Runner.xcodeproj/project.pbxproj': [
|
||||
[/DEVELOPMENT_TEAM = [A-Za-z0-9]+;/g, `DEVELOPMENT_TEAM = ${V.TEAM};`],
|
||||
[/PRODUCT_BUNDLE_IDENTIFIER = [\w.]+\.PacketTunnel;/g, `PRODUCT_BUNDLE_IDENTIFIER = ${V.EXT};`],
|
||||
// 主 app:不以 .PacketTunnel 结尾的那条(负向前瞻,避免误改扩展行)。
|
||||
[/PRODUCT_BUNDLE_IDENTIFIER = (?![\w.]*\.PacketTunnel;)[\w.]+;/g, `PRODUCT_BUNDLE_IDENTIFIER = ${V.APP};`],
|
||||
],
|
||||
// ---- macOS xcconfig(主 app Bundle ID + 版权)----
|
||||
'macos/Runner/Configs/AppInfo.xcconfig': [
|
||||
[/^PRODUCT_BUNDLE_IDENTIFIER = .+$/m, `PRODUCT_BUNDLE_IDENTIFIER = ${V.APP}`],
|
||||
[/^PRODUCT_COPYRIGHT = .+$/m, `PRODUCT_COPYRIGHT = Copyright © 2026 ${V.ENTITY}. All rights reserved.`],
|
||||
],
|
||||
// ---- macOS entitlements:app-identifier 前缀 + native app group ----
|
||||
'macos/Runner/Release.entitlements': [
|
||||
[/\$\(AppIdentifierPrefix\)[\w.]+/g, `$(AppIdentifierPrefix)${V.APP}`],
|
||||
[/<string>[A-Z0-9]{10}\.[\w.]+<\/string>/g, `<string>${V.MAC_GROUP}</string>`],
|
||||
],
|
||||
'macos/Runner/DebugProfile.entitlements': [
|
||||
[/\$\(AppIdentifierPrefix\)[\w.]+/g, `$(AppIdentifierPrefix)${V.APP}`],
|
||||
[/<string>group\.[\w.]+<\/string>/g, `<string>${V.IOS_GROUP}</string>`],
|
||||
],
|
||||
'macos/PacketTunnel/PacketTunnel.entitlements': [
|
||||
[/<string>[A-Z0-9]{10}\.[\w.]+<\/string>/g, `<string>${V.MAC_GROUP}</string>`],
|
||||
],
|
||||
// ---- macOS PacketTunnel Info.plist:NEMachServiceName = app group + .PacketTunnel ----
|
||||
'macos/PacketTunnel/Info.plist': [
|
||||
[/<string>[A-Z0-9]{10}\.[\w.]+\.PacketTunnel<\/string>/g, `<string>${V.MAC_GROUP}.PacketTunnel</string>`],
|
||||
],
|
||||
// ---- macOS Swift / 登录助手脚本 ----
|
||||
'macos/PacketTunnel/PacketTunnelProvider.swift': [
|
||||
[/subsystem: "[\w.]+"/g, `subsystem: "${V.EXT}"`],
|
||||
[/appGroup = "[\w.]+"/g, `appGroup = "${V.MAC_GROUP}"`],
|
||||
],
|
||||
'macos/Runner/VpnChannel.swift': [
|
||||
[/subsystem: "[\w.]+"/g, `subsystem: "${V.APP}"`],
|
||||
[/tunnelBundleId = "[\w.]+"/g, `tunnelBundleId = "${V.EXT}"`],
|
||||
],
|
||||
'macos/Runner/MainFlutterWindow.swift': [
|
||||
[/loginHelperID = "[\w.]+"/g, `loginHelperID = "${V.APP}.LoginHelper"`],
|
||||
],
|
||||
'macos/build_login_helper.sh': [
|
||||
[/HELPER_ID="[\w.]+"/g, `HELPER_ID="${V.APP}.LoginHelper"`],
|
||||
],
|
||||
// ---- iOS entitlements(group. 前缀 app group)----
|
||||
'ios/Runner/Runner.entitlements': [
|
||||
[/<string>group\.[\w.]+<\/string>/g, `<string>${V.IOS_GROUP}</string>`],
|
||||
],
|
||||
'ios/PacketTunnel/PacketTunnel.entitlements': [
|
||||
[/<string>group\.[\w.]+<\/string>/g, `<string>${V.IOS_GROUP}</string>`],
|
||||
],
|
||||
// ---- iOS Swift ----
|
||||
'ios/Runner/VpnManager.swift': [
|
||||
[/extensionBundleId = "[\w.]+"/g, `extensionBundleId = "${V.EXT}"`],
|
||||
[/appGroup = "[\w.]+"/g, `appGroup = "${V.IOS_GROUP}"`],
|
||||
],
|
||||
'ios/PacketTunnel/PacketTunnelProvider.swift': [
|
||||
[/subsystem: "[\w.]+"/g, `subsystem: "${V.EXT}"`],
|
||||
[/appGroup = "[\w.]+"/g, `appGroup = "${V.IOS_GROUP}"`],
|
||||
],
|
||||
'ios/PacketTunnel/MemoryMonitor.swift': [
|
||||
[/subsystem: String = "[\w.]+"/g, `subsystem: String = "${V.EXT}"`],
|
||||
],
|
||||
};
|
||||
|
||||
// ── 执行 ─────────────────────────────────────────────────────────────────────
|
||||
const check = process.argv.includes('--check');
|
||||
let changed = 0;
|
||||
const changedFiles = [];
|
||||
for (const [rel, rules] of Object.entries(TABLE)) {
|
||||
const path = join(CLIENT, rel);
|
||||
const before = readFileSync(path, 'utf8');
|
||||
let after = before;
|
||||
for (const [re, repl] of rules) after = after.replace(re, repl);
|
||||
if (after !== before) {
|
||||
changed++;
|
||||
changedFiles.push(rel);
|
||||
if (!check) writeFileSync(path, after);
|
||||
}
|
||||
}
|
||||
|
||||
if (check) {
|
||||
if (changed) {
|
||||
console.error(`❌ signing codegen drift:${changed} 个文件与 signing.env 不一致:`);
|
||||
for (const f of changedFiles) console.error(' - ' + f);
|
||||
console.error(' 跑 `node scripts/gen-signing.mjs` 回填后重试。');
|
||||
process.exit(1);
|
||||
}
|
||||
console.log('✅ signing codegen 无 drift(原生文件与 signing.env 一致)');
|
||||
} else {
|
||||
console.log(`signing codegen 完成:回填 ${changed} 个文件` + (changed ? ':' : '(已一致,无改动)'));
|
||||
for (const f of changedFiles) console.log(' - ' + f);
|
||||
console.log(` TEAM=${V.TEAM} APP=${V.APP} MAC_GROUP=${V.MAC_GROUP} IOS_GROUP=${V.IOS_GROUP}`);
|
||||
}
|
||||
+9
-5
@@ -1,11 +1,15 @@
|
||||
# signing.env — Apple 签名身份的【单一真相源】(shell 侧)
|
||||
#
|
||||
# 迁移开发者账号 / 改 Bundle ID 时,只改这一个文件;三个签名脚本
|
||||
# (local_test.sh / ci/compile-macos.sh / ci/compile-ios.sh)全部 source 它,
|
||||
# 不再各自硬编码。非机密(Team ID / 实体名 / Bundle ID 本就编进产物、公开),入 git。
|
||||
# 【迁移账号 / 改 Bundle ID 时,改这一个文件就够】,然后跑一次:
|
||||
# node scripts/gen-signing.mjs
|
||||
# 它会把这里的值回填进所有原生文件(pbxproj/entitlements/plist/swift)的字面量
|
||||
# ——Apple 工具链要求这些值以字面量出现、无法 source 变量,故用 codegen 保持单源。
|
||||
#
|
||||
# ⚠️ Xcode 侧另有等价单一真相源 client/Signing.xcconfig(格式不同、内容须一致),
|
||||
# 由 ci/check-signing-config.sh 一致性闸比对,防两处漂移。改这里也要改那里。
|
||||
# 消费方:
|
||||
# - 三个签名脚本(local_test.sh / ci/compile-macos.sh / ci/compile-ios.sh)直接 source 本文件;
|
||||
# - 原生文件(Xcode/Swift)由 scripts/gen-signing.mjs 从本文件回填(勿手改那些标识符)。
|
||||
# drift 闸:ci/check-codegen-drift.sh 跑 `gen-signing.mjs --check`,防改了 env 没重生成 /
|
||||
# 手改了原生标识符。非机密(Team ID / 实体名 / Bundle ID 本就编进产物、公开),入 git。
|
||||
|
||||
# 10 位 Team ID(developer.apple.com → Membership details)。
|
||||
SIGNING_TEAM_ID="44WULXM6SV"
|
||||
|
||||
Reference in New Issue
Block a user