📱

Expo bare workflowで環境分けてビルドする方法をchatGPTに教えてもらいながらやっと解決できた

2023/05/14に公開

ことの発端

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先生に色々と聞きながら解決できた。

流れ

  1. android/app/build.gradleを編集し、flavorオプションを追加する
  2. android/app/src配下に環境ごとのディレクトリを作成する
  3. gradlewコマンドをandroidディレクトリで実行し、アプリをビルドする
  4. abdコマンドを使ってエミュレーターにapkをインストールする
  5. トップディレクトリに戻り、expoのdevサーバーだけ立ち上げる
  6. エミュレーターからアプリを起動する

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

無事立ち上げったら、👇のような表示になる

expo-dev-server

ここで、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の画面が開く

モザイク多くてごめんなさい🙇🏻‍♂️
expo-go

毎回何個もコマンド実行するのはめんどくさいので、トップディレクトリにbin/start-devのshellスクリプトファイルを作りました。

bin/start-dev
#!/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