expo-app-config
app.json, app.config.ts, app.config.js arasinda secim, environment variables, variants (dev/staging/prod) ve identifier disiplini. Plugin chain expo-config-plugin'dedir.
Ne Yapar
app.jsonvsapp.config.tsvsapp.config.jskarari- Environment variables (
.env,EXPO_PUBLIC_*, EAS Secrets) - Multi-variant (dev/staging/production) yapilandirma
extrafield disiplini ve runtime erisim- Slug, scheme, bundleIdentifier, package, version, buildNumber yonetimi
- Plugin chain sirasi
Hangi Format?
| Format | Avantaj | Sinir | Ne zaman? |
|---|---|---|---|
app.json |
Statik, basit | JS yok, env yok | Tek variant, simple |
app.config.js |
Dynamic, env | TypeScript yok | Eski tercih |
app.config.ts |
Dynamic + tipli | Compile step | Onerilen |
Cogu projede
app.config.tskullan.app.json'i statik fallback olarak birak veya tamamen kaldir.
app.config.ts Sablonu
import { ExpoConfig, ConfigContext } from "expo/config";
export default ({ config }: ConfigContext): ExpoConfig => {
const variant = process.env.APP_VARIANT ?? "development";
const isProduction = variant === "production";
return {
...config,
name: variantName(variant),
slug: "myapp",
scheme: "myapp",
version: "1.2.0",
orientation: "portrait",
icon: `./assets/icon-${variant}.png`,
userInterfaceStyle: "automatic",
splash: {
image: "./assets/splash.png",
resizeMode: "contain",
backgroundColor: "#ffffff",
},
ios: {
bundleIdentifier: bundleId(variant),
buildNumber: "1",
supportsTablet: true,
infoPlist: {
NSCameraUsageDescription: "Kamera erisimi gerekli",
},
},
android: {
package: bundleId(variant),
versionCode: 1,
adaptiveIcon: {
foregroundImage: `./assets/icon-fg-${variant}.png`,
backgroundColor: "#ffffff",
},
},
plugins: [
"expo-router",
"expo-dev-client",
["expo-notifications", { icon: "./assets/notif-icon.png" }],
],
extra: {
apiUrl: process.env.EXPO_PUBLIC_API_URL,
sentryDsn: process.env.SENTRY_DSN,
eas: { projectId: "your-eas-project-id" },
variant,
},
runtimeVersion: { policy: "fingerprint" },
updates: {
url: "https://u.expo.dev/your-project-id",
},
};
};
function variantName(v: string): string {
switch (v) {
case "production": return "MyApp";
case "staging": return "MyApp (Staging)";
default: return "MyApp (Dev)";
}
}
function bundleId(v: string): string {
const base = "com.example.myapp";
if (v === "production") return base;
return `${base}.${v}`;
}
Variant Calistirma
APP_VARIANT=development npx expo start
APP_VARIANT=staging eas build --profile preview
APP_VARIANT=production eas build --profile production
eas.json:
{
"build": {
"development": { "env": { "APP_VARIANT": "development" } },
"preview": { "env": { "APP_VARIANT": "staging" } },
"production": { "env": { "APP_VARIANT": "production" } }
}
}
Environment Variables
| Tip | Erisim | Build-time | Runtime |
|---|---|---|---|
EXPO_PUBLIC_* (.env) |
JS: process.env.EXPO_PUBLIC_X |
Evet | Evet (gomulu) |
process.env.X (app.config.ts) |
Sadece config'te | Evet | Hayir |
| EAS Secret | EAS build sirasinda | Evet | Hayir (gomulmez) |
extra field |
Constants.expoConfig.extra.X |
Evet | Evet |
KRITIK: API anahtarlari
EXPO_PUBLIC_*ile ASLA prefix etme — istemciye gomulur, herkes okur. Gercek secret'lar backend'de.
.env Dosyalari
# .env (default)
EXPO_PUBLIC_API_URL=https://api.dev.example.com
# .env.production
EXPO_PUBLIC_API_URL=https://api.example.com
.gitignore:
.env.local
.env.*.local
.envcommit edilir mi?EXPO_PUBLIC_*zaten public, sorun yok. Secret degerler.env.local'de tutulur, asla commit edilmez.
extra Field Runtime Erisim
import Constants from "expo-constants";
const apiUrl = Constants.expoConfig?.extra?.apiUrl;
const variant = Constants.expoConfig?.extra?.variant;
Typed wrapper:
// src/config.ts
import Constants from "expo-constants";
type AppExtra = {
apiUrl: string;
sentryDsn: string;
variant: "development" | "staging" | "production";
};
export const appConfig = Constants.expoConfig?.extra as AppExtra;
Identifier Disiplini
| Field | Format | Degisirse |
|---|---|---|
slug |
kebab-case |
EAS project ID degisir |
scheme |
kebab-case veya tek kelime |
Deep link kirildi |
ios.bundleIdentifier |
com.org.app |
Yeni app, sertifika gecersiz |
android.package |
com.org.app |
Yeni app, keystore gecersiz |
version |
1.2.3 (SemVer) |
Yeni release |
ios.buildNumber |
string |
Her build artir |
android.versionCode |
integer |
Her build artir |
bundleIdentifiervepackagedegisirse uygulama yeni bir uygulama olur. Eski yukleyiciler kaybolur.
Variant'lar Icin Bundle ID Stratejisi
com.example.myapp # production
com.example.myapp.staging # staging
com.example.myapp.dev # development
Avantaj: 3 ayri uygulama ayni cihazda yan yana. Production cihazi tehlikeye atmaz.
Plugin Chain
plugins: [
"expo-router", // Once routing
"expo-dev-client", // Dev araclari
["expo-build-properties", { // Native build ozellikleri
ios: { deploymentTarget: "15.1" },
android: { compileSdkVersion: 34 }
}],
["expo-notifications", { icon: "..." }], // Native modul'ler
"./plugins/withCustomConfig", // Custom plugin'ler
]
Sira: routing → dev tools → build props → native modul → custom.
Best Practices
app.config.tssec — typed + dynamic- Variant bundle ID disiplini ile 3 paralel app
- EAS Secrets gercek secret'lar icin (asla
.envveyaEXPO_PUBLIC_) expo-build-propertiesplugin'i ile native versiyon kontroluruntimeVersion: fingerprintOTA disiplini icinextra.eas.projectIdASLA elden silme- SemVer: major (breaking), minor (feature), patch (fix)
Sik Hata Kaliplari
app.json+app.config.tsikisi de var →app.config.tskazanir, kafa karistirirEXPO_PUBLIC_API_SECRET→ secret istemciye sizarextra.eas.projectIdsilinmis → EAS yeni project olusturmaya calisirbundleIdentifierdegistirilmis → sertifika/keystore yenilemek gerekirversionCodeartmamis → Play Store reddeder.envdegisikligi sonrasi Metro cache →--cleargerekirextrafield tipsiz → runtime'daundefinedpatlama
Hard Refusal
- Baska app'in bundle ID'sini taklit (hijack)
- API secret'i
EXPO_PUBLIC_prefix ile gomdurmek extrafield icine credit card/PII koymak- Variant ID disiplini olmadan production verisini staging app'e bagliyor
Cikti Formati
- Format secimi (
app.config.tsrationale) - Variant ve bundle ID stratejisi
.envve EAS Secret ayrimi- Plugin chain sirasi
- Identifier disiplini ozeti
- Sonraki adim:
expo-config-pluginveyaexpo-eas-build