Version: CURRENT_PROJECT_VERSION 130 -> 131 (project.yml, AGENTS.md, READMEs, docs/llms.txt). fix(flow): host-app identification now compiles in every build configuration (Debug, TestFlight, Release). The arbiter probe and HostAppIdentity were DEBUG-only, so TestFlight/App Store builds never knew the host bundle id and could not auto-return after a startflow handoff. Debug-only logging and the Home test card are unchanged. Also includes the pending work in the tree: - Home: single account/setup card surface (HomeAccountSurfacePolicy/Views) - Wide screens: voice key row and centred mic placement, iPhone Duo layout - Keyboard: clipboard skill ranking and AI skill layout updates - Debug: account session handoff to the Simulator (+ import script) - Docs: portfolio assets, privacy policy URL, site/README refresh
68 lines
2.6 KiB
Swift
68 lines
2.6 KiB
Swift
// HostBundleProbe.swift
|
||
// OSGKeyboard · Keyboard Extension
|
||
//
|
||
// 识别当前宿主 App 的 bundle ID,供冷启动跳转主 App 后自动跳回。
|
||
// 依赖私有 arbiter 探针(`OSGHostArbiterProbe`),Debug / TestFlight / Release 均生效;
|
||
// 探针装不上(系统 < 26.4、私有符号改名)时识别结果为 nil,退化为“不自动跳回”。
|
||
// 调试日志与首页测试卡片仍只在 DEBUG 编译。
|
||
|
||
import Foundation
|
||
import OSGKeyboardShared
|
||
|
||
enum HostAppIdentity {
|
||
/// 最近一次识别到的宿主;识别不到、或宿主是 OSG 自己时为 nil。
|
||
static var currentBundleId: String? {
|
||
guard let bundleId = OSGHostArbiterProbe.lastCapturedBundleId,
|
||
!HostAppURLRegistry.isOwnBundleId(bundleId) else {
|
||
return nil
|
||
}
|
||
return bundleId
|
||
}
|
||
|
||
/// 键盘弹出时主动让 arbiter 回调一次,避免宿主没变时拿不到最新 ID。
|
||
static func refreshOnPresentation() {
|
||
OSGHostArbiterProbe.pingArbiter()
|
||
}
|
||
|
||
/// 跳转主 App(`startflow`)前调用:把当前宿主写进 App Group,主 App 就绪后据此跳回。
|
||
/// 识别不到时写 nil,清掉上一次残留,避免跳回错误的 App。
|
||
static func publishReturnTarget() {
|
||
let bundleId = currentBundleId
|
||
FlowSessionBridge.setPendingHostBundleId(bundleId)
|
||
#if DEBUG
|
||
let returnable = HostAppURLRegistry.lookup(bundleId: bundleId) != nil
|
||
HostBundleProbeLog.append(
|
||
event: "startflow",
|
||
bundleId: bundleId,
|
||
detail: returnable ? "returnable" : "no-return-url"
|
||
)
|
||
#endif
|
||
}
|
||
|
||
/// 键盘收起时作废识别结果,下次弹出由新回调重新填充。
|
||
static func invalidate() {
|
||
OSGHostArbiterProbe.invalidateCapturedBundleId()
|
||
}
|
||
}
|
||
|
||
#if DEBUG
|
||
/// 调试:把探针回调写进 App Group,主 App 首页的测试卡片读取展示。
|
||
enum HostBundleProbe {
|
||
/// 只需安装一次;回调可能来自非主线程,闭包必须是 nonisolated。
|
||
static func installLogging() {
|
||
OSGHostArbiterProbe.setCaptureHandler { @Sendable bundleId, detail in
|
||
HostBundleProbeLog.append(event: "arbiter", bundleId: bundleId, detail: detail)
|
||
}
|
||
}
|
||
|
||
/// 键盘弹出时记一条标记,便于把记录和每次弹出对应起来(ping 由 `HostAppIdentity` 负责)。
|
||
static func recordPresentation() {
|
||
HostBundleProbeLog.append(
|
||
event: "appear",
|
||
bundleId: nil,
|
||
detail: OSGHostArbiterProbe.isInstalled ? "hook=installed" : "hook=missing"
|
||
)
|
||
}
|
||
}
|
||
#endif
|