Rorkでアプリのプロトタイプは作れたものの、いざ本番化を考え始めると「このSDKを追加したい」「このネイティブ機能を呼びたい」という壁にぶつかる方は多いのではないでしょうか。Stripe Mobile SDKの完全機能を使いたい、特殊なBLEデバイスと通信したい、社内独自のSDKを統合したい — こうしたケースで登場するのがExpo Prebuildです。
RorkアプリとExpoの関係をもう一度確認する
まず前提を整理しておきます。Rorkが出力するのは、app.jsonとpackage.jsonを中心としたExpo Managed Workflowのプロジェクトです。ios/やandroid/のディレクトリは存在せず、ネイティブビルドはEAS(Expo Application Services)に丸投げできる構成になっています。
この設計は、最初の数週間で動くアプリを作るには明確に強力です。しかし「Expoのexpo-系ライブラリでカバーされていない機能を使いたい」「特定のSDKがManaged Workflowでは動かない」という状況になると、ネイティブコードを書く必要が出てきます。
そのときに選べる道は次の3つです。
- Config Plugin で済ませる: ネイティブ設定の追加だけで対応できるケース(権限文字列、Info.plist、AndroidManifest等)
- Prebuild + 既存ネイティブモジュールを追加: NPMで配布されているネイティブモジュールを統合する
- Prebuild + 自作ネイティブモジュールを追加: SwiftやKotlinでオリジナルの機能を実装する
どの道を選ぶかは、追加したい機能の性質によります。私の経験では、いきなりネイティブコードを書きに行くのではなく、まず「Config Pluginで足りないか」を確認するのが結果的に早道になります。
Prebuildに踏み切る前のチェックリスト
ネイティブコードに踏み込むと、後戻りはできなくはないものの、メンテナンスコストは確実に上がります。Prebuildする前に、以下を順番に確認することをおすすめします。
- 追加したい機能はExpoのfirst-partyライブラリ(
expo-camera、expo-notifications等)でカバーされていないか - Expo Modulesエコシステム上で配布されているサードパーティライブラリで足りないか
- やりたいことが「ネイティブ設定の変更」だけなら、Config Pluginを書くだけで済まないか
- 本当にネイティブコードに踏み込む必要があるか、それとも別のアーキテクチャ(WebView経由、サーバー側処理)で代替できないか
ここで「Yes、ネイティブが必要」となって初めてPrebuildの出番です。
Expo Prebuildの基本コマンド
Prebuildは、app.jsonの設定をもとにios/とandroid/のディレクトリを生成するコマンドです。Bare Workflowへの完全な移行ではなく、設定ファイルから毎回ネイティブプロジェクトを再生成する「CNG(Continuous Native Generation)」というアプローチを採用しています。
# 1. プロジェクトのバックアップ(重要)
git add . && git commit -m "Snapshot before prebuild"
# 2. 必要に応じてSDKバージョンを揃える
npx expo install --check
# 3. Prebuild実行(クリーンビルド推奨)
npx expo prebuild --clean
# 4. iOSの依存関係をインストール
cd ios && pod install && cd ..
# 5. ローカルで起動確認
npx expo run:ios # または npx expo run:android--cleanフラグは既存のios/とandroid/を削除してから再生成するため、ネイティブディレクトリに手動で加えた変更は消えます。これが落とし穴になりやすいので、後述する「ネイティブ変更の永続化」に従ってください。
ネイティブモジュールを追加する具体例
例として、react-native-mlkit-ocrのようなネイティブビルドが必要なライブラリを追加する流れを見てみます。
# 1. ライブラリをインストール
npx expo install react-native-mlkit-ocr
# 2. Prebuildを再実行(ネイティブ依存を反映)
npx expo prebuild --clean
# 3. iOS依存関係を再インストール
cd ios && pod install && cd ..
# 4. ビルド確認
npx expo run:iosポイントは、ライブラリ追加後に必ずprebuild --cleanを再実行することです。これを忘れると、Podfileにライブラリのエントリが追加されず、ビルド時に「Native module cannot be found」エラーに遭遇します。私も最初の頃、この一手間を省いて30分溶かしたことがあります。
ネイティブ変更を永続化する2つの方法
prebuild --cleanはネイティブディレクトリを毎回再生成するため、Info.plistに手で書き足した設定や、AppDelegate.swiftに追加したコードはすべて失われます。これを防ぐには2つのアプローチがあります。
アプローチ1: Config Pluginで宣言的に管理する
Expo Config Pluginは、app.jsonの設定からネイティブファイルを書き換える仕組みです。例えばInfo.plistにカメラ使用許可文を追加するなら、以下のようにプラグインを書きます。
// plugins/with-camera-usage.js
const { withInfoPlist } = require('@expo/config-plugins');
module.exports = function withCameraUsage(config) {
return withInfoPlist(config, (cfg) => {
cfg.modResults.NSCameraUsageDescription =
'名刺をスキャンするためにカメラを使用します';
return cfg;
});
};そしてapp.jsonに登録します。
{
"expo": {
"plugins": ["./plugins/with-camera-usage"]
}
}これでprebuild --cleanを何度実行しても、設定が再現されます。
アプローチ2: Prebuildを諦めてBare Workflowに完全移行する
ネイティブコードの変更が広範囲に及ぶ場合は、prebuildをやめてios/とandroid/をリポジトリにコミットし、Bare Workflowとして運用する選択肢もあります。ただしExpo SDKのバージョンアップ時にネイティブ側のマージ作業が発生するため、私はできる限りConfig Pluginで完結させる方針を取っています。
EAS Buildとの組み合わせ方
Prebuild後は、ローカルでビルドしてもよいのですが、EAS Buildを使うと環境差異を気にせずクラウドでビルドできます。eas.jsonは次のような構成が基本です。
{
"cli": { "version": ">= 5.0.0" },
"build": {
"development": {
"developmentClient": true,
"distribution": "internal"
},
"preview": {
"distribution": "internal",
"ios": { "simulator": true }
},
"production": {
"autoIncrement": true
}
}
}ビルドコマンドは次のとおりです。
# 開発用ビルド(実機で動作確認)
eas build --profile development --platform ios
# TestFlight配信用
eas build --profile production --platform ios --auto-submitEAS Buildはビルドのたびに自動でPrebuildを実行するため、ローカルではprebuildしなくてもCI上でネイティブプロジェクトが組み立てられます。ただし、ローカル開発でexpo run:iosを使いたい場合は、ローカルでも一度prebuildしておく必要があります。
つまずきやすいポイントと対処法
実際にPrebuildを使ってきて、よく遭遇する問題を3つ挙げます。
1. pod installがXcodeバージョン非互換でエラー
iOSのCocoaPodsは、Xcodeのバージョンとデプロイメントターゲットに敏感です。Podfileのplatform :ios, '15.1'のような行と、各ライブラリが要求するiOS最低バージョンが噛み合わないとエラーになります。EAS Buildでimage: latestを指定しておくと、Cloudのビルド環境では最新のXcodeが使われるため、ローカルとの差異を最小化できます。
2. prebuild後にexpo-routerが動かなくなる
Rork生成アプリはexpo-routerに強く依存していますが、Prebuild後にAppDelegateが書き換わると、初期化順序が変わって画面が真っ白になることがあります。これは@expo/config-pluginsが同梱するexpo-routerのプラグインが正しく適用されているかを確認することで解決します。app.jsonのplugins配列にexpo-routerが含まれているか必ずチェックしてください。
3. AndroidビルドでCould not find com.facebook.react:react-native
Androidでこのエラーが出るときは、android/build.gradleのallprojects.repositoriesにmaven { url 'https://www.jitpack.io' }が追加されていないケースが多いです。Config PluginのwithProjectBuildGradleで書き加えるか、ライブラリ側のドキュメントを再確認してください。
生成されたAppDelegateを読むだけで理解が一段深まる
私が個人的に習慣にしているのは、初めてPrebuildを実行したプロジェクトでは必ずios/{プロジェクト名}/AppDelegate.swiftを一度読んでみることです。最近のExpo Prebuildが生成するAppDelegateは比較的コンパクトで、ほとんどの処理をExpoAppDelegateに委譲しています。5分かけて目を通すだけで、次のことが一気にクリアになります。
- プッシュ通知のトークンがどう受け渡されるか
- URLハンドラがexpo-linkingや他のプラグインとどう協調しているか
- バックグラウンドフェッチのエントリーポイントで何が起きているか
ExpoReactNativeFactoryがブリッジをどう初期化しているか
後でプッシュ通知がJS層まで届かない、ディープリンクが想定の画面に飛ばないといった問題に直面したとき、すでに頭の中にマップができているとブレークポイントを置く場所の見当がつきます。このマップがないままネイティブ側のデバッグに踏み込むと、当てずっぽうの作業になりがちです。
Androidについても同じで、android/app/src/main/java/.../MainApplication.ktを一度読んでおくと、プロジェクト全体の見通しが大きく変わります。生成コードは魔法ではないので、一度目を通すだけで「不透明なブラックボックス」感が消えるはずです。
マシン間でPrebuildの結果を再現可能にする
協業を始めた瞬間、あるいはCIに移した瞬間に効いてくるのが、ローカルのXcode・Node・CocoaPods・Rubyのバージョン差異です。これらを揃えておくと、Prebuildの結果が安定します。
# .nvmrc
20.11.1
# .ruby-version
3.2.2
# Podfile(Expoが既に設定済みだが確認推奨)
platform :ios, podfile_properties['ios.deploymentTarget'] || '15.1'EAS Build側のXcodeバージョンはeas.jsonで固定します。
{
"build": {
"production": {
"ios": { "image": "latest" }
}
}
}これらが揃ってくると、「ローカルでは動くがCIで失敗する」という状況が確実に減ります。私の経験上、ここを最初に固めておくのが結果的にもっとも時間を節約してくれます。
より深く学ぶための参考資料
また、Rork × EAS の運用フローについては、Rork × EAS Build × GitHub Actions で完全自動化CI/CDパイプラインを構築するで実例とともに解説しているので、CI/CDまで踏み込みたい方はそちらも合わせてご覧ください。
ネイティブモジュール追加で個別のエラーに遭遇した場合は、Rork Max + EAS Build カスタムネイティブモジュール導入エラー完全解決ガイドに具体的なエラーパターンと対処法をまとめています。
全体を振り返ってに代えて — 次の一歩
Expo Prebuildは「Rorkで動くプロトタイプ」と「本番運用に耐えるネイティブアプリ」の間にある最も重要な橋渡しです。最初の一歩としておすすめするのは、いきなり大きなSDKを統合するのではなく、まず**expo prebuild --cleanを実行してネイティブディレクトリが生成されることを確認する**ことです。生成されたios/とandroid/を眺めるだけでも、ManagedとBareの違いが体感的に理解できます。
そこから先は、追加したい機能を1つずつConfig Pluginで管理する習慣をつけていけば、長期的にメンテナンス可能なRorkアプリの基盤が整います。プロトタイプから本番アプリへの最後の一押しに、本記事の内容が役立てば嬉しいです。