W tym artykule chcę podzielić się prostym przykładem automatyzacji lokalnych buildów React Native Expo z wykorzystaniem EAS dla Androida, iOS i Web. Przepływ pracy demonstruje, jak: automatycznie generować buildy specyficzne dla platform, instalować wygenerowany plik .apk na wszystkich podłączonych urządzeniach z Androidem, wdrażać plik .ipa na wszystkich podłączonych urządzeniach z iOS oraz uruchamiać kontener Dockera do obsługi wersji webowej.
Głównym celem tego zestawu jest zapewnienie prostej automatyzacji dla testowych buildów podglądowych. Jednak może on być łatwo dostosowany lub rozszerzony do obsługi buildów produkcyjnych, automatycznej dystrybucji oraz dodatkowych przepływów pracy.
Wszystkie skrypty, konfiguracje i pliki Dockera można znaleźć w repozytorium GitHub: https://github.com/AndreiMaksimovich/react-native-expo-eas-local-build-automation
Dlaczego warto zautomatyzować proces budowania dla React Native Expo EAS
Niezależność
Automatyzując lokalne buildy EAS, nie polegasz wyłącznie na infrastrukturze chmurowej Expo. Nawet jeśli usługa w chmurze ma przestoje, zmienia ceny lub wprowadza ograniczenia, Twój pipeline buildów nadal działa.
Bezpieczne zarządzanie certyfikatami, kluczami API i sekretami
Zautomatyzowane lokalne buildy pozwalają przechowywać klucze API, certyfikaty i produkcyjne sekrety w bezpieczny sposób poza repozytoriami projektów oraz maszynami deweloperskimi. Zamiast tego są one wstrzykiwane podczas procesu budowania, co zmniejsza ryzyko wycieku i utrzymuje poufne dane pod kontrolą.
Szybkość
Lokalne zautomatyzowane buildy mogą być znacząco szybsze. Unikasz oczekiwania w kolejkach chmurowych i zyskujesz większą kontrolę nad alokacją zasobów.
Elastyczność
Mając własny pipeline buildów, możesz rozszerzać go o niestandardowe procedury, na przykład:
- uruchamianie testów automatycznych przed budowaniem
- analitykę, optymalizację i kompresję zasobów
- statyczną analizę kodu i skany bezpieczeństwa
Opis pipeline’u i wymagania
Wymagania systemowe
To środowisko zostało zaprojektowane dla macOS. Należy zainstalować i poprawnie skonfigurować następujące narzędzia:
- Docker
- Git
- Android SDK
- Xcode oraz Xcode Command Line Tools
- cfgutil (dostarczany razem z Apple Configurator 2)
Uwaga: adb
i cfgutil
muszą znajdować się w systemowym PATH.
Projekt React Native Expo
Projekt React Native musi być skonfigurowany do używania buildów EAS.
Umieść lub sklonuj go do katalogu ./react-native-project/
.
Kroki budowania
Poniżej znajduje się uproszczony podział kroków wykonywanych przez ten pipeline:
- Pobranie repozytorium projektu React Native
- Instalacja pakietów npm
- Uruchomienie
expo prebuild
- Konfiguracja credentials
- Build dla Androida
- Build dla iOS
- Build dla Web
- Uruchomienie pliku
.apk
na wszystkich podłączonych urządzeniach z Androidem - Uruchomienie pliku
.ipa
na wszystkich podłączonych urządzeniach z iOS - Uruchomienie kontenera Dockera z buildem webowym
Credentials
Należy przygotować wymagane poświadczenia dla systemu buildów EAS. Szczegółowe instrukcje znajdują się w dokumentacji Expo: https://docs.expo.dev/app-signing/local-credentials/
Umieść plik z poświadczeniami w lokalizacji: ./credentials/credentials.preview.json
Uwaga: Na macOS 15+ można otworzyć Keychain Access z terminala poleceniem: open -a „Keychain Access”
Uwaga: Credentials iOS muszą zawierać profil Ad Hoc provisioning oraz certyfikat dystrybucyjny (Distribution certificate).
Sekrety i klucze
W tym przykładzie nie wstrzykuję sekretów ani kluczy bezpośrednio do procesu budowania. Jednak można to łatwo zrobić poprzez wprowadzenie zmiennych środowiskowych.
Weźmy jako przykład pakiet react-native-maps i klucze API Google Maps:
- Na iOS klucz API jest zahardkodowany w kodzie podczas procesu prebuild i musi być dostępny w konfiguracji aplikacji.
- Na Androidzie klucz API znajduje się w pliku
AndroidManifest.xml
.
Możliwe podejście:
- Przełącz projekt na korzystanie z dynamicznego pliku
app.config.ts
. - Zdefiniuj klucze API jako zmienne środowiskowe w skryptach budowania (np.
export GOOGLE_MAPS_API_KEY_ANDROID=...
). - W pliku
app.config.ts
odczytuj te klucze API ze środowiska i dynamicznie wstrzykuj je do konfiguracji aplikacji. - Dla Androida zaimplementuj własną wtyczkę konfiguracyjną, która pobierze zmienną środowiskową i wstrzyknie ją do manifestu (za pomocą
AndroidConfig.Manifest.addMetaDataItemToMainApplication
).
Skrypt budowania
W tym przykładzie używam najprostszego możliwego podejścia do automatyzacji – skryptu shellowego, który działa jak pipeline buildów, wykonując wymagane kroki jeden po drugim.
Skrypt powinien być dość oczywisty w działaniu build.preview.sh
:
#!/bin/bash
# Switch to the script folder
cd "$(dirname "$0")"
export EXPO_NO_GIT_STATUS=1
# Paths
PROJECT_DIR="react-native-project"
APK_PATH="../builds/android.apk"
IPA_PATH="../builds/ios.ipa"
WEB_PATH="../builds/web"
# Git configuration
USE_GIT="true"
GIT_BRANCH="development"
# Switch to the project dir
cd "$PROJECT_DIR"
# Git checkout
if [ "$USE_GIT" == "true" ]; then
git restore . --staged --worktree
git pull
git checkout $GIT_BRANCH
fi
# Clean
rm -rf android/*
rm -rf ios/*
rm -rf dist/*
rm -rf ../builds/*
# Create buids/web dir
mkdir $WEB_PATH
# Install Node packages and prebuild android/ios projects
npm install
npx expo prebuild --clean
# Copy credentials
cp ../credentials/credentials.preview.json ./credentials.json
# Build Android
eas build --platform android --local --profile preview --output "$APK_PATH"
# Build iOS
eas build --platform ios --local --profile preview --output "$IPA_PATH"
# Build Web
npx expo export -p web
# Move web build to buids/web
mv dist/* "$WEB_PATH"
# Remove changes
if [ "$USE_GIT" == "true" ]; then
git restore . --staged --worktree
fi
# Install .apk on all connected Android devices
adb devices | grep "device$" | while read -r line; do
DEVICE_ID=$(echo "$line" | awk '{print $1}')
if [ "$DEVICE_ID" != "List" ]; then
adb -s "$DEVICE_ID" install "$APK_PATH"
fi
done
# Install .ipa on all connected iOS devices
cfgutil --foreach install-app "$IPA_PATH"
# Launch docker container with web build
sh ../docker/Up.sh
Co dalej
Ten przykład można rozbudować do pełnego pipeline’u CI/CD. Niektóre możliwe kierunki to:
Integracja z CI/CD
Części skryptu buildówania mogą być wykorzystane w CI/CD pipeline’ach obsługiwanych przez Jenkins, lokalny GitLab CI/CD lub inne systemy automatyzacji.
Testowanie i zapewnianie jakości
Pipeline produkcyjny powinien integrować testy automatyczne na wielu poziomach (jednostkowe, integracyjne, end-to-end). Powinien również uwzględniać statyczną analizę kodu, linting oraz inne mechanizmy kontroli jakości jako część procesu budowania.
Bezpieczne zarządzanie sekretami
Pipeline powinien być jedynym miejscem, w którym wstrzykiwane/używane są produkcyjne poświadczenia, certyfikaty podpisywania i klucze API. Sekrety nigdy nie mogą być przechowywane w repozytoriach ani na maszynach deweloperskich.
Automatyczna dystrybucja
- iOS: Automatyzacja dystrybucji plików
.ipa
przez OTA wraz ze stroną WWW i powiadomieniami e-mail lub Slack, albo bezpośrednie wypychanie buildów do TestFlight. - Android: Wgrywanie plików
.apk
/.aab
do kanałów Google Play Internal Testing. - Web: Wypychanie zdockerowanego buildu webowego na serwery beta do testów w przeglądarce.