Files
OSGKeyboard/OSGKeyboardExt/Utilities/HostBundleProbe.swift
T
Rocky 4dce67df84 chore(release): bump version to 2.1.6 (build 131)
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
2026-10-29 11:54:13 +08:00

68 lines
2.6 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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