From d6af7ca0240828de05aaca9553ce129ea6c4c4b5 Mon Sep 17 00:00:00 2001 From: FleetAdmiralJakob Date: Sun, 24 Aug 2025 16:30:57 +0200 Subject: [PATCH 1/8] added the build part --- .github/workflows/expo-build.yml | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/.github/workflows/expo-build.yml b/.github/workflows/expo-build.yml index 91be810..d243573 100644 --- a/.github/workflows/expo-build.yml +++ b/.github/workflows/expo-build.yml @@ -69,3 +69,38 @@ jobs: run: pnpm install --frozen-lockfile - name: TypeScript type check run: npx tsc --noEmit + + build: + runs-on: ubuntu-latest + needs: [lint, format, typecheck] + env: + EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + - name: Setup pnpm + uses: pnpm/action-setup@v3 + with: + version: 10.12.1 + - name: Install dependencies + run: pnpm install --frozen-lockfile + - name: Ensure EAS CLI available + run: pnpm dlx eas-cli@latest --version + # No explicit login needed, Expo CLI uses EXPO_TOKEN env automatically + - name: Build Android APK + if: env.EXPO_TOKEN != '' + run: pnpm dlx eas-cli@latest build --platform android --non-interactive --profile preview --clear-cache --wait + - name: Download Android APK + if: env.EXPO_TOKEN != '' + run: pnpm dlx eas-cli@latest build:download --platform android --profile preview --latest --path ./app.apk + # ...existing code... + - name: Upload Android artifact + if: env.EXPO_TOKEN != '' + uses: actions/upload-artifact@v4 + with: + name: android-apk + path: ./app.apk \ No newline at end of file From c9618656c2b81654890d289cf66bad14f25623ec Mon Sep 17 00:00:00 2001 From: FleetAdmiralJakob Date: Sun, 24 Aug 2025 16:32:37 +0200 Subject: [PATCH 2/8] format with prettier --- .github/workflows/expo-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/expo-build.yml b/.github/workflows/expo-build.yml index d243573..2cd54e6 100644 --- a/.github/workflows/expo-build.yml +++ b/.github/workflows/expo-build.yml @@ -103,4 +103,4 @@ jobs: uses: actions/upload-artifact@v4 with: name: android-apk - path: ./app.apk \ No newline at end of file + path: ./app.apk From 2f8371b9f7844326a7a38baa86c3441465d891c9 Mon Sep 17 00:00:00 2001 From: Murtaza Noori <65132706+murtazanoori@users.noreply.github.com> Date: Fri, 5 Sep 2025 17:41:34 +0430 Subject: [PATCH 3/8] fix 1.9 --- app.json | 3 ++- app.plugin.js | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 app.plugin.js diff --git a/app.json b/app.json index d81440b..c4cbf7b 100644 --- a/app.json +++ b/app.json @@ -51,7 +51,8 @@ "resizeMode": "contain", "backgroundColor": "#ffffff" } - ] + ], + "./app.plugin.js" ], "experiments": { "typedRoutes": true diff --git a/app.plugin.js b/app.plugin.js new file mode 100644 index 0000000..93d8837 --- /dev/null +++ b/app.plugin.js @@ -0,0 +1,29 @@ +// Inject core-splashscreen dependency to fix Android resource linking errors for Theme.SplashScreen +// This runs during EAS prebuild and modifies android/app/build.gradle +const { withAppBuildGradle, createRunOncePlugin, WarningAggregator } = require('@expo/config-plugins'); + +const DEP_LINE = 'implementation("androidx.core:core-splashscreen:1.0.1")'; + +function ensureDependency(contents) { + if (contents.includes(DEP_LINE)) return contents; // already present + return contents.replace(/dependencies\s*\{/m, (match) => `${match}\n ${DEP_LINE}`); +} + +const withCoreSplashscreenDependency = (config) => + withAppBuildGradle(config, (config) => { + try { + config.modResults.contents = ensureDependency(config.modResults.contents); + } catch (e) { + WarningAggregator.addWarningAndroid( + 'core-splashscreen', + `Failed to add androidx.core:core-splashscreen dependency: ${e?.message ?? e}` + ); + } + return config; + }); + +module.exports = createRunOncePlugin( + withCoreSplashscreenDependency, + 'with-core-splashscreen-dependency', + '1.0.0' +); From e5ba98e2041e2914d2ee2fe8e05f0e0f88f45b06 Mon Sep 17 00:00:00 2001 From: Murtaza Noori <65132706+murtazanoori@users.noreply.github.com> Date: Sun, 7 Sep 2025 19:27:21 +0430 Subject: [PATCH 4/8] fix(android): inject core-splashscreen via config plugin; small comment tweak --- app.plugin.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app.plugin.js b/app.plugin.js index 93d8837..60fe621 100644 --- a/app.plugin.js +++ b/app.plugin.js @@ -22,6 +22,7 @@ const withCoreSplashscreenDependency = (config) => return config; }); + // module exp module.exports = createRunOncePlugin( withCoreSplashscreenDependency, 'with-core-splashscreen-dependency', From dfdfa13abd95321b249fec1a36eb96277da4555f Mon Sep 17 00:00:00 2001 From: Murtaza Noori <65132706+murtazanoori@users.noreply.github.com> Date: Sun, 7 Sep 2025 19:44:09 +0430 Subject: [PATCH 5/8] chore(format): format app.plugin.js with Prettier --- app.plugin.js | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/app.plugin.js b/app.plugin.js index 60fe621..23d2bcf 100644 --- a/app.plugin.js +++ b/app.plugin.js @@ -1,12 +1,19 @@ // Inject core-splashscreen dependency to fix Android resource linking errors for Theme.SplashScreen // This runs during EAS prebuild and modifies android/app/build.gradle -const { withAppBuildGradle, createRunOncePlugin, WarningAggregator } = require('@expo/config-plugins'); +const { + withAppBuildGradle, + createRunOncePlugin, + WarningAggregator, +} = require("@expo/config-plugins"); const DEP_LINE = 'implementation("androidx.core:core-splashscreen:1.0.1")'; function ensureDependency(contents) { if (contents.includes(DEP_LINE)) return contents; // already present - return contents.replace(/dependencies\s*\{/m, (match) => `${match}\n ${DEP_LINE}`); + return contents.replace( + /dependencies\s*\{/m, + (match) => `${match}\n ${DEP_LINE}`, + ); } const withCoreSplashscreenDependency = (config) => @@ -15,16 +22,16 @@ const withCoreSplashscreenDependency = (config) => config.modResults.contents = ensureDependency(config.modResults.contents); } catch (e) { WarningAggregator.addWarningAndroid( - 'core-splashscreen', - `Failed to add androidx.core:core-splashscreen dependency: ${e?.message ?? e}` + "core-splashscreen", + `Failed to add androidx.core:core-splashscreen dependency: ${e?.message ?? e}`, ); } return config; }); - // module exp +// module exp module.exports = createRunOncePlugin( withCoreSplashscreenDependency, - 'with-core-splashscreen-dependency', - '1.0.0' + "with-core-splashscreen-dependency", + "1.0.0", ); From bdf80c79fa8bb0917dc4ac3eb955cc149eb8b86c Mon Sep 17 00:00:00 2001 From: Murtaza Noori <65132706+murtazanoori@users.noreply.github.com> Date: Sun, 7 Sep 2025 19:54:59 +0430 Subject: [PATCH 6/8] fix(config): guard plugin for EAS Read app config phase --- app.plugin.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app.plugin.js b/app.plugin.js index 23d2bcf..4efcea3 100644 --- a/app.plugin.js +++ b/app.plugin.js @@ -9,6 +9,8 @@ const { const DEP_LINE = 'implementation("androidx.core:core-splashscreen:1.0.1")'; function ensureDependency(contents) { + // If gradle file isn't available during introspection, just return as-is. + if (typeof contents !== "string") return contents; if (contents.includes(DEP_LINE)) return contents; // already present return contents.replace( /dependencies\s*\{/m, @@ -19,7 +21,16 @@ function ensureDependency(contents) { const withCoreSplashscreenDependency = (config) => withAppBuildGradle(config, (config) => { try { - config.modResults.contents = ensureDependency(config.modResults.contents); + const updated = ensureDependency(config.modResults?.contents); + if (typeof updated === "string") { + config.modResults.contents = updated; + } else { + // During introspection (e.g., EAS Read app config) the file may not exist yet. + WarningAggregator.addWarningAndroid( + "core-splashscreen", + "Skipped adding androidx.core:core-splashscreen; app/build.gradle not available during introspection.", + ); + } } catch (e) { WarningAggregator.addWarningAndroid( "core-splashscreen", From 327dcd0eb4ebc6d5abd59322a7c4aa1ec383bde4 Mon Sep 17 00:00:00 2001 From: Murtaza Noori <65132706+murtazanoori@users.noreply.github.com> Date: Sun, 7 Sep 2025 20:06:39 +0430 Subject: [PATCH 7/8] chore(build): add @expo/config-plugins as devDependency for local plugin resolution on EAS --- package.json | 1 + pnpm-lock.yaml | 113 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) diff --git a/package.json b/package.json index 49e1367..8f70358 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ }, "devDependencies": { "@babel/core": "^7.25.2", + "@expo/config-plugins": "^7.9.2", "@types/jest": "^29.5.12", "@types/react": "~19.0.14", "@types/react-test-renderer": "^18.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 37ac851..0b78e9e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -183,6 +183,9 @@ importers: '@babel/core': specifier: ^7.25.2 version: 7.27.4 + '@expo/config-plugins': + specifier: ^7.9.2 + version: 7.9.2 '@types/jest': specifier: ^29.5.12 version: 29.5.14 @@ -1225,6 +1228,12 @@ packages: '@expo/config-plugins@10.1.2': resolution: {integrity: sha512-IMYCxBOcnuFStuK0Ay+FzEIBKrwW8OVUMc65+v0+i7YFIIe8aL342l7T4F8lR4oCfhXn7d6M5QPgXvjtc/gAcw==} + '@expo/config-plugins@7.9.2': + resolution: {integrity: sha512-sRU/OAp7kJxrCUiCTUZqvPMKPdiN1oTmNfnbkG4oPdfWQTpid3jyCH7ZxJEN5SI6jrY/ZsK5B/JPgjDUhuWLBQ==} + + '@expo/config-types@50.0.1': + resolution: {integrity: sha512-EZHMgzkWRB9SMHO1e9m8s+OMahf92XYTnsCFjxhSfcDrcEoSdFPyJWDJVloHZPMGhxns7Fi2+A+bEVN/hD4NKA==} + '@expo/config-types@53.0.5': resolution: {integrity: sha512-kqZ0w44E+HEGBjy+Lpyn0BVL5UANg/tmNixxaRMLS6nf37YsDrLk2VMAmeKMMk5CKG0NmOdVv3ngeUjRQMsy9g==} @@ -1241,9 +1250,16 @@ packages: resolution: {integrity: sha512-MYfPYBTMfrrNr07DALuLhG6EaLVNVrY/PXjEzsjWdWE4ZFn0yqI0IdHNkJG7t1gePT8iztHc7qnsx+oo/rDo6w==} hasBin: true + '@expo/fingerprint@0.6.1': + resolution: {integrity: sha512-ggLn6unI6qowlA1FihdQwPpLn16VJulYkvYAEL50gaqVahfNEglRQMSH2giZzjD0d6xq2/EQuUdFyHaJfyJwOQ==} + hasBin: true + '@expo/image-utils@0.7.6': resolution: {integrity: sha512-GKnMqC79+mo/1AFrmAcUcGfbsXXTRqOMNS1umebuevl3aaw+ztsYEFEiuNhHZW7PQ3Xs3URNT513ZxKhznDscw==} + '@expo/json-file@8.3.3': + resolution: {integrity: sha512-eZ5dld9AD0PrVRiIWpRkm5aIoWBw3kAyd8VkuWEy92sEthBKDDDHAnK2a0dw0Eil6j7rK7lS/Qaq/Zzngv2h5A==} + '@expo/json-file@9.1.5': resolution: {integrity: sha512-prWBhLUlmcQtvN6Y7BpW2k9zXGd3ySa3R6rAguMJkp1z22nunLN64KYTUWfijFlprFoxm9r2VNnGkcbndAlgKA==} @@ -1262,6 +1278,9 @@ packages: '@expo/package-manager@1.8.6': resolution: {integrity: sha512-gcdICLuL+nHKZagPIDC5tX8UoDDB8vNA5/+SaQEqz8D+T2C4KrEJc2Vi1gPAlDnKif834QS6YluHWyxjk0yZlQ==} + '@expo/plist@0.1.3': + resolution: {integrity: sha512-GW/7hVlAylYg1tUrEASclw1MMk9FP4ZwyFAY/SUTJIhPDQHtfOlXREyWV3hhrHdX/K+pS73GNgdfT6E/e+kBbg==} + '@expo/plist@0.3.5': resolution: {integrity: sha512-9RYVU1iGyCJ7vWfg3e7c/NVyMFs8wbl+dMWZphtFtsqyN9zppGREU3ctlD3i8KUE0sCUTVnLjCWr+VeUIDep2g==} @@ -1565,6 +1584,9 @@ packages: resolution: {integrity: sha512-a2wsFlIhvd9ZqCD5KPRsbCQmbZi6KxhRN++jrqG0FUTEV5vY7MvjjUqDILwJd2ZBZsf7uiDuClCcKqA+EEdbvw==} engines: {node: '>=18'} + '@react-native/normalize-color@2.1.0': + resolution: {integrity: sha512-Z1jQI2NpdFJCVgpY+8Dq/Bt3d+YUi1928Q+/CZm/oh66fzM0RUl54vvuXlPJKybH4pdCZey1eDTPaLHkMPNgWA==} + '@react-native/normalize-colors@0.74.89': resolution: {integrity: sha512-qoMMXddVKVhZ8PA1AbUCk83trpd6N+1nF2A6k1i6LsQObyS92fELuk8kU/lQs6M7BsMHwqyLCpQJ1uFgNvIQXg==} @@ -1999,6 +2021,11 @@ packages: '@webassemblyjs/wast-printer@1.14.1': resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + '@xmldom/xmldom@0.7.13': + resolution: {integrity: sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g==} + engines: {node: '>=10.0.0'} + deprecated: this version is no longer supported, please update to at least 0.8.* + '@xmldom/xmldom@0.8.10': resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==} engines: {node: '>=10.0.0'} @@ -3463,6 +3490,10 @@ packages: get-tsconfig@4.10.1: resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} + getenv@1.0.0: + resolution: {integrity: sha512-7yetJWqbS9sbn0vIfliPsFgoXMKn/YMF+Wuiog97x+urnSRRRZ7xB+uVkwGKzRgq9CDFfMQnE9ruL5DHv9c6Xg==} + engines: {node: '>=6'} + getenv@2.0.0: resolution: {integrity: sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==} engines: {node: '>=6'} @@ -3482,6 +3513,10 @@ packages: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true + glob@7.1.6: + resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} + deprecated: Glob versions prior to v9 are no longer supported + glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported @@ -5941,6 +5976,9 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + write-file-atomic@2.4.3: + resolution: {integrity: sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==} + write-file-atomic@4.0.2: resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} @@ -5996,6 +6034,10 @@ packages: resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} engines: {node: '>=4.0'} + xmlbuilder@14.0.0: + resolution: {integrity: sha512-ts+B2rSe4fIckR6iquDjsKbQFK2NlUk6iG5nf14mDEyldgoc2nEKZ3jZWMPTxGQwVgToSjt6VGIho1H8/fNFTg==} + engines: {node: '>=8.0'} + xmlbuilder@15.1.1: resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} engines: {node: '>=8.0'} @@ -7148,6 +7190,30 @@ snapshots: transitivePeerDependencies: - supports-color + '@expo/config-plugins@7.9.2': + dependencies: + '@expo/config-types': 50.0.1 + '@expo/fingerprint': 0.6.1 + '@expo/json-file': 8.3.3 + '@expo/plist': 0.1.3 + '@expo/sdk-runtime-versions': 1.0.0 + '@react-native/normalize-color': 2.1.0 + chalk: 4.1.2 + debug: 4.4.1 + find-up: 5.0.0 + getenv: 1.0.0 + glob: 7.1.6 + resolve-from: 5.0.0 + semver: 7.7.2 + slash: 3.0.0 + slugify: 1.6.6 + xcode: 3.0.1 + xml2js: 0.6.0 + transitivePeerDependencies: + - supports-color + + '@expo/config-types@50.0.1': {} + '@expo/config-types@53.0.5': {} '@expo/config@11.0.13': @@ -7203,6 +7269,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@expo/fingerprint@0.6.1': + dependencies: + '@expo/spawn-async': 1.7.2 + chalk: 4.1.2 + debug: 4.4.1 + find-up: 5.0.0 + minimatch: 3.1.2 + p-limit: 3.1.0 + resolve-from: 5.0.0 + transitivePeerDependencies: + - supports-color + '@expo/image-utils@0.7.6': dependencies: '@expo/spawn-async': 1.7.2 @@ -7215,6 +7293,12 @@ snapshots: temp-dir: 2.0.0 unique-string: 2.0.0 + '@expo/json-file@8.3.3': + dependencies: + '@babel/code-frame': 7.10.4 + json5: 2.2.3 + write-file-atomic: 2.4.3 + '@expo/json-file@9.1.5': dependencies: '@babel/code-frame': 7.10.4 @@ -7262,6 +7346,12 @@ snapshots: ora: 3.4.0 resolve-workspace-root: 2.0.0 + '@expo/plist@0.1.3': + dependencies: + '@xmldom/xmldom': 0.7.13 + base64-js: 1.5.1 + xmlbuilder: 14.0.0 + '@expo/plist@0.3.5': dependencies: '@xmldom/xmldom': 0.8.10 @@ -7742,6 +7832,8 @@ snapshots: '@react-native/js-polyfills@0.79.5': {} + '@react-native/normalize-color@2.1.0': {} + '@react-native/normalize-colors@0.74.89': {} '@react-native/normalize-colors@0.79.5': {} @@ -8222,6 +8314,8 @@ snapshots: '@webassemblyjs/ast': 1.14.1 '@xtuc/long': 4.2.2 + '@xmldom/xmldom@0.7.13': {} + '@xmldom/xmldom@0.8.10': {} '@xtuc/ieee754@1.2.0': {} @@ -9910,6 +10004,8 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 + getenv@1.0.0: {} + getenv@2.0.0: {} glob-parent@5.1.2: @@ -9931,6 +10027,15 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 1.11.1 + glob@7.1.6: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -12760,6 +12865,12 @@ snapshots: wrappy@1.0.2: {} + write-file-atomic@2.4.3: + dependencies: + graceful-fs: 4.2.11 + imurmurhash: 0.1.4 + signal-exit: 3.0.7 + write-file-atomic@4.0.2: dependencies: imurmurhash: 0.1.4 @@ -12787,6 +12898,8 @@ snapshots: xmlbuilder@11.0.1: {} + xmlbuilder@14.0.0: {} + xmlbuilder@15.1.1: {} xmlchars@2.2.0: {} From 4dc9b8b7337fa1700b34ad5e76938efb1011520c Mon Sep 17 00:00:00 2001 From: Murtaza Noori <65132706+murtazanoori@users.noreply.github.com> Date: Sun, 7 Sep 2025 20:44:31 +0430 Subject: [PATCH 8/8] fix(android): ensure implementation(project(":expo")) is added via config plugin --- app.plugin.js | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/app.plugin.js b/app.plugin.js index 4efcea3..a2118cc 100644 --- a/app.plugin.js +++ b/app.plugin.js @@ -7,15 +7,31 @@ const { } = require("@expo/config-plugins"); const DEP_LINE = 'implementation("androidx.core:core-splashscreen:1.0.1")'; +const EXPO_AGG_LINE = 'implementation(project(":expo"))'; function ensureDependency(contents) { // If gradle file isn't available during introspection, just return as-is. if (typeof contents !== "string") return contents; - if (contents.includes(DEP_LINE)) return contents; // already present - return contents.replace( - /dependencies\s*\{/m, - (match) => `${match}\n ${DEP_LINE}`, - ); + const hasDepsBlock = /dependencies\s*\{/m.test(contents); + if (!hasDepsBlock) return contents; + + let updated = contents; + // Ensure the :expo aggregator project is present so expo.* classes resolve + if (!updated.includes(EXPO_AGG_LINE)) { + updated = updated.replace( + /dependencies\s*\{/m, + (match) => `${match}\n ${EXPO_AGG_LINE}`, + ); + } + // Ensure the splashscreen dependency is present + if (!updated.includes(DEP_LINE)) { + updated = updated.replace( + /dependencies\s*\{/m, + (match) => `${match}\n ${DEP_LINE}`, + ); + } + + return updated; } const withCoreSplashscreenDependency = (config) =>