用途:该技能指导为 iOS App 添加 Share Extension,让用户在系统分享面板中把链接或文本保存进原生 App,且复用 App 已有的登录态与后端保存路径,不新增服务端端点、不要求重新登录。
主要能力与模型:分享扩展是独立进程,拥有自己的 bundle id、entitlements 和登录状态,不会自动继承宿主 App 的钥匙串或网络会话。因此需要两座桥:一是通过 keychain access group 共享 Clerk 会话,使扩展以已登录用户身份调用 Convex;二是通过 App Group UserDefaults 共享保存队列,网络不可达或扩展冷启动时先入队,宿主 App 下次激活时排空队列。两座桥都需在 App 和扩展两个 target 上配置 entitlements 与一致的常量。
关键坑点:Clerk 钥匙串 service 默认取进程 bundle id,App 与扩展 bundle id 不同会看到未登录状态。需在两个 target 的 Clerk.configure(options:) 中把 service 和 accessGroup 固定为相同值。注意固定 service/accessGroup 会改变会话存储位置,已登录用户升级后需重新登录一次,属预期行为。
构建顺序:两个 target 配置 App Group 与 keychain-access-group entitlements;在 App 与扩展中固定 Clerk 钥匙串;用 project.yml(XcodeGen)添加 app-extension target 并嵌入 App,共享 auth/config 源码;配置 Info.plist 的激活规则;实现 ShareViewController,提取内容、抓取预览、构建已鉴权 Convex 客户端并调用保存 action,失败时回退到 App Group 队列;用 UIHostingController 承载 SwiftUI 品牌卡片 UI;宿主 App 在 scenePhase == .active 时排空队列;可选做只读 Convex action 实现分类预览。
必要用法要点:扩展类型为 app-extension,NSExtensionPointIdentifier = com.apple.share-services;主类为 $(PRODUCT_MODULE_NAME).ShareViewController;复用 ConvexClientWithAuth 与 ClerkConvexAuthProvider,await client.login() 后调用 client.action("app:saveFromApp", ...);预览用 LPMetadataProvider,8 秒超时;扩展 target 只共享 Config.swift、ClerkConvexAuthProvider.swift 和 Shared/ 目录。
限制与常见错误:扩展显示未登录多为未固定 Clerk service/accessGroup、缺少 entitlement 或 accessGroup 格式不对(运行时需 teamID.<id>);App Group 读空多为两端组名不一致或未启用能力;分享面板不显示 App 多为激活规则不匹配或扩展未嵌入;扩展上 GENERATE_INFOPLIST_FILE: YES 会覆盖 NSExtension;不要打包整个 App;不要让保存在无网络时阻塞且无回退。走同一保存 action 可保持单一代码路径并让响应式查询自动刷新。具体常量值与代码示例见技能附带的 reference 文件,本页未提供完整内容。