有些時候我們會需要針對不同的環境設置不同的key、API…等,或者不希望把隱私的資料直接明晃晃寫出來,就可以將這些隱私資料存到環境變數(Enviroment Variables)中。
要在 RN 管理環境變數可以使用 react-native-dotenv 這個庫。
安裝 react-native-dotenv
npm install -D react-native-dotenv @types/react-native-dotenv
// or
yarn add -D react-native-dotenv @types/react-native-dotenv接著在 babel.config.js 的 plugins 加上 ['module:react-native-dotenv']:
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
['module:react-native-dotenv'],
//...
]
}這邊使用默認設置就好,如果需要進階設置可以參考官方文檔
基本使用
在專案根目錄新增 .env:
API_URL=https://api.example.org
API_TOKEN=abc123在需要使用環境變數的檔案中 import from '@env' :
import { API_URL, API_TOKEN } from '@env'
fetch(`${API_URL}/users`, {
headers: {
'Authorization': `Bearer ${API_TOKEN}`
}
})支持 TypeScript
現在 import 環境變數時 IDE 應該會提示錯誤:

這是因為我們需要為 module 進行型別宣告。
在專案根目錄中建立一個 _types_ 資料夾,並且新增 env.d.ts
declare module '@env' {
export const API_URL: string;
}在裡面定義環境變數的型別後,這個錯誤提示就會消失,並且 IDE 會提示你有哪些變數可使用:

如果還是一樣提示錯誤,那就需要在 tsconfig.json 中指定 typeRoots:
{
"extends": "@tsconfig/react-native/tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
},
"typeRoots": ["./src/_types_"]
}
}題外話,如果希望描述環境變數的用處,可以使用 JSDoc:

declare module '@env' {
/**
* API URL
*/
export const API_URL: string;
}多個環境
如果有多個環境需要設置不同的環境變數,比如說 dev, prod,就可以新建三個 .env:
- .env
API_URL=http://192.168.0.xxx- .env.dev
API_URL=https://dev.api.xxxxxxx- .env.prod
API_URL=https://api.xxxxxxx記得要將
.env,.env.dev,.env.prod加到 .gitignore 中。
接著在 package.json 中新增不同的啟動 script:
- 本地使用 npm run start,默認讀取
.env - dev環境使用
npm run start:dev - prod環境使用
npm run start:prod
{
"scripts": {
"start": "npx react-native start",
"start:dev": "NODE_ENV=dev npx react-native start",
"start:prod": "NODE_ENV=prod npx react-native start",
}
}Expo 管理環境變數
SDK49(含)以上
- 使用
EXPO_PUBLIC_作為環境變數名的前綴 - 不需要安裝任何第三方庫就可以直接獲取環境變數的值
// .env
EXPO_PUBLIC_API_URL=https://staging.example.com
EXPO_PUBLIC_API_KEY=abc123import { Button } from 'react-native'
function Post() {
const apiUrl = process.env.EXPO_PUBLIC_API_URL
async function onPress() {
await fetch(apiUrl, { ... })
}
return <Button onPress={onPress} title="Post" />
}多個環境的設置方法都一樣,只不過是把 react-native start 改為 expo start 而已:
{
"scripts": {
"start": "npx expo start",
"start:dev": "NODE_ENV=dev npx expo start",
"start:prod": "NODE_ENV=prod npx expo start"
}
}SDK49 以下
有兩種方式(其實不只兩種,不過這邊就簡單官方建議的兩種):
一、用 eas secret 管理,詳細的請參考官方文檔
二、使用 dotenv 和 expo-constants
npx expo install dotenv expo-constants
一樣是將環境變數存在 .env
// .env
API_URL=https://api.production.com
PROJECT_ID=xxxxxxxxxxxxxxxxxxxxx
然後在 app.json 或者 app.config.ts 的 extra 中定義環境變數:
<em>// app.config.ts</em>
import 'dotenv/config'
module.exports = ({ config }) => {
return {
...config,
extra: {
API_URL: process.env.API_URL,
eas: {
projectId: process.env.PROJECT_ID,
},
},
}
}
在 App 中使用:
import Constants from 'expo-constants'
const API_URL = Constants.manifest.extra.API_URL;
console.log(API_URL) <em>// https://api.production.com</em>eas build 時獲取環境變數
如果使用 eas build 指令,需要先將 .gitignore 中的 .env 註釋後再 build,否則 expo 無法吃到環境變數的值。
2024-03-08 補充:可以使用
.easignore在 eas build 時取代.gitignore。
注意:如果在eas.json中設定requireCommit: true,則不支援.easignore
參考:How projects are uploaded to EAS Build
在 CI/CD 流程中管理環境變數
可以在 CI/CD 時將環境變數寫入應用的 .env 中,這邊以 github 和 gitlab 為例。
Github
將環境變數新增至倉庫的 actions secrets


然後在 workflow yml 中添加以下 step:
echo "APP_ENV_KEY=${SECRET_KEY}" >> .env即將環境變數的值寫入.env中sed -i "s@.env@@g" .gitignore代表在 .gitignore 中註釋 .env,如果不在 .gitignore 中註釋掉 .env 的話 eas build 時是無法吃到環境變數的。
env:
BASE_URL: ${{ secrets.API_URL }}
steps:
- name: Set Variables
run: |
echo "BASE_URL=${BASE_URL}" >> .env
sed -i "s@.env@@g" .gitignore# .env
BASE_URL=Gitlab
在 repo 的 Settings – CI/CD – Variables 新增環境變數:


注意:設置為
protected的變數只有protected的分支可以獲取得到。
在 .gitlab-ci.yml 中使用 echo "APP_ENV_KEY=${REPO_VARIABLE_NAME}" >> .env 就可以將環境變數的值寫入 .env 中:
# .gitlab-ci.yml
init:develop:
stage: init
script:
- echo "BASE_URL=${API_URL}" >> .env
- sed -i "s@.env@@g" .gitignore
artifacts:
paths:
- .env
- .gitignore// .env
BASE_URL=



