Open22

Expo: EAS Build

Takanori IshikawaTakanori Ishikawa

現時点での制限

まだプレビュー版のため、以下の制限がある (Limitations - Expo Documentation)

  • Expo SDK 41 以降の Managed Workflow のみ対応
  • CocoaPods はキャッシュされない
  • node_modules 以下もキャッシュされない
    • ただし、npm cache server がいるため、ダウンロードは早い(はず)[1]
    • yarn v1 だとデフォルトで無効になっている
  • ビルド時間は 60 分まで
脚注
  1. https://docs.expo.io/build-reference/caching/#javascript-dependencies ↩︎

Takanori IshikawaTakanori Ishikawa

新しいプロジェクトを作成

新規でプロジェクトを作成して試す

$ expo init --npm 

EAS を設定する

$ eas build:configure

ウィザード形式で進む

Which platforms would you like to configure for EAS Build? › All

Android の Application-ID と、iOS の Bundle Identifier を決める。使える文字が微妙に異なるので注意...

What would you like your Android application id to be? … com.example.eas_playground

What would you like your iOS bundle identifier to be? … com.example.eas-playground

最後に git commit してもらって終了

Takanori IshikawaTakanori Ishikawa

iOS シミュレータ向けにビルド

eas.json にシミュレータ用のプロファイルを追加

{
  "builds": {
    "android": {
      "release": {
        "workflow": "managed"
      }
    },
    "ios": {
      "release": {
        "workflow": "managed"
      },
      "simulator": {
        "workflow": "managed",
        "distribution": "simulator"
      }
    }
  }
}

eas コマンドでビルドする。

$ eas build --platform ios --profile simulator
✔ Created @my-org/eas-playground on Expo

Warning! Your git working tree is dirty.
This operation needs to be run on a clean working tree, please commit all your changes before proceeding.
✔ Commit changes to git? … yes
✔ Commit message: … Simulator profile
✔ Uploaded to EAS 3s

Build details: https://expo.io/accounts/...

Waiting for build to complete. You can press Ctrl+C to exit.
⠸ Build queued...

Expo.io を覗いてみると進行状況が出ている。

ビルドが完了すると .tag.gz をダウンロードでき、解凍した .app ファイルをシミュレータにドラッグ&ドロップするとインストールできる。

Takanori IshikawaTakanori Ishikawa

EAS build で iOS をビルドしていると、fastlane で以下のエラーに遭遇した。

❌  error: File /Users/expo/workingdir/build/ios/build/Build/Products/Release-iphonesimulator/myapp.app/main.jsbundle does not exist. This must be a bug with


❌ Metro encountered an error:
Error loading Metro config and Expo app config: Expected `fromDir` to be of type `string`, got `undefined`

Make sure your project is configured properly and your app.json / app.config.js is valid.
If you are using environment variables in app.config.js, verify that you have set them in your EAS Build profile configuration or secrets.
› Generating debug myapp » myapp.app.dSYM
⚠️  Pods/boost-for-react-native: iOS@8.0 deployment version mismatch, expected >= 9.0 <= 14.4.99
▸ ** BUILD FAILED **
▸ The following build commands failed:
▸ 	PhaseScriptExecution Bundle\ React\ Native\ code\ and\ images /Users/expo/workingdir/build/ios/build/Build/Intermediates.noindex/myapp.build/Release-iphonesimulator/myapp.build/Script-00DD1BFF1BD5951E006B06BC.sh
▸ (1 failure)
** BUILD FAILED **
The following build commands failed:
	PhaseScriptExecution Bundle\ React\ Native\ code\ and\ images /Users/expo/workingdir/build/ios/build/Build/Intermediates.noindex/myapp.build/Release-iphonesimulator/myapp.build/Script-00DD1BFF1BD5951E006B06BC.sh
(1 failure)
Exit status: 65

を参考に、プロジェクトのルートに index.js を配置することで解決した。

