Expo bare workflowで環境分けてビルドする方法をchatGPTに教えてもらいながらやっと解決できた
ことの発端
expo使ってreact nativeアプリを作っていて、認証に@react-native-firebaseを使っているが、テスト環境とプロダクション環境での認証認可をfirebaseで別々のプロジェクトにしたかった、@react-native-firebaseはgoogle認証にandroidのnative機能を使ってgoogle認証を行ったあとにfirebaseと連携する流れらしく、google-service.jsonファイルをreact nativeのandroidディレクトリ配下に置かないといけないとのこと
ただし、firebaseのプロジェクトごとにgoole-service.jsonが必要とするため、それぞれの環境でgoogle-service.jsonを分けたかった。
問題
gradleのflavorを使ってみたものの、どうも expo-cli との相性が悪く、devサーバーがコマンド一つで起動できなかった。
解決策をChatGPTに聞く
nativeアプリ開発の経験がなく、仕組みを理解するには時間がかかり、半月もかかってしまったが、やっとchatGPT先生に色々と聞きながら解決できた。
流れ
- android/app/build.gradleを編集し、flavorオプションを追加する
- android/app/src配下に環境ごとのディレクトリを作成する
gradlew
コマンドをandroidディレクトリで実行し、アプリをビルドするabd
コマンドを使ってエミュレーターにapkをインストールする- トップディレクトリに戻り、expoのdevサーバーだけ立ち上げる
- エミュレーターからアプリを起動する
android/app/build.gradleを編集し、flavorオプションを追加する
flavorの設定を加えていく
// 省略
applicationVariants.all { variant ->
// 省略
def flavor = variant.flavorName
variant.resValue "string", "google_json", "\"${flavor}/google-services.json\""
}
// 省略
flavorDimensions 'env'
productFlavors {
development {
dimension 'env'
applicationId 'jp.myapp.dev' // 👈 ここはよしなりに編集して下さい
}
preview {
dimension 'env'
applicationId 'jp.myapp.preview' // 👈 ここはよしなりに編集して下さい
}
production {
dimension 'env'
applicationId 'jp.myapp' // 👈 ここはよしなりに編集して下さい
}
}
android/app/src配下に環境ごとのディレクトリを作成する
今回はdevelopment,preview,productionで作ったので
android
|- src
|-development
| |- google-service.json
|-preview
| |- google-service.json
|-production
| |- google-service.json
gradlew
コマンドをandroidディレクトリで実行し、アプリをビルドする
以下👇のコマンドを実行する
./gradlew assembleDevelopmentDebug
./gradlew assemble<flavor name>Debug のように,<flavor name>のところに立ち上げたい環境をパスカルケースで置き換えれば大丈夫
abd
コマンドを使ってエミュレーターにapkをインストールする
今回はdevelopment実行したので、app/build/outputs/apk/development/debug/app-development-debug.apk
をインストールします。
adb install app/build/outputs/apk/development/debug/app-development-debug.apk
成功したら、エミュレーターにアプリがインストールされているはず。
トップディレクトリに戻り、expoのdevサーバーだけ立ち上げる
トップディレクトリで👇を実行します
yarn expo start --dev-client
expo-cliをグローバルにインストールされている場合はyarnコマンド不要なので👇で大丈夫。
expo start --dev-client
無事立ち上げったら、👇のような表示になる
ここで、aを押してandroidエミュレーターを起動しようとしたら👇のようなエラーで動かない。
Started Metro Bundler
› Opening on Android...
› Opening exp+myapp://expo-development-client/?url=http%3A%2F%2F10.18.172.185%3A8081 on Pixel_4_API_31
Couldn't start project on Android: Error running adb: The development client (jp.myapp) for this project is not installed. Please build and install the client on the device first.
Learn more: https://docs.expo.dev/clients/distribution-for-android/
原因ははっきりわからないが、expoが内部で最初にbuild.gradleを編集して定義した、flavorのappIdを動的に認識できてないと思われる。
expoのオプションで指定できるのかなと思って探してみたが、そのようなオプションは無さそう。
エミュレーターからアプリを起動する
でも、devサーバーが立ち上がっているので、エミュレーターからアプリを起動すると👇のようなexpo goの画面が開く
モザイク多くてごめんなさい🙇🏻♂️
毎回何個もコマンド実行するのはめんどくさいので、トップディレクトリにbin/start-dev
のshellスクリプトファイルを作りました。
#!/bin/bash
export APP_ENV=development
cd android && \
./gradlew assembleDevelopmentDebug && \
adb install app/build/outputs/apk/development/debug/app-development-debug.apk
yarn expo start --dev-client
その他
@react-native-firebase を使っている場合はjsの方で初期化する必要があり、👇のように環境ごとにfirebaseのwebclientIdが変わるようにしておく必要がある
import Constants from 'expo-constants';
import { GoogleSignin } from '@react-native-google-signin/google-signin';
GoogleSignin.configure({
webClientId: Constants.expoConfig.extra.GOOGLE_OAUTH_CLIENT_ID,
scopes: [
'https://www.googleapis.com/auth/user.gender.read',
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
],
});
GOOGLE_OAUTH_CLIENT_ID
はexpoのapp.config.jsの方で定義している、app.config.jsの実行時はnodeJSの環境なので、dotenvが使える、ディレクトリ配下に環境ごとの.envファイルを作り、読み込ませている。
export default {
// 省略
extra: {
GOOGLE_OAUTH_CLIENT_ID,
},
}
結構苦労したので、誰かの役に立てたら嬉しい。
Discussion