
Cap Mobile iOS 开发指南Expo Router、EAS 构建与 OTA 更新全流程【免费下载链接】CapOpen source Loom alternative. Beautiful, shareable screen recordings.项目地址: https://gitcode.com/GitHub_Trending/cap1/CapCap Mobile 是开源屏幕录制项目 Cap 的 iPhone 客户端基于 Expo SDK 55 Expo Router 构建支持相机/麦克风录制、媒体导入、上传分享、评论与观看分析等功能。本文以 apps/mobile/README.md 为核心骨架结合仓库中的package.json、app.config.js、eas.json、store.config.json及scripts/下的自动化脚本系统讲解从本地开发、真机联调、EAS 一次性初始化到模拟器/内部/生产构建、App Store 提交以及 OTAOver-The-Air更新的完整实战流程读完即可独立跑通一条 iOS 移动端发布流水线。说明Cap Mobile 是 iPhone-only 的 Expo 应用原生工程由 Expo 本地生成或由 EAS 远程生成不会提交到 Git 仓库除特别注明外所有命令都在apps/mobile目录下执行。一、项目架构与技术栈在深入命令之前先理解这个客户端是如何被组织的这有助于解释后续各命令为什么这么设计。1.1 Expo 连续原生生成CNG仓库 apps/mobile/README.md 明确指出Cap Mobile 是一个使用Expo Router和Continuous Native Generation连续原生生成构建的 iOS Expo 应用原生工程由本地expo prebuild或 EAS 生成不进版本库。这一点在 apps/mobile/package.json 中可以得到印证——没有ios/目录的固定工程文件只有prebuild:ios脚本expo prebuild --platform ios --no-install。核心技术栈来自 apps/mobile/package.json技术版本用途expo~55.0.29运行时基础框架expo-router~55.0.18文件路由main为expo-router/entryreact-native0.83.10原生渲染引擎react19.2.0UI 框架expo-camera~55.0.22相机与麦克风录制expo-video~55.0.20原生播放expo-dev-client~55.0.38开发客户端expo-updates~55.0.27OTA 更新expo-secure-store~55.0.17账号密钥安全存储expo-apple-authentication~55.0.16Sign in with Appleshopify/flash-list2.0.2高性能视频列表effect^3.18.4类型安全的副作用管理业务层1.2 路由与功能模块Expo Router 的文件路由入口位于 apps/mobile/app/_layout.tsx 的根布局应用启动后先展示加载屏未登录时渲染SignInPanel登录面板已登录则进入 Stack 导航挂载(tabs)My Caps 列表、caps/[id]Cap 详情、analytics、organization-settings、loom-import等页面。根布局还通过AuthProvider与RecordingUploadProvider提供了全局的登录态与上传进度管理并在屏幕底部常驻RecordingUploadStatus显示上传状态。三个主 Tab 定义在 apps/mobile/app/(tabs)/_layout.tsx/_layout.tsx)indexMy Caps 个人库、upload隐藏路由作为录制/上传入口、account账户设置。个人库页面apps/mobile/app/(tabs)/index.tsx/index.tsx)使用FlashList渲染 Cap 卡片并支持文件夹、空间切换、分享、密码设置、保存到相册等操作。录制页 apps/mobile/app/record.tsx 聚合了CapRecorderView相机录制原生模块位于 apps/mobile/modules/cap-recorder与CapScreenRecorderView屏幕录制扩展位于 apps/mobile/modules/cap-screen-recorder并内置提词器Teleprompter。屏幕录制功能通过 App Group 与 Broadcast Extension 实现其配置见下文app.config.js中的cap-screen-recorder插件。1.3 两个原生自定义模块cap-recorderSwift 实现的相机录制模块含.podspec提供CapRecorderView及录制事件回调供record.tsx使用。cap-screen-recorder屏幕录制模块包含 Swift 源码、Broadcast Extension 的.plist/.entitlements与app.plugin.js配置插件用于 iPhone 屏幕录制注意当前 iPhone 端以相机录制为主屏幕录制为扩展能力。二、本地开发四条命令的完整脉络README 给出了四条本地开发命令它们的关系可以用一句话概括决定要不要启动 Web 后端与跑在模拟器还是真机这两个维度。2.1 命令矩阵与根级脚本命令后端目标设备用途bun run dev:mobile启动docker cap/webiOS 模拟器标准全栈开发bun run dev:mobile:physical启动真机 iPhone全栈 真机联调bun run dev不启动复用已运行后端模拟器仅移动端开发bun run dev:physical不启动真机真机 已有后端前两个命令定义在仓库根目录的 package.json 中dev:mobile会先docker:up拉起依赖容器、以trap保证退出时docker:stop随后通过 Turbo 同时运行cap/web与cap/mobile两个 workspacedev:mobile:physical额外设置CAP_MOBILE_DEVICEphysical让移动端脚本走真机分支。后两个命令来自 apps/mobile/package.json 的dev/dev:physical脚本二者都会先执行scripts/prepare-ios-development.mjs再根据CAP_MOBILE_DEVICE环境变量选择调用run-ios-simulator.mjs或run-ios-device.mjs// apps/mobile/package.json节选 dev: CAP_MOBILE_DISABLE_ASSOCIATED_DOMAINS1 CAP_MOBILE_BUILD_REACT_NATIVE_FROM_SOURCE1 sh -c node scripts/prepare-ios-development.mjs if [ \${CAP_MOBILE_DEVICE:-simulator}\ \physical\ ]; then node scripts/run-ios-device.mjs; else node scripts/run-ios-simulator.mjs; fi, dev:physical: CAP_MOBILE_DEVICEphysical bun run dev2.2 prepare-ios-development.mjs预构建与依赖安装scripts/prepare-ios-development.mjs 做两件事执行expo prebuild --platform ios --no-install生成或刷新原生 iOS 工程比较ios/Podfile.lock与ios/Pods/Manifest.lock只要存在差异、或包含React-Core-prebuilt/ReactNativeDependencies、或缺少ExpoAppleAuthentication就自动执行pod install --project-directoryios安装 CocoaPods 依赖。这样每次开发前都能自动保证原生工程与依赖是同步的。脚本支持CAP_MOBILE_DRY_RUN1干跑模式只打印命令不执行便于排查。2.3 run-ios-simulator.mjs模拟器选择与容错scripts/run-ios-simulator.mjs 通过xcrun simctl list devices available --json枚举可用 iPhone 模拟器选择顺序为IOS_SIMULATOR_UDID环境变量指定的设备IOS_SIMULATOR_DEVICE环境变量指定的名称已 Booted 的模拟器名称包含 Pro 的型号列表中的第一个可用设备。选定后会确保模拟器完成启动simctl bootbootstatus -b等待再执行expo run:ios --device udid。值得注意的是脚本的容错设计如果 Expo 启动过程中模拟器意外退出它会自动重新启动并重试一次。另外当CAP_MOBILE_DISABLE_ASSOCIATED_DOMAINS1且检测到工程中已有 Associated Domains 相关 entitlement 时会先执行一次expo prebuild --clean重新生成工程确保开发构建不携带生产关联域名。2.4 run-ios-device.mjs真机联调的网络自动发现真机调试最麻烦的是iPhone 访问 Mac 上的 API 与 Metro。仓库的解决方案在 scripts/run-ios-device.mjs 与 scripts/mobile-development-network.mjs 中优先使用CAP_MOBILE_DEVICE_API_URL如果显式指定否则通过findLanAddress()探测 Mac 的私网 IPv4 地址——按en0、en1、en2优先自动跳过awdl、bridge、docker、lo、tailscale、utun、vbox、vmnet等虚拟网卡找到后组合为http://LAN_IP:3000作为后端地址并通过环境变量注入EXPO_PUBLIC_CAP_WEB_URLapiBaseUrl、REACT_NATIVE_PACKAGER_HOSTNAMELAN_IP后者让 Metro 也走局域网地址端口可通过CAP_MOBILE_LOCAL_API_PORT覆盖默认 3000局域网 IP 可通过CAP_MOBILE_LAN_IP覆盖。如果既找不到局域网地址、也没有EXPO_PUBLIC_CAP_WEB_URL脚本会报错并提示请显式设置CAP_MOBILE_DEVICE_API_URL。三、一次性 EAS 初始化从本地跑通到云端构建需要把项目与 Expo 的 EASExpo Application Services项目关联起来。3.1 project:init 关联 EAS 项目需要拥有对cap-software-incExpo 组织或你自己的组织有权限的 Expo 账号执行bunx eas-cli21.0.2 project:init该命令会把应用关联到 EAS 项目并生成一个公开的项目 ID。这个 ID 会被写入 apps/mobile/app.config.jsconst projectId process.env.EXPO_PROJECT_ID ?? 616ebd7a-e876-4b21-82be-d626028042f6;3.2 项目 ID 的用处在 apps/mobile/app.config.js 中projectId 被用于两处updates: projectId ? { url: https://u.expo.dev/${projectId}, // expo-updates 的 OTA 更新端点 } : undefined, // ... extra: { apiBaseUrl: process.env.EXPO_PUBLIC_CAP_WEB_URL ?? https://cap.so, eas: projectId ? { projectId } : undefined, },updates.urlOTA 更新的服务端点指向该项目的 Expo Updates 服务extra.eas.projectId运行时含 expo-dev-client用于识别所属 EAS 项目。该项目 ID 是公开标识符README 特别强调它是 EAS Build 与 EAS Update 所必需的提交到仓库是安全的。3.3 后端地址与关联域名EXPO_PUBLIC_CAP_WEB_URL后端 API 基地址默认生产环境为https://cap.so。需要在 development / preview / production 三个 EAS 环境分别配置当某个 profile 需要指向非生产后端时例如预发布环境覆盖即可CAP_MOBILE_ASSOCIATED_DOMAINS逗号分隔的关联域名列表用于 Universal Links / Associated Domains仅在显式设置时才会写入 iOS 工程的associatedDomainsCAP_MOBILE_BUILD_REACT_NATIVE_FROM_SOURCE1从源码构建 React Native开发 profile 开启。3.4 其他关键配置速览apps/mobile/app.config.js 中还包含大量值得了解的配置项配置值/行为说明bundleIdentifierso.cap.mobileiOS Bundle IDappleTeamId47B7FCLL43发布团队 IDversion1.0.0应用版本OTA 更新按此隔离runtimeVersionpolicy: appVersion运行时版本跟随应用版本schemecap深链 schemeplatforms[ios]仅 iOS当前无 AndroidusesNonExemptEncryptionfalse声明无豁免出口加密限制usesAppleSignIntrue启用 Sign in with ApplesupportsTabletfalse仅手机不支持 iPaduserInterfaceStylelight浅色模式experiments.typedRoutestrue类型化路由编译期校验路由权限文案也已配置好相册读取Cap imports videos from Photos for upload.、相册写入Cap saves downloaded videos to Photos.、相机/麦克风Allow Cap to use your camera/microphone while recording videos.、Face IDAllow Cap to protect your account key.。字体资源NeueMontreal 三字重、启动屏apps/mobile/assets/splash-icon.png与图标apps/mobile/assets/icon.png同样在 config 中注册。3.5 iOS 签名凭据EAS 负责远程管理 iOS 签名凭据。首次真机preview或生产构建时EAS 会要求被授权的 Apple Developer 账号创建或选择分发证书Distribution Certificate、Provisioning Profile与App Store Connect API Key。也就是说签名凭据不需要也不应该出现在仓库中。四、三种构建 profile 与 App Store 提交apps/mobile/eas.json 定义了三种构建 profile对应的 npm script 与用途如下4.1 development模拟器开发客户端bun run build:development # 等价于 bunx eas-cli21.0.2 build --platform ios --profile developmentprofile 特性developmentClient: true开发客户端可连接 Metro、distribution: internal、simulator: true纯模拟器构建无需签名、channel 为development并在构建环境注入CAP_MOBILE_BUILD_REACT_NATIVE_FROM_SOURCE1。本地开发并不强制需要 EAS 构建——bun run dev配合本地expo run:ios即可。development 构建适用于需要完整原生依赖打包、或 CI 分发开发构建的场景。4.2 preview内部真机构建bun run build:previewprofile 特性developmentClient未开启、distribution: internal通过 TestFlight 或 Ad Hoc 分发给内部测试者、channel 为preview。这是首次需要签名凭据的构建类型EAS 会引导创建或选择证书与 profile。4.3 production生产构建与版本号管理bun run build:productionprofile 特性autoIncrement: true生产构建号由 EAS 自动管理并递增、credentialsSource: remote凭据由 EAS 远程托管、distribution: store面向 App Store 分发、channel 为production。eas.json中cli.appVersionSource: remote也表明应用版本号来源是 EAS 远程管理而不是仓库内的静态版本。4.4 提交到 App Store Connect构建通过发布验证后提交最新生产构建与store.config.json中的元数据bun run submit:production # 等价于 bunx eas-cli21.0.2 submit --platform ios --profile production --latest提交配置apps/mobile/eas.json 的submit.production包含appleTeamId: 47B7FCLL43、appName: Cap、bundleIdentifier: so.cap.mobile、companyName: Cap Software, Inc.、语言en-US、SKUcap-mobile-ios以及元数据路径./store.config.json。apps/mobile/store.config.json 提供了完整的商店文案应用名 Cap、副标题 Record, share, collaborate、分类PRODUCTIVITY与PHOTO_AND_VIDEO、关键词camera recorder、async video、video sharing、analytics 等并声明automaticRelease: false构建上传后手动发布。五、OTA 更新preview 先行production 兜底5.1 先发 preview 验证bun run update:preview -- --message Describe the update # 等价于 bunx eas-cli21.0.2 update --channel preview --environment preview --message ...将当前提交的 JavaScript 与静态资源更新发布到preview通道供内部测试者先验证。5.2 验证后发 productionbun run update:production -- --message Describe the update # 等价于 bunx eas-cli21.0.2 update --channel production --environment production --message ...5.3 更新隔离规则README 明确指出两条关键约束按通道隔离更新只影响对应 channel 的客户端preview 的验证结果不影响 production 用户按应用版本隔离OTA 更新不能跨越原生版本。当原生依赖或 Expo 配置变化时必须递增 apps/mobile/app.config.js 中的version并发布一个新的生产构建而不是推送一个不兼容的 OTA 更新。结合runtimeVersion: { policy: appVersion }的配置可以理解其机制expo-updates 以应用版本作为运行时版本标识因此版本不变时 JS 更新可以热推版本改变后旧的 OTA 更新包会自动失效必须走新的原生构建。六、从开发到上线的完整流水线综合 README 与仓库脚本一条完整的移动端发布流水线如下# 1. 本地全栈开发模拟器 bun run dev:mobile # 2. 真机联调自动发现 Mac 局域网地址 bun run dev:mobile:physical # 3. 一次性关联 EAS 项目首次 bunx eas-cli21.0.2 project:init # 4. 构建三种 profile bun run build:development # 模拟器开发客户端 bun run build:preview # 内部真机构建 bun run build:production # 生产构建构建号由 EAS 自动递增 # 5. OTA 更新先 preview 验证 bun run update:preview -- --message Describe the update bun run update:production -- --message Describe the update # 6. 提交 App Store bun run submit:production版本策略小结变更类型操作JS / 资源 / 业务逻辑改动bun run update:preview验证 →bun run update:production发布 OTA原生依赖 / Expo 配置 / 原生模块改动递增app.config.js中的version→bun run build:production→bun run submit:production七、上线质量保障仓库提供的实测依据虽然 README 未展开但仓库中的 apps/mobile/app-store-release.md 给出了 1.0 版本发布前的完整核验清单可作为版本发布章节的实践佐证基础验证Expo Doctor 全部 19 项检查通过Expo SDK 55 各包版本对齐TypeScript 校验通过移动端测试套件通过 34 个文件、214 个测试对应 apps/mobile/package.json 的typecheck与test脚本构建验证clean prebuild、CocoaPods install、生产 JS 导出、Xcode Release 模拟器构建全部通过构建产物能在 iPhone 17 Pro Max 模拟器上从内嵌生产 bundle 正常启动合规验证非豁免加密声明为 false、包含聚合隐私清单、无广告 SDK、不请求 App Tracking Transparency 权限、默认不启用 Associated Domains功能边界免费账号最多录制 5 分钟1.0 版本不在应用内售卖数字功能不提供外部 Stripe 结账现有 Cap Pro 订阅在其他平台购买的权益会在账户页被识别上线前核对命令在apps/mobile下执行bunx eas-cli21.0.2 project:info --non-interactive bunx eas-cli21.0.2 config --platform ios --profile production bunx expo-doctorlatest bun run typecheck bun run test bun run expo prebuild --platform ios --clean --no-install bunx eas-cli21.0.2 build --platform ios --profile production八、常见问题与排查建议Q1真机开发时 iPhone 连不上后端检查CAP_MOBILE_DEVICE_API_URL是否显式设置确认 Mac 与 iPhone 在同一局域网必要时用CAP_MOBILE_LAN_IP指定局域网 IP、用CAP_MOBILE_LOCAL_API_PORT指定端口默认 3000。网络发现逻辑见 scripts/mobile-development-network.mjs。Q2pod install一直不执行或依赖不同步开发前会自动比对ios/Podfile.lock与ios/Pods/Manifest.lock若提示依赖不一致可删除本地ios/目录后重新执行bun run dev会重新 prebuild或用bun run prebuild:ios手动触发。Q3OTA 更新发布后用户没收到先确认发布到的 channel 与客户端构建时的 channel 一致development / preview / production再确认没有跨版本发布——原生依赖变更后必须提升app.config.js的version并重新走生产构建。Q4找不到合适的模拟器run-ios-simulator.mjs支持用IOS_SIMULATOR_UDID或IOS_SIMULATOR_DEVICE指定目标设备否则按已启动 → 含 Pro → 第一个可用的顺序自动选择。Q5构建失败卡在签名preview 与 production 构建依赖 EAS 远程签名凭据需确认 Expo 账号有权限、Apple Developer 账号已完成证书创建授权本地模拟器开发构建development profile 且simulator: true不需要签名。结语Cap Mobile 用Expo Router CNG EAS expo-updates搭建了一条典型的现代 iOS 应用开发与发布流水线本地通过 scripts/ 下的脚本自动完成 prebuild、Pod 安装、模拟器选择与真机网络发现云端通过 apps/mobile/eas.json 的三种 profile 覆盖开发、内部测试与生产分发日常迭代用 channel 隔离的 OTA 更新热推 JS 与资源原生变更则回归构建 提交。文中所有命令与配置均可在仓库的 apps/mobile 目录下找到对应实现按本文流程即可从零跑通 Cap Mobile 的完整 iOS 发布闭环。【免费下载链接】CapOpen source Loom alternative. Beautiful, shareable screen recordings.项目地址: https://gitcode.com/GitHub_Trending/cap1/Cap创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考