這是我在2023第十五屆 iThome 鐵人賽發表的系列文章。https://ithelp.ithome.com.tw/users/20136637/ironman/6408
這篇文章會分享的是使用 Expo + Github action 實現自動 eas update 和 eas build,主要目的是學會使用 Github action。
生成 EXPO Access Token
https://expo.dev/accounts/%5Baccount%5D/settings/access-tokens
要使用 expo cli, eas cli 做任何操作都需要經過身份驗證,也就是說需要登入 expo 帳號密碼,但還有一種更安全和方便的方式是使用 access token 來驗證身份。
點擊上方的連結後選擇帳號:
接著點擊右上方的 Create token
將這個 EXPO_TOKEN 保存起來,接下來會用到。
新增 Github Secret
因為後面需要使用 Github action workflow 來 eas update 和 eas build,所以會需要將剛剛生成的 EXPO_TOKEN 存到 repo 的 Secrets 裡面,這樣一來執行 workflow 的時候才能從 secrets 中獲取到 EXPO_TOKEN,從而進行下一步動作。
到倉庫的 Settings – Secrets and variables – Actions 新增 secret
EAS_ACCESS_KEY
: EXPO TOKEN(剛剛前面申請的)
創建 Github Action workflow
Github Action 是 Github 的 CI/CD(流程自動化) 服務,一般來說會在根目錄底下新增 .github/workflows
資料夾,並且用 YAML 檔來描述自動化流程。
想瞭解更多 Action 的內容可以參考官方文檔:https://docs.github.com/en/actions
創建 .github/workflows
資料夾,並新增 main.yml
:
name: preview # Action 的名字,會顯示在側邊欄
on:
push:
branches:
- main # 監聽是否 push 到 main 這個分支,是的話就會執行 action
jobs: # 一個 action 裡面可以有多個 job
build: # 這邊的 `build` 就是其中一個 job 的名稱
runs-on: ubuntu-latest
steps:
# 使用 actions/checkout 操作來拉取程式碼
- name: 🏗 Checkout Code
uses: actions/checkout@v3
# actions/setup-node 設置 Node.js 版本
- name: 🏗 Setup Node
uses: actions/setup-node@v3
with:
node-version: 18.x
# expo-github-action 是 expo 官方為方便用 Github Action 實現流程自動化而創建,
# 包含了安裝/更新 eas cli、用 expo access token 進行身份驗證
- name: 🏗 Setup EAS
# 直接用 uses 關鍵字執行 expo github action 就不需要再自己去寫這些流程
uses: expo/expo-github-action@v8
with:
eas-version: latest
token: ${{ secrets.EAS_ACCESS_KEY }}
# 安裝應用依賴套件
- name: 📦 Install dependencies
run: npm install --legacy-peer-deps
# 創建 update
# 設置 auto 的話 expo branch 就會是執行 action 的 branch
- name: 🚀 Create update
run: eas update --auto --non-interactive
# 使用 eas build 來 build 應用
# 這邊 build 的是 Android & iOS, 使用 preview profile
# build iOS 需要先設置 credentials (eas credentials)
- name: 🚀 Build Android App
run: eas build --platform All --profile preview --non-interactive
修改 eas.json
如果你的專案中還沒有 eas.json
請使用 eas build:configure
指令生成,如果不想用 preview
profile 的話可以自行新增一個或者也可以自行修改名稱。
eas.json
{
"cli": {
"version": ">= 3.9.1"
},
"build": {
"development": {
"channel": "development",
"developmentClient": true,
"distribution": "internal",
"ios": {
"resourceClass": "m-medium"
}
},
"preview": {
"channel": "preview",
"distribution": "internal",
"ios": {
"resourceClass": "m-medium"
}
},
"production": {
"channel": "production",
"ios": {
"resourceClass": "m-medium"
}
}
},
"submit": {
"production": {}
}
}
對 eas.json 這些設置不瞭解的話可以看官方文檔:https://docs.expo.dev/build/eas-json/
eas update 設置
為了能夠使用 eas update 指令更新,我們需要先進行設置
eas update:configure
輸入指令後會提示你需要將紅框處這段貼到 app.config.js
或者 app.json
中:
建議將 projectId 存在環境變數中,而不是直接寫在檔案裡面。
<em>// app.config.js</em>
module.exports = ({ config }) => {
return {
...config,
extra: {
eas: {
projectId: process.env.PROJECT_ID,
},
},
updates: {
url: `https://u.expo.dev/${process.env.PROJECT_ID}`,
},
runtimeVersion: {
policy: 'sdkVersion',
},
};
};
如果不知道怎麼在應用中使用環境變數,可以看我之前發的文章:【DAY18】React Native – 環境變數的管理(env)
記得有用到的環境變數都要寫進 yaml 中:
- 最後一行的
sed -i "s@.env@@g" .gitignore
代表在 .gitignore 中註釋 .env,如果不在 .gitignore 中註釋掉 .env 的話 eas build 時是無法吃到環境變數的。
<em># .github/workflows/main.yml</em>
name: preview
on:
push:
branches:
- main
jobs:
init:
runs-on: ubuntu-latest
env:
PROJECT_ID: ${{ secrets.PROJECT_ID }}
steps:
<em># 略...</em>
- name: 🏗 Set Variables
run: |
echo "PROJECT_ID=${PROJECT_ID}" >> .env
sed -i "s@.env@@g" .gitignore
<em># .env</em>
PROJECT_ID=
創建 Pull Request
將分支合併到 main 分支觸發自動化構建:
如果在開 pull request 時提示「There isn’t anything to compare… entirely different commit histories.」,需要先 pull main 分支並加上
--allow-unrelated-histories
:git pull origin main --allow-unrelated-histories git push origin <Your_branch_name>
查看 Github Action
在倉庫的 Actions 可以查看正在執行中的 workflows
Troubleshooting
Input is required, but stdin is not readable.
eas build 時如果在 build 成功後卻 workflow 失敗且遇到下方這個 error:
Input is required, but stdin is not readable. Failed to display prompt: Install and run the Android build on an emulator?
就代表需要在 eas build 後面加上 --non-interactive
eas build --platform all --profile <profile_name> --non-interactive