React Native 项目
在远程 Mac 上打包 iOS
React Native 和 Expo 的 JavaScript 部分在哪里都能写,但 iOS 原生工程的依赖安装、编译和签名必须在 macOS 上完成。这篇说明在远程 Mac 上处理 bare 工作流与 Expo prebuild 项目的步骤,包括 CocoaPods、Xcode 签名设置、命令行 Archive,以及几类常见报错的排查思路。
在远程 Mac 上准备环境
React Native 的 iOS 构建涉及四套工具:Node(Metro 打包 JS)、Ruby 与 CocoaPods(安装原生依赖)、Xcode(编译和签名)、Watchman(可选,用于文件监听)。在一台全新的远程 Mac 上可以这样准备:
xcode-select --install
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
sudo xcodebuild -license accept
brew install node watchman
cd your-app && npm ci新建的 React Native 项目通常带一个 Gemfile,用来锁定 CocoaPods 版本。推荐用 Bundler 安装并执行 bundle exec pod install,这样 Mac 上的 CocoaPods 版本与团队一致。Ruby 可以用系统自带的,也可以用 rbenv 等工具单独安装,避免改动系统 Ruby。
代码同步建议用 Git:Windows 或 Linux 上开发、提交,远程 Mac 上拉取后安装依赖。不要把 Windows 上的 node_modules 直接拷过去,其中部分包带有按平台编译的二进制文件,必须在 Mac 上重新安装。日常调试 Debug 包时,Metro 和模拟器都运行在远程 Mac 上,通过屏幕共享查看模拟器画面,修改代码后在 Mac 上拉取即可触发刷新。
Expo 项目:先 prebuild 再构建
Expo 托管工作流的项目里没有 ios/ 目录。要在自己的 Mac 上构建,先用 prebuild 根据 app.json / app.config.js 和配置插件生成原生工程:
npx expo prebuild --platform ios
# 本地构建并在模拟器运行
npx expo run:ios
# 构建 Release 配置
npx expo run:ios --configuration Releaseprebuild 会运行 pod install。如果改了原生相关的配置(例如权限描述、插件),重新执行 prebuild 即可;需要完全重来时加 --clean,它会删除并重建 ios/,手工改过的原生代码会丢失。
如果不想维护自己的构建机,Expo 的 EAS Build 是官方的云构建方案,计费和额度以 Expo 官网为准。
CocoaPods:安装与更新
bare 工作流或 prebuild 之后,在 ios/ 目录安装依赖:
cd ios
bundle install
bundle exec pod install
# 新增或升级了原生库、本地 spec 仓库过旧时
bundle exec pod install --repo-update安装完成后打开的是 ios/YourApp.xcworkspace,不是 .xcodeproj,否则会报找不到 Pod 模块。Podfile.lock 应提交到仓库,保证每台机器解析出同样的版本。
Xcode 签名设置与命令行 Archive
第一次构建建议在屏幕共享里用 Xcode 打开 workspace,在 Target → Signing & Capabilities 中选择开发团队、确认 Bundle Identifier,勾选 Automatically manage signing 或手动指定描述文件。调通之后,后续构建都可以在 SSH 里用命令行完成:
xcodebuild -workspace ios/YourApp.xcworkspace \
-scheme YourApp -configuration Release \
-destination 'generic/platform=iOS' \
-archivePath build/YourApp.xcarchive archive
xcodebuild -exportArchive \
-archivePath build/YourApp.xcarchive \
-exportOptionsPlist ExportOptions.plist \
-exportPath build/ipaExportOptions.plist 里的 method 决定导出用途(上架或内部分发),可以先在 Xcode Organizer 手动导出一次,导出目录里会附带一份可直接复用的 plist。Release 构建会把 JS 打包进 App,不依赖 Metro。
几类常见报错
- 构建阶段找不到 node:Xcode 的构建脚本不会读取你的 shell 配置。新版 React Native 在
ios/.xcode.env里设置NODE_BINARY,可以在不提交的ios/.xcode.env.local中写入export NODE_BINARY=$(command -v node)。 - No bundle URL present:Debug 包启动时连不上 Metro。确认
npx react-native start或npx expo start正在 Mac 上运行,模拟器和 Metro 在同一台机器上。 - Sandbox: rsync deny file-write:较新的 Xcode 默认开启 User Script Sandboxing,部分旧版本库的构建脚本不兼容。升级相关库是首选;临时方案是在 Build Settings 中把
ENABLE_USER_SCRIPT_SANDBOXING设为 No。 - pod install 版本冲突:先
--repo-update;仍失败时删除ios/Pods和 DerivedData(~/Library/Developer/Xcode/DerivedData)后重装。 - No signing certificate / profile 不匹配:检查 Bundle Identifier 与描述文件是否一致,证书是否在当前用户的钥匙串里。团队协作时建议用 fastlane match 统一管理。
构建稳定之后,可以把这台 Mac 注册成 CI runner,推送即出包,见 iOS 构建机配置指南。
常见问题
Expo 项目一定要 Mac 才能出 iOS 包吗?
不一定。Expo 提供 EAS Build 云构建服务,不需要自己的 Mac。若想在自己的机器上构建、调试原生模块或控制 Xcode 版本,就要先 expo prebuild 生成 ios 目录,再在 Mac 上用 Xcode 或 xcodebuild 构建。两种方式可以并存。
ios 目录要不要提交到 Git?
bare 工作流需要提交,因为原生代码是你维护的。使用 Expo 持续原生生成(CNG)的项目通常把 ios 目录加入 .gitignore,每次通过 expo prebuild 重新生成,原生改动写进配置插件。两种方式选一种,不要混用。
Mac 上和 Windows 上的 Node 版本不一样会有问题吗?
可能会。lockfile、原生依赖的安装脚本和 Metro 的行为都与 Node 版本有关。建议在项目里用 .nvmrc 或 package.json 的 engines 字段声明版本,Mac 上用 nvm、fnm 等工具切换到相同版本。
扫码加微信客服手机上长按二维码识别