React Native開発:EAS BuildによるmicroCMSリクエストのトラブルシューティング
内容ざっくり
React Native
で作成したアプリを配布可能なアプリケーション(apk、ipa)に変換する際に遭遇した問題と、それを解決した経緯を解説しています。
具体的には、Expo Application Services(EAS)のbuildコマンドを用いた際に出現した'404エラー'の原因と、その解決策が書かれています。
作ったアプリ
起ったこと
作ったアプリを手元だけでなく、配布可能なアプリケーション(apk、ipa)を作成するため、Expo Application Services(EAS)のbuildコマンドをしてみた。
eas build --profile preview
立ち上げたアプリ画面から以下のように出力
Request failed with status code 404
外部にリクエストが必要なものといえば思い当たるのはmicroCMS
なので原因を考えてみる。
EAS Buildとは
EAS BuildはExpoとReact Nativeプロジェクト向けのクラウドベースのビルドサービスです。
デフォルト設定により、すぐに配布可能なアプリのビルドを簡素化し、署名資格情報の管理を自動化します。内部配布(internal-distribution)により、ビルドの共有が容易になり、EAS Submitとの密接な連携でアプリストアへの提出もスムーズらしい。
原因の候補
microCMSへのリクエストが404エラーを返すという事象は、通常、以下のいずれかの問題が原因となる可能性があります。
- リクエスト先のURLが間違っている
- エンドポイントが存在しない
- リソースが存在しない
上記はローカル開発環境で検証できるのでおそらく 「アクセス権限がない」 ことが原因として調べてみました。
原因
アクセス権限がない
microCMSでは、APIリクエストにAPIキーを必要とします。APIキーが正しいことはローカル開発環境で検証できているので、リクエスト時にAPIキーを付与できていない線で考えてみます。
まずは公式を見てみます。
"Because your EAS Build job runs on a remote server, these .env files might not be available. For instance, .env files are excluded from your uploaded project if they are listed in .gitignore or not committed to your local version control system."
上記は、EAS Buildのジョブがリモートサーバー上で動作するため、.env
が利用できない可能性があることを示しています。さらに、.gitignore
にリストされているか、ローカルのバージョン管理システムにコミットされていない場合、.env
はアップロードされたプロジェクトから除外されると説明しています。
自分はまさに、.gitignore
に.env
をリストしていたのでこれが原因の可能性が高そうですね。
ローカル環境では404にならなかったのに、配布用にEAS Buildしたら 404になった理由も、リモートビルド環境がローカル開発環境と異なり、APIキーにアクセスができなかったのでしょう。
解決策
同じ公式に解決策になる記述がありました。
"Therefore, EAS Build lets you set per-build-profile environment variables within eas.json as well as sensitive values that should not be committed to source control via EAS Secrets."
EAS Buildでは、以下の二つの重要な機能が提供されています
- eas.jsonの環境変数設定
- ビルドプロファイルごとの環境変数を
eas.json
内で設定することが可能
- ビルドプロファイルごとの環境変数を
- EAS Secretsの機密情報設定
- ソースコード管理にコミットすべきでない機密情報をEAS Secretsを通じて設定することが可能
ローカルの.env
ファイルを直接EAS Buildで使用することはできず、代わりにEAS Buildで必要な環境変数をeas.json
やEAS Secretsで設定することが推奨されていると解釈できます。
ただし、これは解釈であり、公式ドキュメントで直接指示されているわけではありません。
やってみる
EAS Secretsを設定
Expoの管理ダッシュボードを使用して、EAS Secretsを設定できます。これはプライベートな情報を保存するための場所で、これらの値はビルド中に利用できます。以下の手順でEAS Secretsを設定できます
- Expoの管理ダッシュボードにログイン
- ダッシュボード上でプロジェクトを選択
- 左側のメニューから「Secrets」を選択
- 「Create」ボタンをクリック
- Secretの名前(例:MICROCMS_API_KEY)と値(APIキーの実際の値)を入力
結果
eas.jsonで環境変数を設定
ビルド設定ファイル(eas.json)内で、各ビルドプロファイルに環境変数を定義できます。
{
"cli": {
"version": ">= 3.14.0"
},
"build": {
"default": {
"env": {
"MICROCMS_API_KEY": "@secret:MICROCMS_API_KEY",
"MICROCMS_SERVICE_DOMAIN": "@secret:MICROCMS_SERVICE_DOMAIN"
}
},
"development": {
"developmentClient": true,
"distribution": "internal"
},
"preview": {
"distribution": "internal"
},
"production": {
"env": {
"MICROCMS_API_KEY": "@secret:MICROCMS_API_KEY",
"MICROCMS_SERVICE_DOMAIN": "@secret:MICROCMS_SERVICE_DOMAIN"
}
}
},
"submit": {
"production": {}
}
}
環境変数の値をビルドプロファイルごとに異なるものにしたい場合は、それぞれのビルドプロファイルで異なるEAS Secretsを参照するように設定することも可能です。例えば開発用のAPIキーと本番用のAPIキーを分けるとか。
ランタイム上で環境変数を参照する
EAS Buildにおいて環境変数を設定するためには、eas.json
またはEAS Secrets
にて設定を行いますが、それらの環境変数をアプリ内で使用するためにはapp.config.ts
ファイル内でextra
フィールドに環境変数を定義する必要があります。
import { ExpoConfig, ConfigContext } from "@expo/config";
import { config } from "dotenv";
if (process.env.NODE_ENV !== "production") {
config(); // ".env" file is loaded only in non-production environments
}
export default ({ config: expoConfig }: ConfigContext): ExpoConfig => {
return {
...expoConfig,
name: "my-first-react-native-app",
slug: "my-first-react-native-app",
extra: {
microcmsApiKey: process.env.MICROCMS_API_KEY,
microcmsServiceDomain: process.env.MICROCMS_SERVICE_DOMAIN,
eas: {
projectId: "xxxxxxxxxxxxxxxxxx",
},
},
};
};
EAS Buildではdotenv
のconfig()
関数による.envファイルの読み込みは行われません。したがって、ローカル開発環境でのみ.envファイルを読み込むためにdotenv
のconfig()
を使用し、EAS Buildではeas.jsonやEAS Secretsから環境変数を取得するような設定にすることが推奨されます。
例えば下記の記述
import axios, { AxiosInstance } from "axios";
import { MICROCMS_API_KEY, MICROCMS_SERVICE_DOMAIN } from "@env";
const client: AxiosInstance = axios.create({
baseURL: `https://${MICROCMS_SERVICE_DOMAIN}.microcms.io/api/v1`,
headers: { "X-API-KEY": MICROCMS_API_KEY },
});
export const fetchPosts = async () => {
try {
const response = await client.get("/news");
return response.data.contents;
} catch (error: unknown) {
console.error(error);
throw error;
}
};
export const fetchPostById = async (id: string) => {
try {
const response = await client.get(`/news/${id}`);
return response.data;
} catch (error: unknown) {
console.error(error);
throw error;
}
};
このコード例で、MICROCMS_API_KEY
とMICROCMS_SERVICE_DOMAIN
は@env
からインポートされています。@env
は、環境変数を一元的に管理するためのモジュールで、環境変数の値はどの環境であっても同じ方法でアクセスすることができます。
ローカル開発環境では.env
の内容が@env
によってインポートされます。
本番環境 (EAS Build)ではeas.json
やEAS Secretsから環境変数が読み込まれ、app.config.ts
のextra
フィールドで定義されます。その後、@env
を通じてこれらの値にアクセスすることができます。
ただし、@env
モジュールは、標準的なNode.jsやReact Nativeのモジュールではないため、プロジェクトでこれを使うには追加の設定が必要です。
module.exports = function (api) {
api.cache(true);
return {
presets: ["babel-preset-expo"],
plugins: [
[
"module:react-native-dotenv",
{
moduleName: "@env",
path: ".env",
},
],
],
};
};
これによりreact-native-dotenv
というBabelプラグインが設定され、これにより、@env
というモジュール名で環境変数をインポートできます。
この設定でpathに指定された.env
から環境変数を読み込み、変数をインポートできるようになります。これにより、.env
に定義された環境変数をアプリケーションの中で利用することができます。
import { MICROCMS_API_KEY, MICROCMS_SERVICE_DOMAIN } from "@env";
繰り返しになりますが、これはローカル開発環境での設定であり、本番環境(EAS Build)では代わりにapp.config.ts
のextra
フィールドで環境変数を定義しています。これらの値はeas.json
やEAS Secretsから読み込まれます。
以上の手順により、EAS Build時にmicroCMSへのリクエストが404エラーを返す問題を解決することができました。
コミット
感想
公式に全部書いてあった。
Discussion
非常に読みやすく理解しやすかったので、助かりました!
ありがとうございます👏