Takanori IshikawaTakanori Ishikawa

開発中のアプリでは、EAS build は通るものの、デバイスにインストールしたアプリは起動時にクラッシュしてしまった。新規に作ったアプリで、Android に "internal" distribution のプロファイルを追加してビルドしてみる。

{
  "builds": {
    "android": {
      "release": {
        "workflow": "managed"
      },
      "preview": {
        "distribution": "internal",
        "workflow": "managed",
        "buildType": "apk"
      }
...
}

ビルド

$ eas build --platform android --profile preview

ビルドが完了すると、コンソールに QR コードが表示されるので、Android の標準カメラ > モード > レンズで読み取る。

何も問題なく動いた。

Takanori IshikawaTakanori Ishikawa

別のアプリで試したところ問題なく動いたが、画像リソースの一部が抜けてしまう...

hakemalfoyhakemalfoy

とても参考になる投稿をありがとうございます。
私も現在eas builを試しています。
ちょうどiosのeas buildしたアプリでローカルの画像が表示されないバグに直面しているのですが、もし解決していましたらご教示願いたいです。

Takanori IshikawaTakanori Ishikawa

残念ながらまだ未解決です。今はこのへんガンガン手が入ってそうですし、Expo の Issues をときどき眺めながら気長に待つつもりです。(現状 build:ios/android でも大変満足しています)

hakemalfoyhakemalfoy

返信ありがとうございます。
調査を進めたところ、私の場合はeas buildの問題ではなく、expoをejectした際にmetro.config.jsが書き換わらなかったことに問題があったようです。以下を参考にmetro.config.jsを修正して表示されるようになりましたので一応共有させていただきます。ありがとうございました。

https://forums.expo.dev/t/assets-missing-only-in-ios-release-build-after-ejecting/42759/2

Takanori IshikawaTakanori Ishikawa

わざわざありがとうございます!
eject はしていないので別問題っぽいですね。なんにせよ解決したようで何よりです。

Takanori IshikawaTakanori Ishikawa

Expo SDK 41-42

"eject" せずにネイティブコードを扱えるようになる?

Takanori IshikawaTakanori Ishikawa

Expo managed workflow in 2021. Part 1: The preset Expo runtime | by Brent Vatne | Exposition

  • Managed workflow のランタイムは Expo Go に含まれている
  • build:iosbuild:android で使われるビルドツールは "Turtle" と呼ばれている
    • あらかじめビルドされた "shell" アプリにランタイムとアプリのパッケージを含めてビルドするから
    • ビルドコマンドが実行されると、JavaScript バンドル、manifest ファイル、アセットがアップロードされる
    • Turtle は新しいワーカーを走らせ、アップロードされたファイルをダウンロードする
    • ダウンロードした JavaScript ファイルとアセットを、ランタイムを含んだ "shell" アプリにコピーする
    • 最後にユーザーの証明書で署名する
  • Managed workflow で作られたアプリは OTA で安全に更新できる
    • なぜなら、中身はただの JavaScript ファイルなので、新しいバンドルをダウンロードしてきて入れ替えるだけ。
  • しかし、この方式にはいくつかの制限がある
  • 特に多い要望である以下のことができない
    • Expo SDK に含まれないネイティブライブラリを利用したい
    • 使われていないライブラリを含めないことでサイズ削減したい
    • オリジナルのネイティブコードを含めたい
  • これらを実現するには、ランタイムをカスタマイズ可能にしなくてはいけない
  • パート2へ続く
Takanori IshikawaTakanori Ishikawa

Expo managed workflow in 2021. Part 2: Customizing the runtime | by Brent Vatne | Exposition

  • ランタイムをカスタマイズするためには、これまで expo eject して Bare workflow に移行するか、最初から Bare workflow で初期化する必要があった。
  • Managed workflow でランタイムをカスタマイズできるようにすれば、Managed workflow を諦めずにネイティブコードの追加・削除ができる
  • スタンドアロンアプリ
    • あらゆるネイティブコードをビルドするためのクラウドサービスが必要だったので、EAS build を作った
    • eas build を実行すると、リポジトリのコードを clone してアップロードする
    • EAS build は新しい VM を起動し、ダウンロードしたコードを fastlane または Gradle でビルドする
    • 最後にユーザーの証明書で署名する
  • eject に似たコマンドとして prebuild を用意した。これは Manged workflow のプロジェクトからネイティブの iOS/Android プロジェクトを生成する。
    • EAS build は prebuild で生成されたプロジェクトをビルドする。"shell" アプリは必要ない
  • prebuild コマンドは不要なライブラリをリンクしないので、アプリのサイズ削減になる。
  • ネイティブライブラリの追加
    • リンクだけであれば、React Native が自動でやってくれる
    • なんらかのセットアップが必要な場合、Expo ライブラリのみ EAS build が自動でやってくれる
    • 開発者は Config plugin によって、prebuild プロセス中にセットアップできる
  • これで、EAS build でビルドされたアプリではランタイムをカスタマイズできるようになった。
    • SDK 41 ではここまで
    • Expo Go による開発時には利用できない
  • OTA アップデート
    • ランタイムに互換性がなければどうするのか。新しい問題
    • EAS Update というサービスで解決しようとしている
  • 開発時
    • 開発時にランタイムをカスタマイズできるようにするために "Expo Development Client" を用意した。
      • Expo Go と同じ使い勝手を提供する React Native のライブラリ
      • デバッグビルド時には Development Client を使うことができる。リリース時にはこれらのコードは含まれない。
      • Development Client を一度ビルドしてしまえば、あとは JavaScript コードに集中できる。
    • Development Client は ad-hoc provisioning で配布でき、ブラウザ経由でインストール可能

Takanori IshikawaTakanori Ishikawa

Expo の Development Client を試す

$ expo init my-expo-dev-client --npm 
$ cd my-expo-dev-client 
$ npm i expo-dev-client

より分かりやすいエラー表示のために App.tsx に import "expo-dev-client" を追加

import "expo-dev-client";
...

EAS の設定

Development Client で開発するときは EAS Build を使うのが推奨みたいなので設定をする。

まずは EAS CLI のインストール

$ npm install -g eas-cli

eas.json はサンプルのものをそのまま使う。

{
  "build": {
    "development": {
      "developmentClient": true,
      "distribution": "internal"
    },
    "development-simulator": {
      "developmentClient": true,
      "ios": {
        "simulator": true
      }
    },
    "production": {}
  }
}

この後、iOS デバイスでテストするためには ad-hoc provisioning を使うので Developer アカウントが必要。また、EAS を使うためには Expo の有料会員である必要がある。

Android 端末で試すのが一番簡単。Application ID だけ聞かれるので適当に決める。

$ eas build --profile development --platform android

あとは EAS 上でビルドが実行される。ローカルでビルドすることもできるが、Xcode や Android Studio が必要。

ビルドが完了するとターミナル上に QR コードが表示される。QR コードを Andorid 端末で読み取る。Expo のページが表示されるので「インストール」をクリックしてインストールする。

これで、開発用の端末に Development Client がインストールできた。これは従来の Expo Go に相当するものなので、このあとはローカルで Metro サーバを起動して実際のアプリを動かす。

$ expo start --dev-client 

あとはこれまでと同じ。QR コードを読み取ればアプリが起動する。

ネイティブコードに変更がない限り、Development Client のビルドは必要ないので、あとは開発端末上でホットリロードしながら開発を進められる(シミュレータを使いたい場合はローカルでビルドが必要になるが...)

Takanori IshikawaTakanori Ishikawa

やっと、今のプロジェクトを EAS build に移行しつつある。普通に動いてるっぽい。