// The Gradle build resolves this config in a plain node process that does not // read .env, unlike `expo start` / `expo prebuild`. Without this the release // APK was written with the placeholder origin below and could not reach the // API at all. @expo/env is Expo's own loader — the same one the CLI uses. require("@expo/env").load(__dirname); // Dynamic Expo config. We use a JS config (rather than static app.json) so the // Android Google Maps API key can be pulled from EXPO_PUBLIC_GOOGLE_API_KEY // at build time without committing the key to the repo. // // react-native-maps renders blank tiles (just the Google logo, nothing else) // on Android when no Maps API key is set in the AndroidManifest. Expo's // prebuild reads `android.config.googleMaps.apiKey` and writes it to the // manifest as com.google.android.geo.API_KEY — that is what makes the map // actually draw. On iOS the default provider is Apple Maps, which needs no // key, so nothing is injected there. const googleMapsApiKey = process.env.EXPO_PUBLIC_GOOGLE_API_KEY; // Expo Router resolves relative API-route fetches ("/(api)/auth/login") against // this origin. In development it is overridden with the dev server URL, so the // placeholder never mattered; a release build has no such override and would // send every request to example.com. Point it at the same host that serves the // API routes. const serverOrigin = process.env.EXPO_PUBLIC_SERVER_URL || "https://example.com/"; // Adds the SYSTEM_ALERT_WINDOW permission to the AndroidManifest so the app // can request "display over other apps". The grant itself is a special // permission the user must toggle in system settings — it can't be requested // at runtime — but the manifest entry is what makes that system screen offer // the switch for our app. const { withAndroidManifest } = require("@expo/config-plugins"); // Release builds block cleartext HTTP: only src/debug/AndroidManifest.xml opts // in. A LAN test build talks to the dev server over http://, so allow it for // every build type. Drop this plugin once the API is served over https. const withCleartextTraffic = (config) => withAndroidManifest(config, (cfg) => { const application = cfg.modResults.manifest.application?.[0]; if (application) { application.$["android:usesCleartextTraffic"] = "true"; } return cfg; }); const withOverlayPermission = (config) => withAndroidManifest(config, (cfg) => { const manifest = cfg.modResults.manifest; manifest["uses-permission"] = manifest["uses-permission"] || []; const alreadyDeclared = manifest["uses-permission"].some( (entry) => entry.$ && entry.$["android:name"] === "android.permission.SYSTEM_ALERT_WINDOW", ); if (!alreadyDeclared) { manifest["uses-permission"].push({ $: { "android:name": "android.permission.SYSTEM_ALERT_WINDOW" }, }); } return cfg; }); module.exports = ({ config }) => ({ ...config, name: "Waseel", description: "Find your perfect ride with Waseel.", githubUrl: "https://github.com/sanidhyy/uber-clone", slug: "waseel", version: "1.0.0", orientation: "portrait", icon: "./assets/images/icon.png", scheme: "waseel", userInterfaceStyle: "automatic", splash: { image: "./assets/images/splash.png", resizeMode: "contain", backgroundColor: "#2F80ED", }, ios: { supportsTablet: true, bundleIdentifier: "com.waseel.app", }, android: { adaptiveIcon: { foregroundImage: "./assets/images/adaptive-icon.png", backgroundColor: "#ffffff", }, package: "com.waseel.app", config: { googleMaps: { apiKey: googleMapsApiKey ?? "", }, }, }, web: { bundler: "metro", output: "server", favicon: "./assets/images/favicon.png", }, plugins: [ [ "expo-router", { origin: serverOrigin, }, ], withOverlayPermission, withCleartextTraffic, ], experiments: { typedRoutes: true, }, extra: { router: { origin: serverOrigin, }, }, });