iT邦幫忙

2023 iThome 鐵人賽

DAY 18
0
自我挑戰組

React Native 奇幻之旅系列 第 18

【DAY18】React Native - 環境變數的管理(env)

  • 分享至 

  • xImage
  •  

有些時候我們會需要針對不同的環境設置不同的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=abc123
import { 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 以下

有兩種方式(其實不只兩種,不過這邊就簡單官方建議的兩種):

  1. eas secret 管理,詳細的請參考官方文檔
  2. 使用 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 中定義環境變數:
    // app.config.ts
    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) // https://api.production.com
    

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

確認 eas build 時有沒有吃到環境變數

eas build 時有一個階段叫做 Read app config

點開來確定 extra 是否為空就可以知道到底有沒有吃到環境變數。

像這張圖這樣就是沒吃到:

這樣就是吃到了:

在 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=

參考資料


上一篇
【DAY17】React Native - 防鍵盤遮擋(KeyboardAvoidingView)
下一篇
【DAY19】React Native - 資料的存儲和快取
系列文
React Native 奇幻之旅31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言