実践EAS Update 調査から方針を決めるまで
updateコマンドではブランチを指定
eas update --branch [branch] --message [message]
ブランチを見てみる(productionをeas channel:create productionで作っておいた)
eas branch:list
Channel:
Name production
ID hoge
Branches pointed at this channel and their most recent update group:
チャネルを見てみる(productionを作っておいた)
eas channel:list
Branches:
Branch production
Platforms N/A
Runtime Version N/A
Message N/A
Group ID N/A
ステージングのchannelとbranchも作る
eas channel:create staging
Channel:
Name staging
ID foo
Branches pointed at this channel and their most recent update group:
No branches are pointed to this channel.
———
Channel:
Name production
ID hoge
Branches pointed at this channel and their most recent update group:
ブランチも作られた
Branches:
Branch staging
Platforms N/A
Runtime Version N/A
Message N/A
Group ID N/A
———
Branch production
Platforms N/A
Runtime Version N/A
Message N/A
Group ID N/A
ステージングブランチにupdateしてみる
eas update --branch staging
{
"updates": {
"url": "https://u.expo.dev/bar"
}
}
Cannot automatically write to dynamic config at: app.config.ts
Error: update command failed.
と出た(barにはexpo のプロジェクトIDが入る)のでapp.jsonに追記した
もう一度updateすると
Provide an update message とメッセージの入力が求められる。
デフォルトは最終コミットメッセージ
updateは数分で終わった。
Channel: staging pointed at branch: staging
みたいなログも出るので、channelとbranchを確認できる。
expo.devにのUpdatesにも表示された。
stagingのアプリになぜか反映されないなと思ったら、eas.jsonでchannelとして指定していたつもりが、expoでのreleaseChannelのままだった。
この場合(channelが未指定の場合)、channelは未設定になるっぽい(expo.devのBuildsでReleaseChannel: all、Channelで調べても何も出てこなかった)
eas.jsonの各profileにchannelを追加しreleaseChannelを削除
今までreleaseChannelの値で制御指定していたものを、環境変数のAPP_VARIANTで制御するように変更
build時はeas.jsonのenvからAPP_VARIANTを取得し、update時は
APP_VARIANT="prod" eas update --branch production
のように指定することで取得できるようにする
channelは
import * as Updates from 'expo-updates';
Updates.channel
で取得可能だが、app.config.jsonでは起動前だから上記のexpo-updatesを使った取得はできなさそう?(ドキュメントにもapp.config.jsonではexpo-updatesから取得していない)
また、app.config.jsonのexpo.extraにも変数を埋め込むことが可能
export default () => ({
expo: {
extra: {
API_URL: process.env.API_URL || null,
},
// ...
},
});
これはexpo-constantsで
Constants.expoConfig.extra.API_URL
で取得可能
expo-updatesでも
Updates.manifest?.extra?.expoClient?.extra?.eas?.API_URL
で取得できるが、dev環境、もしくはUpdataがないとUpdates.manifestがundefinedなので微妙
横道に逸れまくったが、
build時: eas.jsonのenvからAPP_VARIANTを取得
update時: コマンドの環境変数指定からAPP_VARIANTを取得
が良さそう
APP_VARIANT="stg" eas update --branch staging
で無事stagingのアプリにUpdateが反映された
APP_VARIANTとブランチの対応関係を間違えると悲惨(APIエンドポイントに開発環境を指定したものをユーザーにデリバリーしてしまったり)なので、package.jsonのscriptsにエイリアスを書いておく。
"eas-update-dev": "APP_VARIANT=stg eas update --branch staging",
"eas-update-prod": "APP_VARIANT=prod eas update --branch production",
例えば
"APP_VARIANT=prod eas update --branch production-preview"
でupdateして、それをproductionにつなげれば、かなり本番に近いテストができて安全…?
いやだめか。
productionチャネル がproduction-previewブランチを向いていると、次に試したいバージョンをproduction-previewブランチに上げてしまったらproductionが読み取ってしまう。
なので、どんどんブランチは繰り上げていかないといけないのか。
前のバージョンに戻してみる
まずはstagingブランチの状態を確認
eas branch:view staging
Branch:
Name staging
ID hoge
Recent update groups:
Platforms android, ios
Runtime Version 1.0.0
Message "add ? to runtimeVersion in mypage drawer menu" (4 minutes ago by n_harada)
Code Signing Key N/A
Is Roll Back to Embedded No
Group ID foo
———
Platforms android, ios
Runtime Version 1.0.0
Message "comment out eas.json ios build env macos-monterey-12.6-xcode-14.0 staging" (2 hours ago by n_harada)
Code Signing Key N/A
Is Roll Back to Embedded No
Group ID bar
eas update:republish --group bar
注) barは、上記のGroup ID(実際はuuid)
Update成功!…と思いきやログアウトされてしまった。
調べてみたら、API_HOSTが開発環境に変わってしまっている。
が、それはロールバック先のUpdateでのAPI_HOSTが開発環境のものだったから。ということで成功。
republishの際は環境変数指定はいらないっぽい。前にpublishしたupdateをそのまま反映させるなら当然だけど。
ロールバック簡単で助かる。クラシックupdateのときはロールバックが無限ループしてしまっていたから。
eas update:republish --branch staging
みたいなロールバックの仕方もあるらしいけど、ロールバック先のcommitを指定できない分、GroupID指定と比べると完全に下位互換な気がするけどどうなんだろう
と思ってやってみたら、過去のupdateの履歴が出てきた。選択できた。
どっちでもいいな。
手数はブランチ指定の方が少ないからブランチ指定するか。
ロールバックする時のことも考えてcommitメッセージ書かねば。
--autoオプションを指定
eas update --auto
すると、
- gitのcommitのブランチと同名のブランチ名
- メッセージは最終commitのメッセージ
でupdateがpublishされる
eas update --branch staging --auto
とすれば、ブランチ名はstagingで、メッセージのみ自動化され、は最終commitのメッセージが指定される。
--autoをつけることでinteractiveでなくなるので、CI/CD環境ではこれを使う
このあとやること
-
ブランチ戦略他も試してみる
Branch promotion flow: https://docs.expo.dev/eas-update/deployment-patterns/#branch-promotion-flow -
runtimeVersion変えてみる
=> ドキュメント通りupdate走らなかった -
gitのmainブランチへのマージでプレビュー(https://docs.expo.dev/eas-update/github-actions/#publish-previews-on-pull-requests)
-
pushで更新(https://docs.expo.dev/eas-update/github-actions/#publish-updates-on-push)
-
productionのpreview環境作る
あとは、今developでもmianと同じくbuild, submitまでおこなっているから、それはなしにしよう
mainでsubmitまで行なって、同時にupdateまでpublishすることにすると、storeからインストールしたあとには必ずupdateが走る?submitしたものとupdateしたものが同じだからupdateは走らない?
runtimeVersionが変わった時だけbuild + submitして、変わらなかったらupdateだけにしたい
いや変わらなくてもupdateタグがついてたらupdateするようにしたい(リファクタリングでupdateしたくないのと、タグをつけることで、runtimeVersionを変え忘れを防げそう)
GitHubActionsでの自動Submit, Update案
-
submit時
commitにeas-submit-v1.0.0みたいなruntimeVersionを入れたタグをつける -
update時
commitにeas-update-v1.0.0.3みたいなruntimeVersion + update用のバージョンを入れたタグをつける -
version1.0.0(パッチ番号まで)ないしversion1.0.0(パッチより下位が0)ならsubmit
-
version1.0.0.1(パッチより下位が1以上)ならupdate
とかもありかな。ちょっと明示的じゃなくて良くないかな。
runtimeVersionの更新し忘れ時にはupdate走らせたくない
今は互換性ないのにruntimeVersionを同じにしてしまってアップデートが走るとクラッシュする
runtimeVersionの更新方法のポリシー
runtimeVersionのポリシーはappVersionにしよう
これは、プロジェクトのバージョン番号を元にランタイムバージョンが自動的に設定されるポリシー。
ネイティブのビルド番号(iOSのbuildNumber、AndroidのversionCode)は関係ない。
弊アプリでは
- ネイティブコードに変更があったとき(submit時)のみプロジェクトのバージョン番号をインクリメント
- ネイティブコードに変更はないが、submit後に修正を加えてsubmitしたいときにネイティブのビルド番号をインクリメント
なのでちょうどいい。
なので、
ネイティブコードに変更 => プロジェクトのバージョン番号をインクリメント
の既存の流れだけで済む。
「ネイティブコードに変更があったけどプロジェクトのバージョン番号が変更されていない」は検出不可能だと思われるので、updateのタグをつけた時だけupdateを走らせることにする
デバッグ用に、commitにつけたタグもランタイム時に隠しコマンドで見られるようにしたいな
EASのbuildの制限くると嫌だから来月やろう
ブランチ戦略について
チャネルとブランチの対応関係を変更するには、
eas channel:edit production --branch version-2.0
のように、チャネルを特定のブランチに紐付けさせる(https://docs.expo.dev/eas-update/how-eas-update-works/#matching-updates-and-builds)
チャネルはユーザーの手元のアプリでは固定だから当然と言えば当然
なので、
stagingチャネルで新しいコード(v2ブランチ)を試し、
productionチャネルをv2ブランチに向ける
みたいな戦略がある。
https://zenn.dev/link/comments/4b6df53ebe3c03 と同じ話で、
- stagingチャネルでv1.0ブランチを試す
- v1.0に問題ないことを確認
- prodチャネルをv1.0に向ける
- stagingチャネルでv1.1ブランチを試す
- v1.1に問題ないことを確認
- prodチャネルをv1.1に向ける
以下同様に続く
って感じか。どんどんブランチを繰り上げていく。
上記は前提としてruntimeVersionが同じ
もしruntimeVersioinがv2.0から変わるのであれば、
- prodチャネルとstagingチャネルでv2.0でビルドし直し
- stagingチャネルでv2.1を試す
- v2.1に問題ないことを確認
- prodチャネルをv2.1に向ける
以下同様
って感じか
メリット
- このフローは他のフローよりも安全である。
更新は内部テスターに配布されるテストビルドでテストされるため、本番ビルドにデプロイされるアーティファクトはテストされた正確なものである。 - GitHubブランチとEASアップデートブランチの間に直接的なマッピングを作成し、GitHubのコミットとEASアップデートの間にもマッピングを作成する。
- GitHubブランチを追跡している場合、EASアップデートブランチを各GitHubブランチに作成し、それらのブランチをビルドのチャネルにリンクできる。
- デプロイの以前のバージョンは常にGitHubに保存され、プロジェクトの以前のバージョンに簡単に戻ることができる
デメリット
- 1つの本番ランタイムバージョンにつき1つのチャネルが必要
- ランタイムバージョンポリシーの使用が困難になる。runtimeVersionが必然的にカスタムに。
- ブランチ名のブックキーピングが必要
- チームとのコミュニケーションで現在のテストビルドと本番ビルドにポイントされているブランチを伝える必要がある。
ここまでやるの結構めんどそうなので、production-previewみたいな、ブランチ名だけ異なるほぼproductionのステージング環境作って、そこで試したコードはproduction反映、とかでもいい気がする。
それがこれっぽい。
デメリットは以下として挙げられてる
- アプリの以前のバージョンのチェックアウトは、古いブランチではなく古いコミットをチェックアウトする必要があるため、少し複雑です。
- productionにマージすると、stagingチャネルのビルドからproductionチャネルのビルドに移動する代わりに、更新が再ビルドされて再公開されます。
一つ目がどう複雑なのかわかってない。eas update:republishがめっちゃ簡単だったので。
二つ目はまぁ再ビルドされるよね、って感じ。そこに不確実性が紛れ込むのはあり得る。
このproduction-previewを取り入れるのであれば、staging環境(stagingのDB、APIサーバー)と繋げるstagingブランチいらない気もするな?
mainブランチへのPR作成時にproduction-previewをbuild、ないしupdateするのが良いなぁ
弊アプリのEAS Update方針まとめ
ランタイムバージョン
- runtimeVersionポリシーはappVersionで、アプリのバージョン番号と常に一致
ブランチ戦略
- チャネルとブランチが一対一対応のupdate戦略(https://docs.expo.dev/eas-update/deployment-patterns/#persistent-staging-flow)をとる。ブランチ以外productionと同じものをproduction_previewでテストし、OKならmainにマージしてproductionへ反映。
- 環境変数 APP_VARIANTで環境ごとの値をアプリケーション内で指定
EASブランチ | EASチャネル | APP_VARIANT | Gitブランチとの関係 |
---|---|---|---|
production | production | production | mainへのマージでbuild + submit, update |
production_preview | production_preview | production | mainへのPRでbuild, update |
staging | staging | staging | developマージでbuild, update |
local | local | local | feature |
ただし、
- アップデート用タグ(eas-update-v1.0.0.1みたいなフォーマットのタグ)をつけたcommitのみ自動でupdate
- サブミット用タグ(eas-submit-v1.0.0みたいなフォーマットのタグ)をつけたcommitのみ自動でbuild(submit)
その他
- APP_VARIANTの指定を間違わないように、ブランチごとupdateコマンドのエイリアスをpackage.jsonに設定
- ロールバックは今の所手作業
eas update:republish --branch production