- AI Agent
- 人工智能
- 代码智能体
- 交互助手
【免费下载链接】openchamber
Agentic Development Environment based on OpenCode AI agent
导读:本文围绕
packages/mobile/HANDOFF.md这一交接文档展开,系统讲解 OpenChamber 原生 iOS/Android 应用的完整技术栈:它如何用 Capacitor 将托管式移动端 Web UI(MobileApp)包装成真正的原生 App,如何通过with-mobile-env.mjs统一管理 Xcode/JDK/Android SDK 工具链,如何实现连接引导、QR 配对、安全存储、深链、推送通知、桌面组件与 Control Center 等原生能力,以及当前距 TestFlight / Play 内部测试还差哪些 CI、签名与审核事项。读完本文,你将掌握 OpenChamber 移动端的构建命令、原生能力清单、平台配置要点、已知坑位与发布路线图,可直接据此继续开发或补齐发布自动化。
一、这个包是什么:Capacitor 壳工程而不是桌面壳
packages/mobile是 OpenChamber 仓库中的Capacitor 工作区,它包装的是托管式移动端 Web UI(即MobileApp渲染器),而不是桌面端的 Electron 壳。原生 App 本质上是:
- iOS:一个WKWebView
- Android:一个Android WebView
两者加载的是打进 App 包里的 Web 构建产物副本;原生能力则通过 Capacitor 插件和两个 iOS App Extension 补充。
基本身份信息
- App ID / 包名:
com.openchamber.app;应用名称OpenChamber。 - Capacitor 配置:capacitor.config.ts 中关键的三个插件设置:
Keyboard.resize: 'none'—— 键盘弹出时 WebView 保持全高,UI 通过--oc-keyboard-insetCSS 变量自行跟随键盘(useNativeMobileChrome驱动),而非等待内建 resize 动画结束后再调整(实测内建方案有约 1.5s 延迟);StatusBar覆盖 WebView(overlay);PushNotifications.presentationOptions: []—— 前台时永不显示 APNs 横幅(见推送章节)。
- 渲染入口:Web 构建的
mobile.html入口(MobileApp),被复制进dist/并由 Capacitor 伺服。 - Capacitor 专属表面:连接引导(connection onboarding)、
Instances管理、QR 配对、小组件等只存在于 Capacitor 壳内——在普通浏览器里直接访问托管mobile.html并不会暴露这些能力。
这一点在 README.md 中描述得更细:移动包复用 Web 构建,然后把mobile.html改写为packages/mobile/dist中的index.html,确保原生 iOS/Android 启动时永远进入MobileApp而非托管的表面选择器;原生 App不内嵌OpenChamber Web 服务器或 OpenCode 服务器,首次启动时展示连接已有服务器的界面。
运行模型要点
- 连接保存在 App 本地,可从会话抽屉底部的
Instances管理;首次连接界面与Instances入口都是 Capacitor 专属能力。 - 手机与平板共用同一套导航模型:左侧会话抽屉/侧栏、右侧工作区抽屉(Changes / Files / Terminal / Notes / MCP),无 overflow 菜单;平板差异仅在会话列表是可调整宽度的常驻侧栏、头部下拉是锚定弹层。
- 平板布局是一个实时尺寸类(
useTabletLayout),不是设备检测:任何短边 ≥ 600px 的表面都会获得平板布局,工作区只有在宽度足以同时容纳侧栏、面板和可读的聊天列时才会变成侧面板(WORKSPACE_PANEL_MIN_WIDTH_PX = 1000)。书页式折叠屏展开时命中该尺寸类,折叠后自动回落手机布局;Android activity 声明了匹配的configChanges,因此折叠只是 resize WebView 而非重建。实现见 lib/device.ts - 密码保护的 OpenChamber 服务器可在移动端解锁,App 会把签发的 client token 与保存的连接一并存储。
二、构建管线:Web 构建如何变成原生二进制
HANDOFF 文档给出了完整的构建链路:
bun run --cwd packages/web build # web/dist → scripts/prepare-web-assets.mjs # copy web/dist → mobile/dist, mobile.html → index.html → cap sync # copy dist → native, sync plugins/config → xcodebuild / gradle assembleDebug # native binarysync(在 package.json 中定义)实际执行的是bun run build && cap sync,并且整个流程跑在移动端环境包装器里。
prepare-web-assets.mjs:HTML 入口重写
prepare-web-assets.mjs 做的事非常直接:清空并重建mobile/dist,把web/dist递归复制过去,然后把dist/mobile.html的内容写到dist/index.html。这样原生容器永远加载index.html(即MobileApp),而不是托管表面选择器。
工具链包装器 with-mobile-env.mjs(排错构建环境问题前必读)
with-mobile-env.mjs 是所有构建/部署脚本的统一入口,它为子进程设置环境变量,环境变量覆盖优先:
| 变量 | 解析顺序(先到先用) | 默认/兜底值 |
|---|---|---|
DEVELOPER_DIR | $DEVELOPER_DIR→xcode-select -p→ 硬编码路径 | /Applications/Xcode.app/Contents/Developer |
JAVA_HOME | $JAVA_HOME→ 兜底 | /opt/homebrew/opt/openjdk@21 |
ANDROID_HOME/ANDROID_SDK_ROOT | $ANDROID_HOME→ 兜底 | /opt/homebrew/share/android-commandlinetools |
PATH | 前插$JAVA_HOME/bin与$ANDROID_HOME/platform-tools | 保证adb可解析 |
设计上它有意尊重xcode-select:这样 Xcode 测试版或非默认安装也能被正确使用——文档明确说明此前硬编码路径曾把构建推到错误的 Xcode / Command Line Tools 上(模拟器运行时不匹配会导致xcodebuild找不到目标模拟器)。换一台机器时,请通过环境变量覆盖这些值而不是改脚本;即使xcode-select指向 Command Line Tools,包装器对移动命令的DEVELOPER_DIR处理也能覆盖到。
三、命令速查:根别名与包内命令
根目录别名(从仓库根运行)
bun run mobile:build # web build + prepare-web-assets bun run mobile:sync # build + cap sync bun run mobile:build:android:debug # sync + gradle assembleDebug bun run mobile:build:ios:simulator # simulator build(会临时剥离 MLKit pod,见"坑位") bun run mobile:open:ios # 在 Xcode 中打开 bun run mobile:open:android # 在 Android Studio 中打开 bun run type-check:mobile bun run lint:mobileAndroid 真机部署(adb 方式,未做根别名)
这些命令基于 android-device.mjs,需在包目录内运行:
bun run --cwd packages/mobile android:devices # 列出 adb 设备(期望 `device` 而非 `unauthorized`) bun run --cwd packages/mobile android:install # adb install -r 安装 debug APK bun run --cwd packages/mobile android:launch # am start MainActivity bun run --cwd packages/mobile android:run # 安装 + 启动 bun run --cwd packages/mobile android:logcat # 应用日志典型的真机迭代流程:先bun run --cwd packages/mobile build:android:debug产出 APK,再android:run。APK 路径固定为android/app/build/outputs/apk/debug/app-debug.apk。脚本内部细节:requireDevice()会提示开启开发者选项 + USB 调试并接受授权弹窗;launch通过am start -n com.openchamber.app/.MainActivity启动;logcat优先按pidof过滤该 App 的日志,未运行时退化为流式输出 Capacitor/Chromium 日志。
iOS 模拟器辅助命令
mobile:sim:{boot,install,launch,run,serve,list,kill}一组(见 ios-sim.mjs):boot默认启动iPhone 17 Pro;install/launch/run通过xcrun simctl操作构建产物App.app;serve-sim提供模拟器画面的浏览器预览流。sim:dev(ios-sim-dev.mjs)是一键开发循环:构建模拟器 App → 安装启动 → 启动serve-sim流并打印预览 URL,Ctrl+C 停止流(可传--no-build跳过慢速构建直接重跑)。
无头快速上手
bun run build bun run sync bun run build:ios:simulator bun run build:android:debug以上命令不启动 Xcode、Android Studio、Simulator 或模拟器,即可完成原生工程构建与同步。
四、已实现的原生能力清单
- 连接引导(Connection onboarding):服务器 URL 输入、锁定服务器的密码解锁、client-token 签发、已保存连接管理、
Instances管理面板、启动时自动连接最后一次实例。删除活动实例会把运行时重置回连接界面。连接的持久化模型在 mobileConnections.ts 中有清晰注释:实例元数据(id/label/url/lastUsedAt +hasToken标志)存 localStorage,绝不包含 token;client token 通过@aparajita/capacitor-secure-storage存进系统安全存储(iOS Keychain / Android Keystore),按实例 URL 为键。token 写入是await后才切换运行时端点,保证解锁成功即持久化成功。 - QR 配对:基于
@capacitor-mlkit/barcode-scanning。Android 走 CameraX 支撑的startScan()流程,条码模型打包进 App,因此离线且不依赖 Google Play Services也能扫描;iOS 用插件自带原生扫描器。已声明CAMERA权限与NSCameraUsageDescription。前端逻辑见 mobileQrScan.ts:isQrScanSupported()检测插件存在性,scanConnectionQr()统一处理权限申请(拒绝返回permission-denied)、Android 的事件监听式扫描与 iOS 的一次性scan(),并兼容老 Android WebView 解析openchamber://失败时的字符串兜底解析。 - 安全存储:
@aparajita/capacitor-secure-storage存连接 token(见上)。 - 深链(Deep links):
openchamber://URL scheme;一套可复用的意图词表(deepLinks.ts),被通知点击、小组件、Control Center 共同使用;冷启动意图会被暂存。parseDeepLink()把原始 URL 解析成类型化DeepLinkIntent(session / new-session / sessions / status / settings / changes / view),未知路由返回null而非抛错;deepLinkNavigation.ts 是唯一知道如何应用意图的层,模块级pending持有器保证冷启动的意图在 App ready 后仍能被消费(最新意图胜出)。 - 推送通知:iOS APNs + Android FCM(详见下一节)。存在感知路由:当交互式(桌面/Web)客户端可见时,抑制该设备的推送。
- iOS 小组件 + Control Center + 通知服务扩展:WidgetKit 扩展(
OpenChamberWidget)、一个 Control Center 控制项、以及一个 NSE(OpenChamberNotificationService)——NSE 负责在推送到达时刷新小组件。三者共享 App Groupgroup.com.openchamber.app。 - 原生 Chrome:状态栏(iOS 覆盖 + 安全区;Android inset + 主题背景)、键盘处理(iOS CSS inset;Android 原生
adjustResize)、边缘滑动切换会话、返回键处理、App 图标角标。 - 应用图标:iOS
AppIcon;Android 自适应启动图标;通知小图标(ic_stat_notify)。
五、推送/通知架构
- 注册:启动时 App 注册设备 token——iOS → APNs、Android → FCM——并打上
platform(ios/android)标签发送给已连接的服务器。 - 转发:服务器把值得通知的事件转发给已签名的 relay;relay 按 token 绑定的平台路由到 APNs 或 FCM。App 自身只需要获取并注册 token。
- 存在感知抑制:每个客户端上报前台可见性 + 平台;当交互式(桌面/Web/VSCode)客户端可见时跳过移动端推送(它已在应用内展示通知)。门控条件是桌面的可见性,而不是手机自身的可见性。
- 前台行为:iOS 通过
presentationOptions: []抑制横幅(服务器总是发送、无竞态可见性门控,前台由 iOS 抑制展示);Web/PWA 的 service worker 在窗口聚焦时抑制展示。
iOS 侧还有一个值得注意的细节:AppDelegate.swift中计算apnsEnvironment(development/production),从内嵌的 provisioning profile 读取aps-environmententitlement,无内嵌 profile 的 App Store 构建即为production;该值通过__OPENCHAMBER_APNS_ENV__文档起始脚本暴露给 Web 层,让服务器把每个设备 token 投递到真正认识它的 APNs 端点(sandbox vs production)。
六、平台配置细节
iOS(ios/App)
- 扩展:
OpenChamberWidget(WidgetKit,部署目标 17.0)与OpenChamberNotificationService(NSE,15.5),两者都手工接线进App.xcodeproj/project.pbxproj并通过 copy phase 内嵌。 - 三个 target(App + Widget + NSE)的 entitlements 都声明App Group
group.com.openchamber.app。 Info.plist:CFBundleURLTypes注册openchamberscheme;NSCameraUsageDescription(扫描配对 QR 码)、NSMicrophoneUsageDescription(语音输入)、NSLocalNetworkUsageDescription(连接局域网服务器)等使用说明字符串齐备;NSAppTransportSecurity对 Web 内容允许任意加载并允许本地网络。- 需要push entitlement(aps-environment)。
- APNs
mutable-content: 1(在服务器/relay 侧设置)会唤醒 NSE 刷新小组件。
Android(android/app)
google-services.json已提交(Firebase 项目openchamber-8bf7e)。Google Services Gradle 插件在文件存在时条件应用(build.gradle 中file('google-services.json')存在即apply plugin: 'com.google.gms.google-services');@capacitor/push-notifications引入firebase-messaging。- Manifest(AndroidManifest.xml):权限
INTERNET、CAMERA(+ 可选相机 featureandroid.hardware.camera required=false)、POST_NOTIFICATIONS(Android 13+;旧版本默认允许通知)、以及语音输入所需的RECORD_AUDIO+MODIFY_AUDIO_SETTINGS;windowSoftInputMode=adjustResize;FCMdefault_notification_icon=@drawable/ic_stat_notify(状态栏/通知栏小图标,必须是单色剪影)。 - 自适应启动图标:全出血纯色背景 +
ic_launcher_foreground(源文件在packages/mobile/assets/,可用@capacitor/assets重新生成)。 - SDK 级别(variables.gradle):
minSdk 24、compileSdk 35、targetSdk 35,满足 Play 当前要求。 - CI 签名预留:
build.gradle已预留从环境变量(OPENCHAMBER_ANDROID_KEYSTORE_PATH等)读取 release 签名配置的逻辑,hasCiSigning为真时才启用签名,为后续 CI 打带签名的 release 包铺路。
七、已知坑位(Quirks / gotchas)
- iOS 模拟器 + MLKit:
GoogleMLKit条码库没有 arm64-simulator 切片,正常构建会产出只有 x86_64 的二进制,无法装进 arm64-only 的 iOS 26+ 模拟器("does not contain code for ... arm64")。因此 ios-sim-build.mjs 会临时从 Podfile 剥离CapacitorMlkitBarcodeScanningpod →pod install→ 构建 arm64 模拟器二进制 → 在finally中始终恢复Podfile + Pods(模拟器没有摄像头,剥离扫描器不损失功能;前端mobileQrScan在原生插件缺失时会干净降级:getScannerPlugin()返回null→isQrScanSupported()为 false)。真机/TestFlight 构建则正常包含扫描器。 - Android WebView 版本:UI 使用了
color-mix()(Tailwind v4 + 主题),需要Chromium 111+。过旧的 Android System WebView 会导致半透明/选区渲染错误——提醒测试人员保持 Android System WebView 更新(或使用自带较新版本的设备)。 - Capacitor 流传输锁定为 SSE:原生 App 上原生 WebSocket 流在 Android 上不可靠,因此 Chat 传输设置会显示选中 SSE 并禁用其他选项。
- Android 推送必须带
google-services.json重新构建:没有它,register()曾直接崩溃("Default FirebaseApp is not initialized")。注册逻辑已门控到 iOS/Android 原生环境。 - 混合内容:
capacitor.config.ts中android.allowMixedContent: true允许 Android WebView(https://origin)访问明文 http 局域网服务器(如http://192.168.x.x);iOS 无此问题(capacitor://scheme),relay/tunnel 流量本身走 TLS。
八、验证命令与预期警告
bun run type-check:mobile bun run lint:mobile bun run mobile:build:android:debug bun run mobile:build:ios:simulatorWeb 继承的构建警告(KaTeX 字体 URL、onnxruntime-webeval、chunk-size)是预期且非致命的。
九、差距:CI / 发布自动化(下一步工作)
App 目前仅能本地构建与部署,还没有 CI、签名与发布管线。要推进到 TestFlight / Play 内部测试,需要:
iOS
- Apple Developer 账号;为 App和两个扩展分别创建 App ID(
com.openchamber.app、.OpenChamberWidget、.OpenChamberNotificationService),各自启用App Group和(App 的)Push。 - 三个 target 的签名证书 + provisioning profiles(扩展需要各自的 profile)。
- App Store Connect API key 用于非交互式 TestFlight 上传(
xcodebuild archive+notarytool/altool,或 fastlanegym+pilot)。 - Runner:与
DEVELOPER_DIR相同 Xcode 版本的 macOS。
Android
- Release keystore(作为 CI secret 保存);构建签名的 AAB(
bundleRelease)——当前 debug 脚本产出的是未签名 debug APK。 - Play Console 应用 + 内部测试轨道;用于自动化上传的 Play service account(fastlane
supply或 Play Developer API)。 google-services.json已提交,因此 CI 中 FCM 构建无需额外配置。- Runner:带 Android SDK +
openjdk@21的 Linux。
CI 备注
- 复用
with-mobile-env.mjs的环境契约(DEVELOPER_DIR、JAVA_HOME、ANDROID_HOME)——在 workflow 中设置它们,而不是依赖本地 Homebrew 路径。 - Relay/推送密钥(APNs key、FCM service account)属于 relay 基础设施,不在 App CI 中。
- 版本/构建号自动递增尚未自动化。
十、商店审核就绪度
Xcode 构建警告不会阻塞审核;具体事项是商店要求而非代码质量问题。
仓库内已完成(当前分支):
- iOS隐私清单(PrivacyInfo.xcprivacy):声明不追踪(
NSPrivacyTracking = false,无追踪域、无收集数据类型),并声明必需的 UserDefaults API 原因(CA92.1、C56D.1,对应 App Group 快照);打包的 SDK 自带各自的清单。 - iOS
ITSAppUsesNonExemptEncryption = false(Info.plist):跳过每次构建的出口合规提示。 - iOS 相机 + 本地网络使用说明字符串;Android SDK 级别(
target/compile 35、min 24)满足 Play 当前要求。
发布时需在控制台/基础设施完成(非代码):
- 隐私政策 URL—— 两个商店都要求(App 使用相机 + 通知)。
- iOSApp Privacy nutrition label(App Store Connect)与 AndroidData Safety表单——声明收集了什么(设备推送 token;App 除此之外只与用户自己的服务器通信)。
- 生产 APNs(App Store / TestFlight 构建):release 构建中 App 的
aps-environment必须是production,relay 必须发送到生产 APNs(而非 sandbox)。 - 演示实例 + 凭据供审核员使用——App 连接的是用户自己的服务器,因此审核需要一个可达的测试实例(App Store 2.1 / Play)。
- Guideline 4.2(最低功能要求)——WebView 包装类 App 可能被严格审查;请在审核备注中引用原生特性(推送、小组件、Control Center、QR 配对)。
- 签名/上传按上文 CI 章节执行(三个 iOS target;签名 Android AAB)。
十一、从文档到实现:关键文件索引
| 主题 | 文件 |
|---|---|
| 交接文档(本文主线) | packages/mobile/HANDOFF.md |
| 移动包自述(运行模型 + 命令 + 排错) | packages/mobile/README.md |
| Capacitor 配置 | packages/mobile/capacitor.config.ts |
| 构建脚本与工具链包装 | packages/mobile/package.json、scripts/with-mobile-env.mjs、scripts/prepare-web-assets.mjs |
| 设备部署与模拟器 | scripts/android-device.mjs、scripts/ios-sim.mjs、scripts/ios-sim-build.mjs、scripts/ios-sim-dev.mjs |
| 深链意图与导航 | apps/deepLinks.ts、apps/deepLinkNavigation.ts |
| QR 扫描与连接存储 | apps/mobileQrScan.ts、apps/mobileConnections.ts |
| 平板尺寸类布局 | lib/device.ts |
| iOS 原生配置 | Info.plist、PrivacyInfo.xcprivacy、AppDelegate.swift |
| Android 原生配置 | AndroidManifest.xml、build.gradle、variables.gradle |
整体来看,OpenChamber 移动端是一套以托管 Web UI 为核心、以 Capacitor 为壳、以原生插件与扩展补齐能力的典型混合应用工程:构建管线通过统一的环境包装器在不同机器间可复现,原生能力(QR、安全存储、深链、推送、组件)都对应着明确的源码实现,而发布环节则清晰地拆成了"仓库内已完成"与"发布时待办"两部分,为接手者提供了可直接执行的后续路线。
- AI Agent
- 人工智能
- 代码智能体
- 交互助手
【免费下载链接】openchamber
Agentic Development Environment based on OpenCode AI agent
相关推荐
OmniRoute Playground Studio 深度解析:统一 AI 测试空间、四 Tab 并行比较与源码级实现
OmniRoute Playground Studio 深度解析:统一 AI 测试空间、四 Tab 并行比较与源码级实现 Playground Studio 是
AI Agent人工智能代码智能体交互助手Kronos-Tokenizer-2k避坑指南:从安装到分词K线数据的四步完整路径
Kronos Tokenizer 2k避坑指南:从安装到分词K线数据的四步完整路径 第一次喂 K 线数据就卡住?最容易翻车的无非四处:依赖安装、数据格式、序列长
语言运行时标准库JIT编译编译器GeoLibre iOS 构建与发布完全指南:从 Tauri v2 移动端架构到 App Store 上架实战
GeoLibre iOS 构建与发布完全指南:从 Tauri v2 移动端架构到 App Store 上架实战 导读 本文以 docs/ios.md https
GIS数据可视化前端桌面应用后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考