diff --git a/.github/actions/expo-caches/action.yml b/.github/actions/expo-caches/action.yml
index cbb16a96f8f1a6..6034c9e37a17e1 100644
--- a/.github/actions/expo-caches/action.yml
+++ b/.github/actions/expo-caches/action.yml
@@ -68,14 +68,14 @@ runs:
steps:
- name: ♻️ Restore /docs node modules
if: inputs.pnpm-docs == 'true'
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
+ uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
id: docs-modules-cache
with:
path: docs/node_modules
key: ${{ runner.os }}-docs-modules-${{ hashFiles('docs/pnpm-lock.yaml') }}
- name: ♻️ Restore Docs Next cache
if: inputs.pnpm-docs == 'true'
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
+ uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: docs/.next/cache
key: ${{ runner.os }}-docs-${{ hashFiles('docs/pnpm-lock.yaml') }}-${{ hashFiles('docs/**/*.js', 'docs/**/*.jsx', 'docs/**/*.ts', 'docs/**/*.tsx') }}
@@ -83,7 +83,7 @@ runs:
${{ runner.os }}-docs-${{ hashFiles('docs/pnpm-lock.yaml') }}-
- name: ♻️ Restore Docs ESLint cache
if: inputs.pnpm-docs == 'true'
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
+ uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: docs/.eslintcache
key: ${{ runner.os }}-docs-eslint-${{ hashFiles('docs/pnpm-lock.yaml') }}-${{ hashFiles('docs/eslint.config.mjs') }}
@@ -91,7 +91,7 @@ runs:
- name: ♻️ Restore Docs API data
if: inputs.docs-api-data == 'true'
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
+ uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
id: docs-api-data-cache
with:
path: docs/public/static/data/unversioned
@@ -99,7 +99,7 @@ runs:
- name: ♻️ Restore ios/Pods from cache
if: inputs.ios-pods == 'true'
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
+ uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
id: ios-pods-cache
with:
path: ios/Pods
@@ -107,7 +107,7 @@ runs:
- name: ♻️ Restore apps/bare-expo/ios/Pods from cache
if: inputs.bare-expo-pods == 'true'
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
+ uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
id: bare-expo-pods-cache
with:
path: apps/bare-expo/ios/Pods
@@ -115,7 +115,7 @@ runs:
- name: ♻️ Restore apps/bare-expo/macos/Pods from cache
if: inputs.bare-expo-macos-pods == 'true'
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
+ uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
id: bare-expo-macos-pods-cache
with:
path: apps/bare-expo/macos/Pods
@@ -123,7 +123,7 @@ runs:
- name: ♻️ Restore apps/native-tests/ios/Pods from cache
if: inputs.native-tests-pods == 'true'
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
+ uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
id: native-tests-pods-cache
with:
path: apps/native-tests/ios/Pods
@@ -131,13 +131,13 @@ runs:
- name: ♻️ Restore Gradle cache
if: inputs.ndk == 'true' || inputs.gradle == 'true'
- uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4
+ uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2
with:
cache-read-only: ${{ github.ref != 'refs/heads/main' && !contains(github.ref, 'sdk-') }}
- name: ♻️ Restore Android NDK from cache
if: inputs.ndk == 'true'
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
+ uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
id: cache-android-ndk
with:
path: /usr/local/lib/android/sdk/ndk/${{ inputs.ndk-version }}/
@@ -155,7 +155,7 @@ runs:
- name: ♻️ Restore ccache (iOS)
if: inputs.ccache == 'true' && runner.os == 'macOS'
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
+ uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ${{ runner.temp }}/.ccache
# It is necessary to include Xcode version in the cache key, because each Xcode version introduces changes to clang compiler,
@@ -165,7 +165,7 @@ runs:
- name: ♻️ Restore ccache (Android)
if: inputs.ccache == 'true' && runner.os == 'Linux'
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
+ uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ${{ runner.temp }}/.ccache
key: ${{ runner.os }}-ccache-${{ hashFiles('pnpm-lock.yaml', 'packages/**/*.c', 'packages/**/*.cpp', 'packages/**/*.h', 'packages/**/build.gradle', 'packages/**/build.gradle.kts', 'packages/**/settings.gradle', 'packages/**/settings.gradle.kts', 'apps/bare-expo/**/build.gradle', 'apps/bare-expo/**/settings.gradle') }}
@@ -177,7 +177,7 @@ runs:
run: echo "sha256=$(git lfs ls-files | openssl dgst -sha256)" >> $GITHUB_OUTPUT
shell: bash
- name: ♻️ Restore Git LFS cache
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
+ uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
id: git-lfs-cache
if: inputs.git-lfs == 'true'
with:
@@ -190,7 +190,7 @@ runs:
run: echo "REACT_NATIVE_DOWNLOADS_DIR=$HOME/.gradle/react-native-downloads" >> $GITHUB_ENV
- name: ♻️ Restore Gradle downloads cache for React Native libraries
if: inputs.react-native-gradle-downloads == 'true'
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
+ uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ${{ env.REACT_NATIVE_DOWNLOADS_DIR }}
key: gradle-downloads-${{ hashFiles('pnpm-lock.yaml') }}
diff --git a/.github/actions/slack-notify/action.yml b/.github/actions/slack-notify/action.yml
index 52d282fb180976..90bd0e3821d566 100644
--- a/.github/actions/slack-notify/action.yml
+++ b/.github/actions/slack-notify/action.yml
@@ -36,7 +36,7 @@ runs:
steps:
- name: Gather job details
id: details
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
JOB_NAME: ${{ inputs.job_name }}
JOB_STATUS: ${{ inputs.status }}
@@ -186,7 +186,7 @@ runs:
core.setOutput('author_name', escape(process.env.AUTHOR_NAME));
- name: Send to Slack
- uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
+ uses: slackapi/slack-github-action@45a88b9581bfab2566dc881e2cd66d334e621e2c # v3.0.3
with:
webhook: ${{ inputs.webhook }}
webhook-type: incoming-webhook
diff --git a/.github/codemention.yml b/.github/codemention.yml
index 94182cd6b615a1..39c3a8fa3f77e7 100644
--- a/.github/codemention.yml
+++ b/.github/codemention.yml
@@ -1,6 +1,13 @@
commentConfiguration:
- preamble: 'Subscribed to pull request'
- epilogue: 'Generated by [CodeMention](https://github.com/expo/expo/actions/workflows/codemention.yaml)'
+ template: |
+ Subscribed to pull request
+ | File Patterns | Mentions |
+ | - | - |
+ {{#each matchedRules}}
+ | {{#each patterns}}{{markdownEscape this}}{{#unless @last}}
{{/unless}}{{/each}} | {{#each mentions}}@{{this}}{{#unless @last}}, {{/unless}}{{/each}} |
+ {{/each}}
+
+ Generated by [CodeMention](https://github.com/expo/expo/actions/workflows/codemention.yaml)
rules:
- patterns: ['.github/workflows/**']
mentions: ['tsapeta', 'brentvatne', 'kudo']
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index fff8eee6575662..b990e80787329e 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -10,6 +10,12 @@ updates:
- /.github/actions/use-android-emulator
schedule:
interval: weekly
+ ignore:
+ # Stay on gradle/actions v5.x: v6 moved caching into the closed-source
+ # gradle-actions-caching component governed by Gradle's Terms of Use.
+ # Remove this if we decide to adopt the v6+ caching component.
+ - dependency-name: 'gradle/actions'
+ update-types: ['version-update:semver-major']
groups:
actions:
patterns:
diff --git a/.github/workflows/android-instrumentation-tests.yml b/.github/workflows/android-instrumentation-tests.yml
index 774982009969d1..f28b91e2cdcebd 100644
--- a/.github/workflows/android-instrumentation-tests.yml
+++ b/.github/workflows/android-instrumentation-tests.yml
@@ -58,7 +58,7 @@ jobs:
api-level: [36]
steps:
- name: 👀 Check out repository
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🔨 Install pnpm
uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6
with:
@@ -94,7 +94,7 @@ jobs:
script: pnpm expotools android-native-unit-tests --type instrumented
- name: 💾 Save test results
if: always()
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: test-results
path: packages/*/android/build/outputs/androidTest-results/**/*
diff --git a/.github/workflows/android-unit-tests.yml b/.github/workflows/android-unit-tests.yml
index 2694afa3d4c472..63ba32b650dc5c 100644
--- a/.github/workflows/android-unit-tests.yml
+++ b/.github/workflows/android-unit-tests.yml
@@ -35,7 +35,7 @@ jobs:
GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx3072m -XX:MaxMetaspaceSize=1024m
steps:
- name: 👀 Check out repository
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🔨 Install pnpm
uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6
with:
@@ -68,7 +68,7 @@ jobs:
run: pnpm expotools native-unit-tests --platform android
- name: 💾 Save test results
if: always()
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: test-results
path: packages/*/android/build/test-results/**/*xml
diff --git a/.github/workflows/bare-diffs.yml b/.github/workflows/bare-diffs.yml
index beee451a8d6020..27b8b71b9e0d77 100644
--- a/.github/workflows/bare-diffs.yml
+++ b/.github/workflows/bare-diffs.yml
@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🔨 Install pnpm
uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6
with:
@@ -43,7 +43,7 @@ jobs:
author_name: Check for Changes in Bare Diffs
- name: 💾 Store artifacts of diff failures
if: failure()
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: template-bare-minimum-bare-diff-failure
path: docs/public/static/diffs/template-bare-minimum/raw
diff --git a/.github/workflows/check-issues-nightly.yml b/.github/workflows/check-issues-nightly.yml
index 69bf5d530ed988..feb2d438844d5d 100644
--- a/.github/workflows/check-issues-nightly.yml
+++ b/.github/workflows/check-issues-nightly.yml
@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: ➕ Add `bin` to GITHUB_PATH
run: echo "$(pwd)/bin" >> $GITHUB_PATH
- name: 🔨 Install pnpm
diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml
index 653744d9c00dd9..bf18f2adfc506e 100644
--- a/.github/workflows/cli.yml
+++ b/.github/workflows/cli.yml
@@ -63,7 +63,7 @@ jobs:
shard: [1, 2, 3, 4]
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 100
- name: ⬇️ Fetch commits from base branch
@@ -121,7 +121,7 @@ jobs:
git config --global core.eol lf
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 100
- name: ⬇️ Fetch commits from base branch
@@ -165,7 +165,7 @@ jobs:
shard: [1, 2, 3, 4]
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 100
- name: ⬇️ Fetch commits from base branch
@@ -198,7 +198,7 @@ jobs:
run: |
echo version="$(pnpm exec playwright --version)" >> $GITHUB_OUTPUT
- name: 🎭 Cache Playwright browser binaries
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
+ uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
id: playwright-browser-cache
with:
path: ~/.cache/ms-playwright
@@ -213,7 +213,7 @@ jobs:
run: pnpm test:playwright --shard ${{ matrix.shard }}/${{ strategy.job-total }}
- name: 🗄️ Upload playwright report
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: always()
with:
name: playwright-report-ubuntu-${{ matrix.shard }}
@@ -246,7 +246,7 @@ jobs:
git config --global core.eol lf
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 100
- name: ⬇️ Fetch commits from base branch
@@ -280,7 +280,7 @@ jobs:
echo version="$(pnpm exec playwright --version)" >> $GITHUB_OUTPUT
echo dir="$(echo $PLAYWRIGHT_BROWSERS_PATH)" >> $GITHUB_OUTPUT
- name: 🎭 Cache Playwright browser binaries
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
+ uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
id: playwright-browser-cache
with:
path: ${{ steps.playwright-info.outputs.dir }}
@@ -295,7 +295,7 @@ jobs:
run: pnpm test:playwright --shard ${{ matrix.shard }}/${{ strategy.job-total }}
- name: 🗄️ Upload playwright report
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: always()
with:
name: playwright-report-windows-${{ matrix.shard }}
diff --git a/.github/workflows/code-review.yml b/.github/workflows/code-review.yml
index 60af1ff722bded..bd61caefac3911 100644
--- a/.github/workflows/code-review.yml
+++ b/.github/workflows/code-review.yml
@@ -27,7 +27,7 @@ jobs:
timeout-minutes: 30
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🔨 Install pnpm
uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6
with:
diff --git a/.github/workflows/codemention.yaml b/.github/workflows/codemention.yaml
index ec332388d23667..f91e48e5dc8f2a 100644
--- a/.github/workflows/codemention.yaml
+++ b/.github/workflows/codemention.yaml
@@ -16,6 +16,6 @@ jobs:
# Pinned to a commit SHA (not the v1.4.0 tag) because this runs under
# pull_request_target with a write-scoped token — a re-pointed tag from
# a compromised upstream account would give the attacker repo write access.
- - uses: tobyhs/codemention@bb6bfb2c3ff1e6fee7ee37006bbee6d114057225 # v1.4.0
+ - uses: tobyhs/codemention@14c10ab8528ed556c3b92f205e7b5aa03e7b187c # v1.5.2
with:
githubToken: ${{ secrets.GITHUB_TOKEN }}
\ No newline at end of file
diff --git a/.github/workflows/commentator.yml b/.github/workflows/commentator.yml
index 1009aad8794f55..0fbedb6bea7d86 100644
--- a/.github/workflows/commentator.yml
+++ b/.github/workflows/commentator.yml
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: ➕ Add `bin` to GITHUB_PATH
run: echo "$(pwd)/bin" >> $GITHUB_PATH
- name: 🔨 Install pnpm
diff --git a/.github/workflows/create-expo-app.yml b/.github/workflows/create-expo-app.yml
index 8d53b80a14f3bd..3f547d3d52ca36 100644
--- a/.github/workflows/create-expo-app.yml
+++ b/.github/workflows/create-expo-app.yml
@@ -29,7 +29,7 @@ jobs:
node: [20, 22]
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 100
- name: ⬇️ Fetch commits from base branch
diff --git a/.github/workflows/create-expo-module.yml b/.github/workflows/create-expo-module.yml
index ab332e81ca2ec4..e1aaea2f66180f 100644
--- a/.github/workflows/create-expo-module.yml
+++ b/.github/workflows/create-expo-module.yml
@@ -29,7 +29,7 @@ jobs:
node: [20, 22]
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 100
- name: ⬇️ Fetch commits from base branch
diff --git a/.github/workflows/development-client-e2e.yml b/.github/workflows/development-client-e2e.yml
index 091042cf0104bd..602ec27a5e1172 100644
--- a/.github/workflows/development-client-e2e.yml
+++ b/.github/workflows/development-client-e2e.yml
@@ -25,7 +25,7 @@ jobs:
api-level: [36]
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: ➕ Add `bin` to GITHUB_PATH
run: echo "$(pwd)/bin" >> $GITHUB_PATH
- name: 🍺 Install required tools
@@ -34,7 +34,7 @@ jobs:
brew install applesimutils
brew install watchman
- name: 💎 Setup Ruby and install gems
- uses: ruby/setup-ruby@6aaa311d81eba98ae12eaffbcb63296ace0efcde # v1
+ uses: ruby/setup-ruby@12fd324f1d0b43274fdc8130f6980590a667c455 # v1
with:
bundler-cache: true
ruby-version: 3.2.2
@@ -71,7 +71,7 @@ jobs:
working-directory: packages/expo-dev-client
- name: 💾 Store artifacts of build failures
if: failure()
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: expo-dev-client-e2e-artifacts
path: packages/expo-dev-client/artifacts
diff --git a/.github/workflows/development-client-latest-e2e.yml b/.github/workflows/development-client-latest-e2e.yml
index d192dad6e94c6d..fd2d157850412b 100644
--- a/.github/workflows/development-client-latest-e2e.yml
+++ b/.github/workflows/development-client-latest-e2e.yml
@@ -18,7 +18,7 @@ jobs:
api-level: [36]
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: ➕ Add `bin` to GITHUB_PATH
run: echo "$(pwd)/bin" >> $GITHUB_PATH
- name: 🍺 Install required tools
@@ -27,7 +27,7 @@ jobs:
brew install applesimutils
brew install watchman
- name: 💎 Setup Ruby and install gems
- uses: ruby/setup-ruby@6aaa311d81eba98ae12eaffbcb63296ace0efcde # v1
+ uses: ruby/setup-ruby@12fd324f1d0b43274fdc8130f6980590a667c455 # v1
with:
bundler-cache: true
ruby-version: 3.2.2
@@ -69,7 +69,7 @@ jobs:
working-directory: packages/expo-dev-client
- name: 💾 Store artifacts of build failures
if: failure()
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: expo-dev-client-latest-e2e-artifacts
path: packages/expo-dev-client/artifacts
diff --git a/.github/workflows/development-client.yml b/.github/workflows/development-client.yml
index c26544bd4000e2..23e511e7978050 100644
--- a/.github/workflows/development-client.yml
+++ b/.github/workflows/development-client.yml
@@ -26,7 +26,7 @@ jobs:
ndk-version: [21.4.7075529]
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: ➕ Add `bin` to GITHUB_PATH
run: echo "$(pwd)/bin" >> $GITHUB_PATH
- name: 🔨 Install pnpm
@@ -90,7 +90,7 @@ jobs:
runs-on: macos-15
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: ➕ Add `bin` to GITHUB_PATH
run: echo "$(pwd)/bin" >> $GITHUB_PATH
- name: 🔨 Install pnpm
diff --git a/.github/workflows/docs-pr-destroy.yml b/.github/workflows/docs-pr-destroy.yml
index 847756070d755c..419070b83d909d 100644
--- a/.github/workflows/docs-pr-destroy.yml
+++ b/.github/workflows/docs-pr-destroy.yml
@@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: 👀 Checkout
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- name: ⬢ Setup Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
diff --git a/.github/workflows/docs-pr.yml b/.github/workflows/docs-pr.yml
index b3b2acd1a9d833..5713f9755922be 100644
--- a/.github/workflows/docs-pr.yml
+++ b/.github/workflows/docs-pr.yml
@@ -26,7 +26,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: 👀 Checkout
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- name: 🏗️ Setup pnpm
uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6
with:
@@ -80,15 +80,16 @@ jobs:
- name: 🚀 Deploy Docs website
if: contains(github.event.pull_request.labels.*.name, 'preview')
id: deploy
- uses: cloudflare/wrangler-action@9acf94ace14e7dc412b076f2c5c20b8ce93c79cd # v3
+ uses: cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 # v4.0.0
with:
apiToken: ${{ secrets.CLOUDFLARE_PAGES_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy --branch=pr-${{ github.event.pull_request.number }}
workingDirectory: docs
+ wranglerVersion: '3'
- name: 💬 Comment with preview URL
if: contains(github.event.pull_request.labels.*.name, 'preview')
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.EXPO_BOT_GITHUB_TOKEN }}
script: |
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index e0d01fa4171f71..b5aa1887093238 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -25,7 +25,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: 👀 Checkout
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
fetch-depth: 30000
- name: 🏗️ Setup pnpm
@@ -100,12 +100,13 @@ jobs:
- name: 🚀 Deploy Docs website
if: github.ref == 'refs/heads/main'
id: deploy
- uses: cloudflare/wrangler-action@9acf94ace14e7dc412b076f2c5c20b8ce93c79cd # v3
+ uses: cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 # v4.0.0
with:
apiToken: ${{ secrets.CLOUDFLARE_PAGES_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy --branch=main
workingDirectory: docs
+ wranglerVersion: '3'
- name: 🧹 Prune old production deployments
if: github.ref == 'refs/heads/main'
working-directory: docs
diff --git a/.github/workflows/expo-go-android-lint.yml b/.github/workflows/expo-go-android-lint.yml
index 401146b9de0656..f702d1c2ea1216 100644
--- a/.github/workflows/expo-go-android-lint.yml
+++ b/.github/workflows/expo-go-android-lint.yml
@@ -25,7 +25,7 @@ jobs:
GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx3072m -XX:MaxMetaspaceSize=1024m
steps:
- name: 👀 Check out repository
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
submodules: true
- name: 🔨 Install pnpm
diff --git a/.github/workflows/expotools.yml b/.github/workflows/expotools.yml
index 8db1cbbe1f21af..8ddc5efca04618 100644
--- a/.github/workflows/expotools.yml
+++ b/.github/workflows/expotools.yml
@@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🔨 Install pnpm
uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6
with:
diff --git a/.github/workflows/fingerprint.yml b/.github/workflows/fingerprint.yml
index 5f29988ad6b435..ca487c22e33a9b 100644
--- a/.github/workflows/fingerprint.yml
+++ b/.github/workflows/fingerprint.yml
@@ -31,7 +31,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 100
- name: 🔨 Install pnpm
@@ -125,7 +125,7 @@ jobs:
node ${{ github.workspace }}/packages/@expo/fingerprint/bin/cli.js fingerprint:generate > ${{ github.workspace }}/fingerprint-${{ matrix.os }}.json
}
- name: 📤 Upload fingerprint
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: fingerprint-${{ matrix.os }}
path: fingerprint-${{ matrix.os }}.json
@@ -135,17 +135,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: 📥 Download fingerprint (macos)
- uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v4
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v4
with:
name: fingerprint-macos-latest
- name: 📥 Download fingerprint (ubuntu)
- uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v4
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v4
with:
name: fingerprint-ubuntu-latest
- name: 📥 Download fingerprint (windows)
- uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v4
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v4
with:
name: fingerprint-windows-latest
diff --git a/.github/workflows/ios-prebuild-external-xcframeworks.yml b/.github/workflows/ios-prebuild-external-xcframeworks.yml
index aa164341787554..9476f37bb82015 100644
--- a/.github/workflows/ios-prebuild-external-xcframeworks.yml
+++ b/.github/workflows/ios-prebuild-external-xcframeworks.yml
@@ -47,7 +47,7 @@ jobs:
packages: ${{ steps.detect.outputs.packages }}
steps:
- name: Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
submodules: false
# Start shallow; the detect step fetches the event base if needed.
@@ -167,7 +167,7 @@ jobs:
flavor: [Debug, Release]
steps:
- name: Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Switch to Xcode 26.4.1
run: sudo xcode-select --switch /Applications/Xcode_26.4.1.app
@@ -209,7 +209,7 @@ jobs:
et prebuild $ARGS
- name: Upload XCFrameworks
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: xcframeworks-${{ matrix.flavor }}
path: packages/precompile/.build/*/output/**/${{ matrix.flavor == 'Debug' && 'debug' || 'release' }}/xcframeworks/*.tar.gz
@@ -226,7 +226,7 @@ jobs:
- name: Setup gcloud
if: ${{ success() && (github.event.inputs.publish == 'true' || github.event_name == 'push') && github.repository == 'expo/expo' }}
- uses: google-github-actions/setup-gcloud@e427ad8a34f8676edf47cf7d7925499adf3eb74f # v2
+ uses: google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db # v3.0.1
with:
project_id: exponentjs
diff --git a/.github/workflows/ios-static-frameworks.yml b/.github/workflows/ios-static-frameworks.yml
index bffae7009b732c..78eb328c3f42f6 100644
--- a/.github/workflows/ios-static-frameworks.yml
+++ b/.github/workflows/ios-static-frameworks.yml
@@ -18,13 +18,13 @@ jobs:
runs-on: macos-26
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🔨 Switch to Xcode 26.4.1
run: sudo xcode-select --switch /Applications/Xcode_26.4.1.app
- name: ➕ Add `bin` to GITHUB_PATH
run: echo "$(pwd)/bin" >> $GITHUB_PATH
- name: 💎 Setup Ruby
- uses: ruby/setup-ruby@6aaa311d81eba98ae12eaffbcb63296ace0efcde # v1
+ uses: ruby/setup-ruby@12fd324f1d0b43274fdc8130f6980590a667c455 # v1
with:
ruby-version: 3.2.2
- name: 💎 Install Ruby gems
diff --git a/.github/workflows/ios-unit-tests.yml b/.github/workflows/ios-unit-tests.yml
index 0454eeafa091a1..3617a2cb2329e3 100644
--- a/.github/workflows/ios-unit-tests.yml
+++ b/.github/workflows/ios-unit-tests.yml
@@ -41,13 +41,13 @@ jobs:
timeout-minutes: 75
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🔨 Switch to Xcode 26.4.1
run: sudo xcode-select --switch /Applications/Xcode_26.4.1.app
- name: ➕ Add `bin` to GITHUB_PATH
run: echo "$(pwd)/bin" >> $GITHUB_PATH
- name: 💎 Setup Ruby and install gems
- uses: ruby/setup-ruby@6aaa311d81eba98ae12eaffbcb63296ace0efcde # v1
+ uses: ruby/setup-ruby@12fd324f1d0b43274fdc8130f6980590a667c455 # v1
with:
bundler-cache: true
ruby-version: 3.2.2
@@ -98,7 +98,7 @@ jobs:
run: ccache -s -v
- name: 📤 Upload xcresult
if: always()
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ios-unit-tests-results
path: /tmp/ios-unit-tests-results
diff --git a/.github/workflows/issue-closed.yml b/.github/workflows/issue-closed.yml
index 3770e8826d4eca..076bfb17f7ea0c 100644
--- a/.github/workflows/issue-closed.yml
+++ b/.github/workflows/issue-closed.yml
@@ -10,7 +10,7 @@ jobs:
if: github.repository == 'expo/expo' && contains(github.event.issue.labels.*.name, 'Issue accepted')
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: ➕ Add `bin` to GITHUB_PATH
run: echo "$(pwd)/bin" >> $GITHUB_PATH
- name: 🔨 Install pnpm
diff --git a/.github/workflows/issue-opened.yml b/.github/workflows/issue-opened.yml
index 6775df4fd0188e..a4ef525b2ecb51 100644
--- a/.github/workflows/issue-opened.yml
+++ b/.github/workflows/issue-opened.yml
@@ -20,7 +20,7 @@ jobs:
text: 'This issue should be triaged ASAP: ${{ github.event.issue.html_url }}'
author_name: ${{ github.event.issue.user.login }}
fields: repo
- - uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
+ - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
if: ${{ contains( env.TRUSTED_USERS, github.event.issue.user.login ) }}
with:
github-token: ${{ secrets.EXPO_BOT_GITHUB_TOKEN }}
@@ -37,7 +37,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: ➕ Add `bin` to GITHUB_PATH
run: echo "$(pwd)/bin" >> $GITHUB_PATH
- name: 🔨 Install pnpm
diff --git a/.github/workflows/issue-stale.yml b/.github/workflows/issue-stale.yml
index 3e860b5bfecd5a..f1640aaa129171 100644
--- a/.github/workflows/issue-stale.yml
+++ b/.github/workflows/issue-stale.yml
@@ -9,7 +9,7 @@ jobs:
if: github.repository == 'expo/expo'
runs-on: ubuntu-24.04
steps:
- - uses: actions/stale@a20b814fb01b71def3bd6f56e7494d667ddf28da # v4
+ - uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # v10.3.0
with:
ascending: false
operations-per-run: 300
diff --git a/.github/workflows/issue-triage.yml b/.github/workflows/issue-triage.yml
index 3ef325678b615e..a335455cd2648d 100644
--- a/.github/workflows/issue-triage.yml
+++ b/.github/workflows/issue-triage.yml
@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-24.04
if: "${{ github.repository == 'expo/expo' && contains(github.event.label.name, 'incomplete issue: missing or invalid repro') }}"
steps:
- - uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
+ - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.EXPO_BOT_GITHUB_TOKEN }}
script: |
@@ -60,7 +60,7 @@ jobs:
runs-on: ubuntu-24.04
if: "${{ github.repository == 'expo/expo' && contains(github.event.label.name, 'incomplete issue: missing info') }}"
steps:
- - uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
+ - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.EXPO_BOT_GITHUB_TOKEN }}
script: |
@@ -96,7 +96,7 @@ jobs:
if: github.repository == 'expo/expo' && github.event_name == 'issues' && github.event.label.name == 'issue accepted'
steps:
- name: Comment on issue
- uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.EXPO_BOT_GITHUB_TOKEN }}
script: |
@@ -109,7 +109,7 @@ jobs:
However, we can’t promise any sort of timeline for resolution. We prioritize issues based on severity, breadth of impact, and alignment with our roadmap. If you’d like to help move it more quickly, you can continue to investigate it more deeply and/or you can open a pull request that fixes the cause.
`})
- name: Remove "Needs Review" label
- uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
try {
@@ -125,7 +125,7 @@ jobs:
}
}
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: ➕ Add `bin` to GITHUB_PATH
run: echo "$(pwd)/bin" >> $GITHUB_PATH
- name: 🔨 Install pnpm
@@ -153,7 +153,7 @@ jobs:
runs-on: ubuntu-24.04
if: "${{ github.repository == 'expo/expo' && contains(github.event.label.name, 'invalid issue: question') }}"
steps:
- - uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
+ - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.EXPO_BOT_GITHUB_TOKEN }}
script: |
@@ -181,7 +181,7 @@ jobs:
runs-on: ubuntu-24.04
if: "${{ github.repository == 'expo/expo' && contains(github.event.label.name, 'invalid issue: feature request') }}"
steps:
- - uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
+ - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.EXPO_BOT_GITHUB_TOKEN }}
script: |
@@ -204,7 +204,7 @@ jobs:
runs-on: ubuntu-24.04
if: "${{ github.repository == 'expo/expo' && contains(github.event.label.name, 'invalid issue: third-party library') }}"
steps:
- - uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
+ - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.EXPO_BOT_GITHUB_TOKEN }}
script: |
@@ -231,7 +231,7 @@ jobs:
runs-on: ubuntu-24.04
if: "${{ github.repository == 'expo/expo' && contains(github.event.label.name, 'invalid issue: react-native-core') }}"
steps:
- - uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
+ - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.EXPO_BOT_GITHUB_TOKEN }}
script: |
@@ -253,7 +253,7 @@ jobs:
runs-on: ubuntu-24.04
if: "${{ github.repository == 'expo/expo' && github.event.label.name == 'Comments on closed issue' }}"
steps:
- - uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
+ - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.EXPO_BOT_GITHUB_TOKEN }}
script: |
@@ -275,7 +275,7 @@ jobs:
runs-on: ubuntu-24.04
if: "${{ github.repository == 'expo/expo' && github.event.label.name == 'invalid issue: EAS Build troubleshooting' }}"
steps:
- - uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
+ - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.EXPO_BOT_GITHUB_TOKEN }}
script: |
@@ -297,7 +297,7 @@ jobs:
runs-on: ubuntu-24.04
if: "${{ github.repository == 'expo/expo' && github.event.label.name == 'Version bump PR' }}"
steps:
- - uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
+ - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.EXPO_BOT_GITHUB_TOKEN }}
script: |
diff --git a/.github/workflows/native-component-list.yml b/.github/workflows/native-component-list.yml
index 122c3cec95ac78..ea092fed92f242 100644
--- a/.github/workflows/native-component-list.yml
+++ b/.github/workflows/native-component-list.yml
@@ -27,7 +27,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🔨 Install pnpm
uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6
with:
diff --git a/.github/workflows/pr-contributor-labeler.yml b/.github/workflows/pr-contributor-labeler.yml
index 7c242358ec53b2..fe4433dae6d683 100644
--- a/.github/workflows/pr-contributor-labeler.yml
+++ b/.github/workflows/pr-contributor-labeler.yml
@@ -16,12 +16,12 @@ jobs:
if: github.repository == 'expo/expo'
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
sparse-checkout: |
.github/partner-allowlist.json
sparse-checkout-cone-mode: false
- - uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
+ - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
AFFILIATIONS: |
facebook=meta
diff --git a/.github/workflows/pr-labeler.yml b/.github/workflows/pr-labeler.yml
index 0a14173207359f..cbfc09fe6cb5ce 100644
--- a/.github/workflows/pr-labeler.yml
+++ b/.github/workflows/pr-labeler.yml
@@ -37,7 +37,7 @@ jobs:
actions: write
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 100
- name: ⬇️ Fetch commits from base branch
@@ -74,7 +74,7 @@ jobs:
echo "isPreviousFingerprintEmpty=${{ steps.fingerprint.outputs.previous-fingerprint == '' }}"
- name: 🏷️ Labeling PR
- uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
if: ${{ github.event_name == 'pull_request' && steps.fingerprint.outputs.previous-fingerprint != '' && steps.fingerprint.outputs.fingerprint-diff == '[]' }}
with:
script: |
@@ -97,7 +97,7 @@ jobs:
labels: ['bot: fingerprint compatible']
})
- name: 🏷️ Labeling PR
- uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
if: ${{ github.event_name == 'pull_request' && steps.fingerprint.outputs.previous-fingerprint != '' && steps.fingerprint.outputs.fingerprint-diff != '[]' }}
with:
script: |
@@ -121,7 +121,7 @@ jobs:
})
- name: 🔍 Find old comment if it exists
- uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3
+ uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad # v4.0.0
if: ${{ github.event_name == 'pull_request' }}
id: old_comment
with:
@@ -130,7 +130,7 @@ jobs:
body-includes:
- name: 💬 Add comment with fingerprint
if: ${{ github.event_name == 'pull_request' && steps.fingerprint.outputs.previous-fingerprint != '' && steps.fingerprint.outputs.fingerprint-diff != '[]' && steps.old_comment.outputs.comment-id == '' }}
- uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.EXPO_BOT_GITHUB_TOKEN }}
script: |
@@ -159,7 +159,7 @@ jobs:
});
- name: 💬 Update comment with fingerprint
if: ${{ github.event_name == 'pull_request' && steps.fingerprint.outputs.previous-fingerprint != '' && steps.fingerprint.outputs.fingerprint-diff != '[]' && steps.old_comment.outputs.comment-id != '' }}
- uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.EXPO_BOT_GITHUB_TOKEN }}
script: |
@@ -189,7 +189,7 @@ jobs:
});
- name: 💬 Delete comment with fingerprint
if: ${{ github.event_name == 'pull_request' && steps.fingerprint.outputs.previous-fingerprint != '' && steps.fingerprint.outputs.fingerprint-diff == '[]' && steps.old_comment.outputs.comment-id != '' }}
- uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.EXPO_BOT_GITHUB_TOKEN }}
script: |
diff --git a/.github/workflows/publish-canaries.yml b/.github/workflows/publish-canaries.yml
index fc8b4560fac38a..1f79d3cf4c588d 100644
--- a/.github/workflows/publish-canaries.yml
+++ b/.github/workflows/publish-canaries.yml
@@ -26,7 +26,7 @@ jobs:
NODE_AUTH_TOKEN: ${{ secrets.EXPO_BOT_NPM_TOKEN }}
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🔨 Switch to Xcode 26.4.1
run: sudo xcode-select --switch /Applications/Xcode_26.4.1.app
- name: 🔨 Add bin to GITHUB_PATH
diff --git a/.github/workflows/router.yml b/.github/workflows/router.yml
index 26455a74e21815..ae910047d0f3bb 100644
--- a/.github/workflows/router.yml
+++ b/.github/workflows/router.yml
@@ -24,7 +24,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 100
- name: 🔨 Install pnpm
diff --git a/.github/workflows/sdk-cutoff.yml b/.github/workflows/sdk-cutoff.yml
index cb15436545a65c..fde6c858349306 100644
--- a/.github/workflows/sdk-cutoff.yml
+++ b/.github/workflows/sdk-cutoff.yml
@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Cut release branch
run: |
git checkout -b sdk-${{ github.event.inputs.sdkVersion }}
diff --git a/.github/workflows/sdk.yml b/.github/workflows/sdk.yml
index 08af20caf8c2f7..2207357e1dfff5 100644
--- a/.github/workflows/sdk.yml
+++ b/.github/workflows/sdk.yml
@@ -35,10 +35,10 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 100
- - uses: dorny/paths-filter@d1c1ffe0248fe513906c8e24db8ea791d46f8590 # v3
+ - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: filter
with:
filters: |
@@ -86,7 +86,7 @@ jobs:
if: ${{ github.event_name == 'workflow_dispatch' || (github.event_name == 'schedule' && github.repository == 'expo/expo') }}
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 100
- name: 🔨 Install pnpm
diff --git a/.github/workflows/swift-format.yml b/.github/workflows/swift-format.yml
index 7d1d4eb5afdc05..6748f812d1e4f2 100644
--- a/.github/workflows/swift-format.yml
+++ b/.github/workflows/swift-format.yml
@@ -34,7 +34,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🐦 Install Swift ${{ env.SWIFT_VERSION }}
run: |
set -euo pipefail
@@ -52,7 +52,7 @@ jobs:
echo "/opt/swift/usr/bin" >> "$GITHUB_PATH"
- name: ♻️ Cache swift-format binary
id: swift-format-cache
- uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4
+ uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v4
with:
path: ~/.local/bin/swift-format
key: swift-format-${{ runner.os }}-${{ env.SWIFT_FORMAT_VERSION }}
diff --git a/.github/workflows/sync-template.yml b/.github/workflows/sync-template.yml
index cfbb6b559a2638..7a4482c73b1ed6 100644
--- a/.github/workflows/sync-template.yml
+++ b/.github/workflows/sync-template.yml
@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🚚 Rename .gitignore
run: mv ./templates/expo-template-default/gitignore ./templates/expo-template-default/.gitignore
- name: 🚀 Push changes to the template repository
diff --git a/.github/workflows/test-react-native-nightly.yml b/.github/workflows/test-react-native-nightly.yml
index b0c3de5d9a0336..160432ed4032c2 100644
--- a/.github/workflows/test-react-native-nightly.yml
+++ b/.github/workflows/test-react-native-nightly.yml
@@ -28,7 +28,7 @@ jobs:
runs-on: macos-26
steps:
- name: 👀 Checkout
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🔨 Switch to Xcode 26.4.1
run: sudo xcode-select --switch /Applications/Xcode_26.4.1.app
- name: 🍺 Install required tools
@@ -48,7 +48,7 @@ jobs:
node-version: 20
cache: 'pnpm'
- name: 💎 Setup Ruby
- uses: ruby/setup-ruby@6aaa311d81eba98ae12eaffbcb63296ace0efcde # v1
+ uses: ruby/setup-ruby@12fd324f1d0b43274fdc8130f6980590a667c455 # v1
with:
ruby-version: 3.2.2
- name: 💎 Install Ruby gems
@@ -74,7 +74,7 @@ jobs:
NODE_ENV: production
CONFIGURATION: ${{ matrix.build-type == 'release' && 'Release' || 'Debug' }}
- name: 📸 Upload builds
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ github.event_name == 'workflow_dispatch' && matrix.build-type == 'release' }} # Only archive release builds
with:
name: ios-builds-arch-${{ matrix.build-type }}
@@ -99,7 +99,7 @@ jobs:
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx4096m -XX:MaxMetaspaceSize=4096m"
steps:
- name: 👀 Checkout
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🧹 Cleanup GitHub Linux runner disk space
uses: ./.github/actions/cleanup-linux-disk-space
- name: 🏗️ Setup pnpm
@@ -134,7 +134,7 @@ jobs:
NODE_ENV: production
VARIANT: ${{ matrix.build-type == 'release' && 'Release' || 'Debug' }}
- name: 📸 Upload builds
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ github.event_name == 'workflow_dispatch' && matrix.build-type == 'release' }} # Only archive release builds
with:
name: android-builds-${{ matrix.build-type }}
diff --git a/.github/workflows/test-suite-lint.yml b/.github/workflows/test-suite-lint.yml
index 5804ecaaf0690f..8946ddc60b2884 100644
--- a/.github/workflows/test-suite-lint.yml
+++ b/.github/workflows/test-suite-lint.yml
@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🔨 Install pnpm
uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6
with:
diff --git a/.github/workflows/test-suite-macos.yml b/.github/workflows/test-suite-macos.yml
index a1c58cd27803ed..5581073557f1e9 100644
--- a/.github/workflows/test-suite-macos.yml
+++ b/.github/workflows/test-suite-macos.yml
@@ -55,7 +55,7 @@ jobs:
runs-on: macos-26
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🔨 Switch to Xcode 26.4.1
run: sudo xcode-select --switch /Applications/Xcode_26.4.1.app
- name: 🍺 Install required tools
@@ -64,7 +64,7 @@ jobs:
- name: ➕ Add `bin` to GITHUB_PATH
run: echo "$(pwd)/bin" >> $GITHUB_PATH
- name: 💎 Setup Ruby and install gems
- uses: ruby/setup-ruby@6aaa311d81eba98ae12eaffbcb63296ace0efcde # v1
+ uses: ruby/setup-ruby@12fd324f1d0b43274fdc8130f6980590a667c455 # v1
with:
bundler-cache: true
ruby-version: 3.2.2
@@ -109,12 +109,12 @@ jobs:
NODE_ENV: production
- name: 📄 Upload xcodebuild log
if: failure()
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: bare-expo-macos-xcodebuild-log
path: apps/bare-expo/xcodebuild.log
- name: 📸 Upload builds
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: bare-expo-macos-builds
path: apps/bare-expo/macos/build/BareExpo.app
diff --git a/.github/workflows/test-suite-nightly.yml b/.github/workflows/test-suite-nightly.yml
index f122840dfc9747..067914069e0832 100644
--- a/.github/workflows/test-suite-nightly.yml
+++ b/.github/workflows/test-suite-nightly.yml
@@ -24,7 +24,7 @@ jobs:
runs-on: macos-26
steps:
- name: 👀 Checkout
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🏗️ Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
@@ -37,7 +37,7 @@ jobs:
- name: ➕ Add `bin` to GITHUB_PATH
run: echo "$(pwd)/bin" >> $GITHUB_PATH
- name: 💎 Setup Ruby and install gems
- uses: ruby/setup-ruby@6aaa311d81eba98ae12eaffbcb63296ace0efcde # v1
+ uses: ruby/setup-ruby@12fd324f1d0b43274fdc8130f6980590a667c455 # v1
with:
bundler-cache: true
ruby-version: 3.2.2
@@ -73,7 +73,7 @@ jobs:
EXPO_DEBUG: 1
NODE_ENV: production
- name: 📸 Upload builds
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: bare-expo-ios-builds
path: apps/bare-expo/ios/build/BareExpo.app
@@ -91,7 +91,7 @@ jobs:
runs-on: macos-26
steps:
- name: 👀 Checkout
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🏗️ Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
@@ -101,7 +101,7 @@ jobs:
- name: ➕ Add `bin` to GITHUB_PATH
run: echo "$(pwd)/bin" >> $GITHUB_PATH
- name: 🌠 Download builds
- uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v4
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v4
with:
name: bare-expo-ios-builds
path: apps/bare-expo/ios/build/BareExpo.app
@@ -135,7 +135,7 @@ jobs:
working-directory: apps/bare-expo
- name: 📸 Store testing artifacts
if: always()
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: bare-expo-artifacts-ios
path: |
@@ -158,7 +158,7 @@ jobs:
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx4096m -XX:MaxMetaspaceSize=4096m"
steps:
- name: 👀 Checkout
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🧹 Cleanup GitHub Linux runner disk space
uses: ./.github/actions/cleanup-linux-disk-space
- name: 🏗️ Setup Bun
@@ -200,7 +200,7 @@ jobs:
run: ./scripts/start-android-e2e-test.ts --build
working-directory: apps/bare-expo
- name: 📸 Upload builds
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: bare-expo-android-builds
path: apps/bare-expo/android/app/build/outputs/apk
@@ -221,13 +221,13 @@ jobs:
api-level: [36]
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🏗️ Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: 1.x
- name: 🌠 Download builds
- uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v4
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v4
with:
name: bare-expo-android-builds
path: apps/bare-expo/android/app/build/outputs/apk
@@ -261,7 +261,7 @@ jobs:
working-directory: ./apps/bare-expo
- name: 📸 Store testing artifacts
if: always()
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: bare-expo-artifacts-android
path: |
diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml
index a0203a57b9003f..d3bc0fe248d66c 100644
--- a/.github/workflows/test-suite.yml
+++ b/.github/workflows/test-suite.yml
@@ -50,7 +50,7 @@ jobs:
should_test_android: ${{ steps.e2e.outputs.should_run_android }}
steps:
- name: 👀 Checkout
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🧐 Detect build-relevant platform changes
id: build
uses: ./.github/actions/detect-platform-change
@@ -144,7 +144,7 @@ jobs:
actions: write
steps:
- name: 👀 Checkout
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🏗️ Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
@@ -157,7 +157,7 @@ jobs:
- name: ➕ Add `bin` to GITHUB_PATH
run: echo "$(pwd)/bin" >> $GITHUB_PATH
- name: 💎 Setup Ruby and install gems
- uses: ruby/setup-ruby@6aaa311d81eba98ae12eaffbcb63296ace0efcde # v1
+ uses: ruby/setup-ruby@12fd324f1d0b43274fdc8130f6980590a667c455 # v1
with:
bundler-cache: true
ruby-version: 3.2.2
@@ -242,7 +242,7 @@ jobs:
runs-on: macos-26
steps:
- name: 👀 Checkout
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🏗️ Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
@@ -252,7 +252,7 @@ jobs:
- name: ➕ Add `bin` to GITHUB_PATH
run: echo "$(pwd)/bin" >> $GITHUB_PATH
- name: 🌠 Download builds
- uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v4
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v4
with:
name: bare-expo-ios-builds
path: apps/bare-expo/ios/build/BareExpo.app
@@ -309,7 +309,7 @@ jobs:
mv ~/.maestro ~/maestroArtifacts
- name: 📸 Store testing artifacts
if: always()
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
id: upload-artifacts
with:
name: bare-expo-artifacts-ios
@@ -349,7 +349,7 @@ jobs:
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx4096m -XX:MaxMetaspaceSize=4096m"
steps:
- name: 👀 Checkout
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🧹 Cleanup GitHub Linux runner disk space
uses: ./.github/actions/cleanup-linux-disk-space
- name: 🏗️ Setup Bun
@@ -441,7 +441,7 @@ jobs:
api-level: [36]
steps:
- name: 👀 Checkout
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 🧹 Cleanup GitHub Linux runner disk space
uses: ./.github/actions/cleanup-linux-disk-space
- name: 🏗️ Setup Bun
@@ -449,7 +449,7 @@ jobs:
with:
bun-version: 1.x
- name: 🌠 Download builds
- uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v4
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v4
with:
name: bare-expo-android-builds
path: apps/bare-expo/android/app/build/outputs/apk/release
@@ -496,7 +496,7 @@ jobs:
- name: 📸 Store testing artifacts
if: always()
id: upload-artifacts
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: bare-expo-artifacts-android
path: |
diff --git a/.github/workflows/validate-npm-owners.yml b/.github/workflows/validate-npm-owners.yml
index 3ae68ef9a908ee..78b31fc8aeb751 100644
--- a/.github/workflows/validate-npm-owners.yml
+++ b/.github/workflows/validate-npm-owners.yml
@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: 👀 Checkout
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: ➕ Add `bin` to GITHUB_PATH
run: echo "$(pwd)/bin" >> $GITHUB_PATH
- name: 🔨 Install pnpm
diff --git a/apps/bare-expo/MainNavigator.tsx b/apps/bare-expo/MainNavigator.tsx
index 6671dcfc38dd55..e8d413d95aaf37 100644
--- a/apps/bare-expo/MainNavigator.tsx
+++ b/apps/bare-expo/MainNavigator.tsx
@@ -1,5 +1,8 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
-import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
+import {
+ BottomTabNavigationOptions,
+ createBottomTabNavigator,
+} from '@react-navigation/bottom-tabs';
import { LinkingOptions } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { useTheme } from 'ThemeProvider';
@@ -12,7 +15,11 @@ import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { AppMetrics } from 'expo-observe';
import { ObserveNavigationContainer } from 'expo-observe/integrations/react-navigation';
-type NavigationRouteConfigMap = React.ComponentType;
+import Playground from './Playground';
+
+type NavigationRouteConfigMap = React.ComponentType & {
+ navigationOptions?: BottomTabNavigationOptions;
+};
const testSuiteRouteName = 'test-suite';
@@ -20,6 +27,7 @@ type RoutesConfig = {
[testSuiteRouteName]: NavigationRouteConfigMap;
apis?: NavigationRouteConfigMap;
components?: NavigationRouteConfigMap;
+ playground: NavigationRouteConfigMap;
};
type NativeComponentListExportsType = null | {
@@ -38,6 +46,7 @@ export function optionalRequire(requirer: () => { default: React.ComponentType }
}
const routes: RoutesConfig = {
[testSuiteRouteName]: TestStackNavigator,
+ playground: Playground,
};
// TODO vonovak there's potential for skipping the require of APIs tab as it's not used in CI
@@ -108,14 +117,16 @@ function TabNavigator() {
default: undefined,
})}
initialRouteName={testSuiteRouteName}>
- {Object.keys(routes).map((name) => (
-
- ))}
+ {Object.entries(routes).map(([name, component]) =>
+ component ? (
+
+ ) : null
+ )}
);
}
diff --git a/apps/bare-expo/Playground.tsx b/apps/bare-expo/Playground.tsx
new file mode 100644
index 00000000000000..fa3a792f1d5517
--- /dev/null
+++ b/apps/bare-expo/Playground.tsx
@@ -0,0 +1,47 @@
+import { useTheme } from 'ThemeProvider';
+import { TabBackground } from 'native-component-list/src/components/TabBackground';
+import TabIcon from 'native-component-list/src/components/TabIcon';
+import * as React from 'react';
+import { StyleSheet, Text, View } from 'react-native';
+
+// Empty scratch screen for isolating reproductions. Replace the contents with your repro code
+// and open it from the Playground tab. Revert your changes before committing unrelated work.
+export default function Playground() {
+ const { theme } = useTheme();
+ return (
+
+
+ Playground
+
+ Replace the contents of apps/bare-expo/Playground.tsx with your repro code.
+
+
+ );
+}
+
+Playground.navigationOptions = {
+ title: 'Playground',
+ tabBarLabel: 'Playground',
+ tabBarIcon: ({ focused }: { focused: boolean }) => {
+ return ;
+ },
+ tabBarBackground: () => ,
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ alignItems: 'center',
+ justifyContent: 'center',
+ gap: 8,
+ padding: 24,
+ },
+ title: {
+ fontSize: 20,
+ fontWeight: '600',
+ },
+ subtitle: {
+ fontSize: 14,
+ textAlign: 'center',
+ },
+});
diff --git a/apps/bare-expo/ios/Podfile b/apps/bare-expo/ios/Podfile
index 31686b0780ef78..53a9f69bc60d80 100644
--- a/apps/bare-expo/ios/Podfile
+++ b/apps/bare-expo/ios/Podfile
@@ -6,7 +6,7 @@ podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties
ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] ||= podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR']
ENV['RCT_USE_RN_DEP'] ||= podfile_properties['ios.buildReactNativeFromSource'] == 'true' ? '0' : '1'
-ENV['RCT_HERMES_V1_ENABLED'] ||= '1' if podfile_properties['expo.useHermesV1'] == 'true'
+ENV['RCT_HERMES_V1_ENABLED'] ||= '0' if podfile_properties['expo.useHermesV1'] == 'false'
ENV['RCT_USE_PREBUILT_RNCORE'] ||= podfile_properties['ios.buildReactNativeFromSource'] == 'true' ? '0' : '1'
ENV['EXPO_USE_PRECOMPILED_MODULES'] ||= '1' if podfile_properties['EXPO_USE_PRECOMPILED_MODULES'] != 'false'
diff --git a/apps/minimal-tester/ios/Podfile b/apps/minimal-tester/ios/Podfile
index 3e282405ff4657..8c595e9d0656f2 100644
--- a/apps/minimal-tester/ios/Podfile
+++ b/apps/minimal-tester/ios/Podfile
@@ -15,7 +15,7 @@ end
ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] ||= podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR']
ENV['RCT_USE_RN_DEP'] ||= podfile_properties['ios.buildReactNativeFromSource'] == 'true' ? '0' : '1'
ENV['RCT_USE_PREBUILT_RNCORE'] ||= podfile_properties['ios.buildReactNativeFromSource'] == 'true' ? '0' : '1'
-ENV['RCT_HERMES_V1_ENABLED'] ||= '1' if podfile_properties['expo.useHermesV1'] == 'true'
+ENV['RCT_HERMES_V1_ENABLED'] ||= '0' if podfile_properties['expo.useHermesV1'] == 'false'
ENV['EXPO_USE_PRECOMPILED_MODULES'] ||= '1' if podfile_properties['EXPO_USE_PRECOMPILED_MODULES'] != 'false'
platform :ios, podfile_properties['ios.deploymentTarget'] || '16.4'
diff --git a/apps/native-component-list/src/screens/MediaLibrary@Next/SortScreen.tsx b/apps/native-component-list/src/screens/MediaLibrary@Next/SortScreen.tsx
index 85e93d0193a7cc..fe8deb4e91de15 100644
--- a/apps/native-component-list/src/screens/MediaLibrary@Next/SortScreen.tsx
+++ b/apps/native-component-list/src/screens/MediaLibrary@Next/SortScreen.tsx
@@ -1,5 +1,11 @@
import { Image } from 'expo-image';
-import { MediaType, requestPermissionsAsync, Query, AssetField } from 'expo-media-library';
+import {
+ MediaType,
+ requestPermissionsAsync,
+ Query,
+ AssetField,
+ AssetInfo,
+} from 'expo-media-library';
import { useEffect, useState } from 'react';
import {
View,
@@ -16,25 +22,6 @@ const numColumns = 3;
const screenWidth = Dimensions.get('window').width;
const imageSize = screenWidth / numColumns - 8;
-type AssetInfo = {
- id: string;
- height: number;
- width: number;
- mediaType: MediaType;
- creationTime: number | null;
- modificationTime: number | null;
- duration: number | null;
-};
-
-const sortFields: AssetField[] = [
- AssetField.CREATION_TIME,
- AssetField.MODIFICATION_TIME,
- AssetField.MEDIA_TYPE,
- AssetField.HEIGHT,
- AssetField.WIDTH,
- AssetField.DURATION,
-];
-
const sortLabels: Record = {
[AssetField.CREATION_TIME]: 'Creation Time',
[AssetField.MODIFICATION_TIME]: 'Modification Time',
@@ -42,6 +29,7 @@ const sortLabels: Record = {
[AssetField.HEIGHT]: 'Height',
[AssetField.WIDTH]: 'Width',
[AssetField.DURATION]: 'Duration',
+ [AssetField.IS_FAVORITE]: 'Is Favorite',
};
const SortScreen = () => {
@@ -60,12 +48,15 @@ const SortScreen = () => {
const assetInfos = await Promise.all(
rawAssets.map(async (asset) => ({
id: asset.id,
+ filename: await asset.getFilename(),
+ uri: await asset.getUri(),
height: await asset.getHeight(),
width: await asset.getWidth(),
mediaType: await asset.getMediaType(),
creationTime: await asset.getCreationTime(),
modificationTime: await asset.getModificationTime(),
duration: await asset.getDuration(),
+ isFavorite: await asset.getFavorite(),
}))
);
setAssets(assetInfos);
@@ -133,6 +124,12 @@ const SortScreen = () => {
{item.mediaType}
);
+ case AssetField.IS_FAVORITE:
+ return (
+
+ {item.isFavorite ? 'Yes' : 'No'}
+
+ );
default:
return null;
@@ -142,6 +139,7 @@ const SortScreen = () => {
);
const cycleSortField = () => {
+ const sortFields = Object.values(AssetField);
const currentIndex = sortFields.indexOf(sortingBy);
const nextIndex = (currentIndex + 1) % sortFields.length;
setSortingBy(sortFields[nextIndex]);
diff --git a/apps/test-suite/tests/MediaLibraryNext.ts b/apps/test-suite/tests/MediaLibraryNext.ts
index 665d440a6327d9..049a96bca5afb0 100644
--- a/apps/test-suite/tests/MediaLibraryNext.ts
+++ b/apps/test-suite/tests/MediaLibraryNext.ts
@@ -640,6 +640,36 @@ export async function test(t) {
t.expect(await videoAsset.getMediaType()).toBe(MediaType.VIDEO);
});
+ t.it('isFavorite filter works correctly', async () => {
+ // given
+ const albumName = createAlbumName('isFavorite filter');
+ const favoriteAsset = await Asset.create(pngFile.localUri);
+ const nonFavoriteAsset = await Asset.create(jpgFile.localUri);
+ assetsContainer.push(favoriteAsset, nonFavoriteAsset);
+ const album = await Album.create(albumName, [favoriteAsset, nonFavoriteAsset]);
+ albumsContainer.push(album);
+ await favoriteAsset.setFavorite(true);
+
+ // when
+ const favoriteAssets = await new Query().album(album).eq(AssetField.IS_FAVORITE, true).exe();
+ const nonFavoriteAssets = await new Query()
+ .album(album)
+ .eq(AssetField.IS_FAVORITE, false)
+ .exe();
+
+ // then
+ if (Platform.OS === 'android' && Platform.Version < 29) {
+ // IS_FAVORITE filtering is a no-op pre-Q — both queries return all assets
+ t.expect(favoriteAssets.length).toBe(2);
+ t.expect(nonFavoriteAssets.length).toBe(2);
+ } else {
+ t.expect(favoriteAssets.map((a) => a.id)).toContain(favoriteAsset.id);
+ t.expect(favoriteAssets.map((a) => a.id)).not.toContain(nonFavoriteAsset.id);
+ t.expect(nonFavoriteAssets.map((a) => a.id)).toContain(nonFavoriteAsset.id);
+ t.expect(nonFavoriteAssets.map((a) => a.id)).not.toContain(favoriteAsset.id);
+ }
+ });
+
if (Platform.OS !== 'ios') {
t.it('mediatype audio works correctly', async () => {
// given
diff --git a/docs/pages/versions/unversioned/sdk/ui/drop-in-replacements/bottomsheet.mdx b/docs/pages/versions/unversioned/sdk/ui/drop-in-replacements/bottomsheet.mdx
index b9607a8e8dd356..bd87b804159a66 100644
--- a/docs/pages/versions/unversioned/sdk/ui/drop-in-replacements/bottomsheet.mdx
+++ b/docs/pages/versions/unversioned/sdk/ui/drop-in-replacements/bottomsheet.mdx
@@ -122,6 +122,39 @@ export default function DynamicBottomSheetExample() {
}
```
+### Scrollable React Native content
+
+The bottom sheet supports a React Native `FlatList` or `ScrollView` (or a high-performance list like [FlashList](https://shopify.github.io/flash-list/) or [Legend List](https://github.com/LegendApp/legend-list)) as a child for scrollable content. With `nestedScrollEnabled`, the list scrolls its own content first. Once it reaches the top edge, the remaining drag moves the sheet. `BottomSheetFlatList` and `BottomSheetScrollView` are also exported for `@gorhom/bottom-sheet` compatibility, but they are plain re-exports of the React Native components.
+
+```tsx BottomSheetScrollableExample.tsx
+import { useRef } from 'react';
+import { Button, FlatList, Text, View } from 'react-native';
+import BottomSheet from '@expo/ui/community/bottom-sheet';
+
+const DATA = Array.from({ length: 50 }, (_, i) => `Item ${i + 1}`);
+
+export default function BottomSheetScrollableExample() {
+ const sheetRef = useRef(null);
+
+ return (
+
+
+ );
+}
+```
+
## Platform behavior
`@gorhom/bottom-sheet` renders inline at the bottom of its parent view. This component uses native modal presentation on Android and iOS, and a drawer overlay on web.
diff --git a/docs/pages/versions/unversioned/sdk/ui/universal/bottomsheet.mdx b/docs/pages/versions/unversioned/sdk/ui/universal/bottomsheet.mdx
index a537619669f08e..fc6365f7e12b1c 100644
--- a/docs/pages/versions/unversioned/sdk/ui/universal/bottomsheet.mdx
+++ b/docs/pages/versions/unversioned/sdk/ui/universal/bottomsheet.mdx
@@ -100,6 +100,42 @@ export default function BottomSheetSnapPointsExample() {
> On Android, `{ fraction }` and `{ height }` snap to the nearest of `'half'` / `'full'` — the underlying `ModalBottomSheet` only supports two resting states. The partial state is only visible when content is tall enough to exceed Material's partial threshold; give the content an explicit height or fill the available space if you need the half state on short content.
+### Scrollable React Native content
+
+The bottom sheet supports a React Native list such as `FlatList` (or a high-performance list like [FlashList](https://shopify.github.io/flash-list/) or [Legend List](https://github.com/LegendApp/legend-list)) as a child when wrapped in [`RNHostView`](rnhostview). [`snapPoints`](#snappoints) sizes the sheet, and the list scrolls within that height. With `nestedScrollEnabled`, the list scrolls its own content first; once it reaches the top edge, the remaining drag moves the sheet.
+
+```tsx BottomSheetScrollableExample.tsx
+import { useState } from 'react';
+import { FlatList, Text } from 'react-native';
+import { Host, BottomSheet, Button, RNHostView } from '@expo/ui';
+
+const DATA = Array.from({ length: 50 }, (_, i) => `Item ${i + 1}`);
+
+export default function BottomSheetScrollableExample() {
+ const [isPresented, setIsPresented] = useState(false);
+
+ return (
+
+
+ );
+}
+```
+
## API
```tsx
diff --git a/docs/pages/versions/v56.0.0/sdk/ui/drop-in-replacements/bottomsheet.mdx b/docs/pages/versions/v56.0.0/sdk/ui/drop-in-replacements/bottomsheet.mdx
index 24d4ab4a304325..6a8315ffdfaa51 100644
--- a/docs/pages/versions/v56.0.0/sdk/ui/drop-in-replacements/bottomsheet.mdx
+++ b/docs/pages/versions/v56.0.0/sdk/ui/drop-in-replacements/bottomsheet.mdx
@@ -122,6 +122,39 @@ export default function DynamicBottomSheetExample() {
}
```
+### Scrollable React Native content
+
+The bottom sheet supports a React Native `FlatList` or `ScrollView` (or a high-performance list like [FlashList](https://shopify.github.io/flash-list/) or [Legend List](https://github.com/LegendApp/legend-list)) as a child for scrollable content. With `nestedScrollEnabled`, the list scrolls its own content first; once it reaches the top edge, the remaining drag moves the sheet. `BottomSheetFlatList` and `BottomSheetScrollView` are also exported for `@gorhom/bottom-sheet` compatibility, but they are plain re-exports of the React Native components.
+
+```tsx BottomSheetScrollableExample.tsx
+import { useRef } from 'react';
+import { Button, FlatList, Text, View } from 'react-native';
+import BottomSheet from '@expo/ui/community/bottom-sheet';
+
+const DATA = Array.from({ length: 50 }, (_, i) => `Item ${i + 1}`);
+
+export default function BottomSheetScrollableExample() {
+ const sheetRef = useRef(null);
+
+ return (
+
+
+ );
+}
+```
+
## Platform behavior
`@gorhom/bottom-sheet` renders inline at the bottom of its parent view. This component uses native modal presentation on Android and iOS, and a drawer overlay on web.
diff --git a/docs/pages/versions/v56.0.0/sdk/ui/universal/bottomsheet.mdx b/docs/pages/versions/v56.0.0/sdk/ui/universal/bottomsheet.mdx
index a537619669f08e..fc6365f7e12b1c 100644
--- a/docs/pages/versions/v56.0.0/sdk/ui/universal/bottomsheet.mdx
+++ b/docs/pages/versions/v56.0.0/sdk/ui/universal/bottomsheet.mdx
@@ -100,6 +100,42 @@ export default function BottomSheetSnapPointsExample() {
> On Android, `{ fraction }` and `{ height }` snap to the nearest of `'half'` / `'full'` — the underlying `ModalBottomSheet` only supports two resting states. The partial state is only visible when content is tall enough to exceed Material's partial threshold; give the content an explicit height or fill the available space if you need the half state on short content.
+### Scrollable React Native content
+
+The bottom sheet supports a React Native list such as `FlatList` (or a high-performance list like [FlashList](https://shopify.github.io/flash-list/) or [Legend List](https://github.com/LegendApp/legend-list)) as a child when wrapped in [`RNHostView`](rnhostview). [`snapPoints`](#snappoints) sizes the sheet, and the list scrolls within that height. With `nestedScrollEnabled`, the list scrolls its own content first; once it reaches the top edge, the remaining drag moves the sheet.
+
+```tsx BottomSheetScrollableExample.tsx
+import { useState } from 'react';
+import { FlatList, Text } from 'react-native';
+import { Host, BottomSheet, Button, RNHostView } from '@expo/ui';
+
+const DATA = Array.from({ length: 50 }, (_, i) => `Item ${i + 1}`);
+
+export default function BottomSheetScrollableExample() {
+ const [isPresented, setIsPresented] = useState(false);
+
+ return (
+
+
+ );
+}
+```
+
## API
```tsx
diff --git a/packages/@expo/cli/CHANGELOG.md b/packages/@expo/cli/CHANGELOG.md
index 0fbd252df6e175..0b4a5ec82f9e4f 100644
--- a/packages/@expo/cli/CHANGELOG.md
+++ b/packages/@expo/cli/CHANGELOG.md
@@ -6,11 +6,13 @@
### 🎉 New features
+- Add option to specify targets to use with inline modules ([#46698](https://github.com/expo/expo/pull/46698) by [@HubertBer](https://github.com/HubertBer))
- Support Bundler-managed CocoaPods installations ([#43605](https://github.com/expo/expo/pull/43605) by [@tiwari91](https://github.com/tiwari91), [@kitten](https://github.com/kitten))
- Support Device Hub as Simulator replacement for Xcode 27+ ([#46757](https://github.com/expo/expo/pull/46757) by [@byCedric](https://github.com/byCedric), [@GersonRocha9](https://github.com/GersonRocha9))
### 🐛 Bug fixes
+- Focus the booted device in Device Hub using its `devices://` deep link instead of only bringing the app forward. ([#46809](https://github.com/expo/expo/pull/46809) by [@krystofwoldrich](https://github.com/krystofwoldrich))
- Symbolicate web error stacks in the dev server console. ([#46584](https://github.com/expo/expo/pull/46584) by [@krystofwoldrich](https://github.com/krystofwoldrich))
- Disable sextant QR code rendering for Windows Terminal ([#46455](https://github.com/expo/expo/pull/46455) by [@kitten](https://github.com/kitten))
- Use favicon from app config when SSR is enabled ([#46570](https://github.com/expo/expo/pull/46570) by [@hassankhan](https://github.com/hassankhan))
diff --git a/packages/@expo/cli/src/prebuild/prebuildAsync.ts b/packages/@expo/cli/src/prebuild/prebuildAsync.ts
index b6fd2653147ddd..a69c099c28b588 100644
--- a/packages/@expo/cli/src/prebuild/prebuildAsync.ts
+++ b/packages/@expo/cli/src/prebuild/prebuildAsync.ts
@@ -187,6 +187,8 @@ export async function prebuildAsync(
if (inlineModules && options.platforms.includes('ios')) {
await updateXcodeProject(projectRoot, {
watchedDirectories: inlineModules.watchedDirectories ?? [],
+ xcodeProjectTargets: inlineModules.xcodeProjectTargets,
+ name: exp.name,
});
}
diff --git a/packages/@expo/cli/src/start/platforms/ios/__tests__/ensureSimulatorAppRunning-test.ts b/packages/@expo/cli/src/start/platforms/ios/__tests__/ensureSimulatorAppRunning-test.ts
index dbfbbdb98b76e6..c00380c6fbf778 100644
--- a/packages/@expo/cli/src/start/platforms/ios/__tests__/ensureSimulatorAppRunning-test.ts
+++ b/packages/@expo/cli/src/start/platforms/ios/__tests__/ensureSimulatorAppRunning-test.ts
@@ -34,6 +34,47 @@ it('should activate the window when Simulator.app is not running', async () => {
]);
});
+it('should open DeviceHub focused on the device via deep link when Simulator.app is unavailable', async () => {
+ jest
+ .mocked(spawnAppleScriptAsync)
+ .mockResolvedValueOnce({ stdout: '0\n' } as any)
+ .mockResolvedValueOnce({ stdout: '1\n' } as any);
+
+ // Xcode 27+ ships DeviceHub instead of Simulator.app, so `open -a Simulator` fails.
+ jest
+ .mocked(spawnAsync)
+ .mockRejectedValueOnce(new Error("Unable to find application named 'Simulator'"))
+ .mockResolvedValueOnce({} as any);
+
+ await ensureSimulatorAppRunningAsync({ udid: '123' });
+
+ expect(spawnAsync).toHaveBeenNthCalledWith(1, 'open', [
+ '-a',
+ 'Simulator',
+ '--args',
+ '-CurrentDeviceUDID',
+ '123',
+ ]);
+ expect(spawnAsync).toHaveBeenNthCalledWith(2, 'open', ['devices://device/open?id=123']);
+});
+
+it('should fall back to opening DeviceHub without a device when no udid is provided', async () => {
+ jest
+ .mocked(spawnAppleScriptAsync)
+ .mockResolvedValueOnce({ stdout: '0\n' } as any)
+ .mockResolvedValueOnce({ stdout: '1\n' } as any);
+
+ jest
+ .mocked(spawnAsync)
+ .mockRejectedValueOnce(new Error("Unable to find application named 'Simulator'"))
+ .mockResolvedValueOnce({} as any);
+
+ await ensureSimulatorAppRunningAsync({});
+
+ expect(spawnAsync).toHaveBeenNthCalledWith(1, 'open', ['-a', 'Simulator']);
+ expect(spawnAsync).toHaveBeenNthCalledWith(2, 'open', ['-a', 'DeviceHub']);
+});
+
it('should throw a timeout warning when Simulator.app takes too long to start', async () => {
jest.mocked(spawnAppleScriptAsync).mockRejectedValue(new Error('Application isn’t running'));
diff --git a/packages/@expo/cli/src/start/platforms/ios/ensureSimulatorAppRunning.ts b/packages/@expo/cli/src/start/platforms/ios/ensureSimulatorAppRunning.ts
index 808e9832df5254..38cb6ea764648f 100644
--- a/packages/@expo/cli/src/start/platforms/ios/ensureSimulatorAppRunning.ts
+++ b/packages/@expo/cli/src/start/platforms/ios/ensureSimulatorAppRunning.ts
@@ -71,8 +71,13 @@ async function openSimulatorAppAsync(device: { udid?: string }) {
}
await spawnAsync('open', args);
} catch {
- // Device Hub does not allow us to focus to the right device
- await spawnAsync('open', ['-a', 'DeviceHub']).catch(() => {
+ // Xcode 27+ replaces Simulator.app with DeviceHub, so `open -a Simulator` fails.
+ // DeviceHub registers the `devices://` URL scheme, which lets us focus the right
+ // device by its UDID — `open -a DeviceHub` can only bring the app forward.
+ const deviceHubArgs = device.udid
+ ? [`devices://device/open?id=${device.udid}`]
+ : ['-a', 'DeviceHub'];
+ await spawnAsync('open', deviceHubArgs).catch(() => {
// Noop - we can't do much more here
});
}
diff --git a/packages/@expo/config-plugins/src/ios/__tests__/__snapshots__/BundleIdentifier-test.ts.snap b/packages/@expo/config-plugins/src/ios/__tests__/__snapshots__/BundleIdentifier-test.ts.snap
index 64fec3276c971f..94b0cb981f59c0 100644
--- a/packages/@expo/config-plugins/src/ios/__tests__/__snapshots__/BundleIdentifier-test.ts.snap
+++ b/packages/@expo/config-plugins/src/ios/__tests__/__snapshots__/BundleIdentifier-test.ts.snap
@@ -14,6 +14,7 @@ exports[`BundleIdentifier module setBundleIdentifierForPbxproj sets the bundle i
3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */; };
BB2F792D24A3F905000567C9 /* Expo.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB2F792C24A3F905000567C9 /* Expo.plist */; };
F11748422D0307B40044C1D9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F11748412D0307B40044C1D9 /* AppDelegate.swift */; };
+ F11748442D0307B40044C1D9 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F11748432D0307B40044C1D9 /* SceneDelegate.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@@ -24,6 +25,7 @@ exports[`BundleIdentifier module setBundleIdentifierForPbxproj sets the bundle i
BB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Expo.plist; sourceTree = ""; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
F11748412D0307B40044C1D9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = HelloWorld/AppDelegate.swift; sourceTree = ""; };
+ F11748432D0307B40044C1D9 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SceneDelegate.swift; path = HelloWorld/SceneDelegate.swift; sourceTree = ""; };
F11748442D0722820044C1D9 /* HelloWorld-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "HelloWorld-Bridging-Header.h"; path = "HelloWorld/HelloWorld-Bridging-Header.h"; sourceTree = ""; };
/* End PBXFileReference section */
@@ -42,6 +44,7 @@ exports[`BundleIdentifier module setBundleIdentifierForPbxproj sets the bundle i
isa = PBXGroup;
children = (
F11748412D0307B40044C1D9 /* AppDelegate.swift */,
+ F11748432D0307B40044C1D9 /* SceneDelegate.swift */,
F11748442D0722820044C1D9 /* HelloWorld-Bridging-Header.h */,
BB2F792B24A3F905000567C9 /* Supporting */,
13B07FB51A68108700A75B9A /* Images.xcassets */,
@@ -233,6 +236,7 @@ exports[`BundleIdentifier module setBundleIdentifierForPbxproj sets the bundle i
buildActionMask = 2147483647;
files = (
F11748422D0307B40044C1D9 /* AppDelegate.swift in Sources */,
+ F11748442D0307B40044C1D9 /* SceneDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/packages/@expo/config-plugins/src/ios/__tests__/__snapshots__/DevelopmentTeam-test.ts.snap b/packages/@expo/config-plugins/src/ios/__tests__/__snapshots__/DevelopmentTeam-test.ts.snap
index 4f7c90b0380978..2635cde0b6edb3 100644
--- a/packages/@expo/config-plugins/src/ios/__tests__/__snapshots__/DevelopmentTeam-test.ts.snap
+++ b/packages/@expo/config-plugins/src/ios/__tests__/__snapshots__/DevelopmentTeam-test.ts.snap
@@ -14,6 +14,7 @@ exports[`DevelopmentTeam module setDevelopmentTeamForPbxproj adds the \`DEVELOPM
3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */; };
BB2F792D24A3F905000567C9 /* Expo.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB2F792C24A3F905000567C9 /* Expo.plist */; };
F11748422D0307B40044C1D9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F11748412D0307B40044C1D9 /* AppDelegate.swift */; };
+ F11748442D0307B40044C1D9 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F11748432D0307B40044C1D9 /* SceneDelegate.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@@ -24,6 +25,7 @@ exports[`DevelopmentTeam module setDevelopmentTeamForPbxproj adds the \`DEVELOPM
BB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Expo.plist; sourceTree = ""; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
F11748412D0307B40044C1D9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = HelloWorld/AppDelegate.swift; sourceTree = ""; };
+ F11748432D0307B40044C1D9 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SceneDelegate.swift; path = HelloWorld/SceneDelegate.swift; sourceTree = ""; };
F11748442D0722820044C1D9 /* HelloWorld-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "HelloWorld-Bridging-Header.h"; path = "HelloWorld/HelloWorld-Bridging-Header.h"; sourceTree = ""; };
/* End PBXFileReference section */
@@ -42,6 +44,7 @@ exports[`DevelopmentTeam module setDevelopmentTeamForPbxproj adds the \`DEVELOPM
isa = PBXGroup;
children = (
F11748412D0307B40044C1D9 /* AppDelegate.swift */,
+ F11748432D0307B40044C1D9 /* SceneDelegate.swift */,
F11748442D0722820044C1D9 /* HelloWorld-Bridging-Header.h */,
BB2F792B24A3F905000567C9 /* Supporting */,
13B07FB51A68108700A75B9A /* Images.xcassets */,
@@ -233,6 +236,7 @@ exports[`DevelopmentTeam module setDevelopmentTeamForPbxproj adds the \`DEVELOPM
buildActionMask = 2147483647;
files = (
F11748422D0307B40044C1D9 /* AppDelegate.swift in Sources */,
+ F11748442D0307B40044C1D9 /* SceneDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/packages/@expo/config-plugins/src/ios/__tests__/__snapshots__/Maps-test.ts.snap b/packages/@expo/config-plugins/src/ios/__tests__/__snapshots__/Maps-test.ts.snap
index 5e61562227eeaa..29a80ab8b2c902 100644
--- a/packages/@expo/config-plugins/src/ios/__tests__/__snapshots__/Maps-test.ts.snap
+++ b/packages/@expo/config-plugins/src/ios/__tests__/__snapshots__/Maps-test.ts.snap
@@ -11,7 +11,7 @@ import GoogleMaps
#endif
// @generated end react-native-maps-import
@main
-class AppDelegate: ExpoAppDelegate {
+class AppDelegate: ExpoAppDelegate, ExpoReactNativeFactoryProvider {
var window: UIWindow?
var reactNativeDelegate: ExpoReactNativeFactoryDelegate?
@@ -28,35 +28,10 @@ class AppDelegate: ExpoAppDelegate {
reactNativeDelegate = delegate
reactNativeFactory = factory
-#if os(iOS) || os(tvOS)
- window = UIWindow(frame: UIScreen.main.bounds)
- factory.startReactNative(
- withModuleName: "main",
- in: window,
- launchOptions: launchOptions)
-#endif
-
+ // The window is created and React Native is started by \`SceneDelegate\` under the
+ // scene-based life cycle (required by the iOS 27 SDK).
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
-
- // Linking API
- public override func application(
- _ app: UIApplication,
- open url: URL,
- options: [UIApplication.OpenURLOptionsKey: Any] = [:]
- ) -> Bool {
- return super.application(app, open: url, options: options) || RCTLinkingManager.application(app, open: url, options: options)
- }
-
- // Universal Links
- public override func application(
- _ application: UIApplication,
- continue userActivity: NSUserActivity,
- restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
- ) -> Bool {
- let result = RCTLinkingManager.application(application, continue: userActivity, restorationHandler: restorationHandler)
- return super.application(application, continue: userActivity, restorationHandler: restorationHandler) || result
- }
}
class ReactNativeDelegate: ExpoReactNativeFactoryDelegate {
@@ -84,7 +59,7 @@ import React
import ReactAppDependencyProvider
@main
-class AppDelegate: ExpoAppDelegate {
+class AppDelegate: ExpoAppDelegate, ExpoReactNativeFactoryProvider {
var window: UIWindow?
var reactNativeDelegate: ExpoReactNativeFactoryDelegate?
@@ -101,14 +76,8 @@ class AppDelegate: ExpoAppDelegate {
reactNativeDelegate = delegate
reactNativeFactory = factory
-#if os(iOS) || os(tvOS)
- window = UIWindow(frame: UIScreen.main.bounds)
- factory.startReactNative(
- withModuleName: "main",
- in: window,
- launchOptions: launchOptions)
-#endif
-
+ // The window is created and React Native is started by \`SceneDelegate\` under the
+ // scene-based life cycle (required by the iOS 27 SDK).
// @generated begin react-native-maps-init - expo prebuild (DO NOT MODIFY) sync-d167568d212e7a4ec24615c397330e087bc93758
#if canImport(GoogleMaps)
GMSServices.provideAPIKey("mykey")
@@ -116,25 +85,6 @@ GMSServices.provideAPIKey("mykey")
// @generated end react-native-maps-init
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
-
- // Linking API
- public override func application(
- _ app: UIApplication,
- open url: URL,
- options: [UIApplication.OpenURLOptionsKey: Any] = [:]
- ) -> Bool {
- return super.application(app, open: url, options: options) || RCTLinkingManager.application(app, open: url, options: options)
- }
-
- // Universal Links
- public override func application(
- _ application: UIApplication,
- continue userActivity: NSUserActivity,
- restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
- ) -> Bool {
- let result = RCTLinkingManager.application(application, continue: userActivity, restorationHandler: restorationHandler)
- return super.application(application, continue: userActivity, restorationHandler: restorationHandler) || result
- }
}
class ReactNativeDelegate: ExpoReactNativeFactoryDelegate {
@@ -162,7 +112,7 @@ import React
import ReactAppDependencyProvider
@main
-class AppDelegate: ExpoAppDelegate {
+class AppDelegate: ExpoAppDelegate, ExpoReactNativeFactoryProvider {
var window: UIWindow?
var reactNativeDelegate: ExpoReactNativeFactoryDelegate?
@@ -179,14 +129,8 @@ class AppDelegate: ExpoAppDelegate {
reactNativeDelegate = delegate
reactNativeFactory = factory
-#if os(iOS) || os(tvOS)
- window = UIWindow(frame: UIScreen.main.bounds)
- factory.startReactNative(
- withModuleName: "main",
- in: window,
- launchOptions: launchOptions)
-#endif
-
+ // The window is created and React Native is started by \`SceneDelegate\` under the
+ // scene-based life cycle (required by the iOS 27 SDK).
// @generated begin react-native-maps-init - expo prebuild (DO NOT MODIFY) sync-d167568d212e7a4ec24615c397330e087bc93758
#if canImport(GoogleMaps)
GMSServices.provideAPIKey("mykey")
@@ -194,25 +138,6 @@ GMSServices.provideAPIKey("mykey")
// @generated end react-native-maps-init
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
-
- // Linking API
- public override func application(
- _ app: UIApplication,
- open url: URL,
- options: [UIApplication.OpenURLOptionsKey: Any] = [:]
- ) -> Bool {
- return super.application(app, open: url, options: options) || RCTLinkingManager.application(app, open: url, options: options)
- }
-
- // Universal Links
- public override func application(
- _ application: UIApplication,
- continue userActivity: NSUserActivity,
- restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
- ) -> Bool {
- let result = RCTLinkingManager.application(application, continue: userActivity, restorationHandler: restorationHandler)
- return super.application(application, continue: userActivity, restorationHandler: restorationHandler) || result
- }
}
class ReactNativeDelegate: ExpoReactNativeFactoryDelegate {
@@ -252,7 +177,7 @@ end
ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] ||= podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR']
ENV['RCT_USE_RN_DEP'] ||= podfile_properties['ios.buildReactNativeFromSource'] == 'true' ? '0' : '1'
ENV['RCT_USE_PREBUILT_RNCORE'] ||= podfile_properties['ios.buildReactNativeFromSource'] == 'true' ? '0' : '1'
-ENV['RCT_HERMES_V1_ENABLED'] ||= '1' if podfile_properties['expo.useHermesV1'] == 'true'
+ENV['RCT_HERMES_V1_ENABLED'] ||= '0' if podfile_properties['expo.useHermesV1'] == 'false'
ENV['EXPO_USE_PRECOMPILED_MODULES'] ||= '1' if podfile_properties['EXPO_USE_PRECOMPILED_MODULES'] != 'false'
platform :ios, podfile_properties['ios.deploymentTarget'] || '16.4'
diff --git a/packages/@expo/config-plugins/src/ios/__tests__/__snapshots__/ProvisioningProfile-test.ts.snap b/packages/@expo/config-plugins/src/ios/__tests__/__snapshots__/ProvisioningProfile-test.ts.snap
index c5f4d1948dc91a..9f2faca9fd39bf 100644
--- a/packages/@expo/config-plugins/src/ios/__tests__/__snapshots__/ProvisioningProfile-test.ts.snap
+++ b/packages/@expo/config-plugins/src/ios/__tests__/__snapshots__/ProvisioningProfile-test.ts.snap
@@ -1328,6 +1328,7 @@ exports[`ProvisioningProfile module setProvisioningProfileForPbxproj single targ
3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */; };
BB2F792D24A3F905000567C9 /* Expo.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB2F792C24A3F905000567C9 /* Expo.plist */; };
F11748422D0307B40044C1D9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F11748412D0307B40044C1D9 /* AppDelegate.swift */; };
+ F11748442D0307B40044C1D9 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F11748432D0307B40044C1D9 /* SceneDelegate.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@@ -1338,6 +1339,7 @@ exports[`ProvisioningProfile module setProvisioningProfileForPbxproj single targ
BB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Expo.plist; sourceTree = ""; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
F11748412D0307B40044C1D9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = HelloWorld/AppDelegate.swift; sourceTree = ""; };
+ F11748432D0307B40044C1D9 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SceneDelegate.swift; path = HelloWorld/SceneDelegate.swift; sourceTree = ""; };
F11748442D0722820044C1D9 /* HelloWorld-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "HelloWorld-Bridging-Header.h"; path = "HelloWorld/HelloWorld-Bridging-Header.h"; sourceTree = ""; };
/* End PBXFileReference section */
@@ -1356,6 +1358,7 @@ exports[`ProvisioningProfile module setProvisioningProfileForPbxproj single targ
isa = PBXGroup;
children = (
F11748412D0307B40044C1D9 /* AppDelegate.swift */,
+ F11748432D0307B40044C1D9 /* SceneDelegate.swift */,
F11748442D0722820044C1D9 /* HelloWorld-Bridging-Header.h */,
BB2F792B24A3F905000567C9 /* Supporting */,
13B07FB51A68108700A75B9A /* Images.xcassets */,
@@ -1549,6 +1552,7 @@ exports[`ProvisioningProfile module setProvisioningProfileForPbxproj single targ
buildActionMask = 2147483647;
files = (
F11748422D0307B40044C1D9 /* AppDelegate.swift in Sources */,
+ F11748442D0307B40044C1D9 /* SceneDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/packages/@expo/config-types/build/ExpoConfig.d.ts b/packages/@expo/config-types/build/ExpoConfig.d.ts
index f4a0219f54ad56..f685640d0a505a 100644
--- a/packages/@expo/config-types/build/ExpoConfig.d.ts
+++ b/packages/@expo/config-types/build/ExpoConfig.d.ts
@@ -270,6 +270,10 @@ export interface ExpoConfig {
* List of directories watched for inline modules.
*/
watchedDirectories: string[];
+ /**
+ * List of targets to which inline modules files are added. If undefined defaults to the main target only.
+ */
+ xcodeProjectTargets?: string[];
};
};
/**
diff --git a/packages/@expo/config-types/src/ExpoConfig.ts b/packages/@expo/config-types/src/ExpoConfig.ts
index e75edf8e51e3ba..cec38261f70a3b 100644
--- a/packages/@expo/config-types/src/ExpoConfig.ts
+++ b/packages/@expo/config-types/src/ExpoConfig.ts
@@ -284,6 +284,10 @@ export interface ExpoConfig {
* List of directories watched for inline modules.
*/
watchedDirectories: string[];
+ /**
+ * List of targets to which inline modules files are added. If undefined defaults to the main target only.
+ */
+ xcodeProjectTargets?: string[];
};
};
/**
diff --git a/packages/@expo/config-types/src/__tests__/fixtures/ExpoConfig.backup.ts b/packages/@expo/config-types/src/__tests__/fixtures/ExpoConfig.backup.ts
index e75edf8e51e3ba..cec38261f70a3b 100644
--- a/packages/@expo/config-types/src/__tests__/fixtures/ExpoConfig.backup.ts
+++ b/packages/@expo/config-types/src/__tests__/fixtures/ExpoConfig.backup.ts
@@ -284,6 +284,10 @@ export interface ExpoConfig {
* List of directories watched for inline modules.
*/
watchedDirectories: string[];
+ /**
+ * List of targets to which inline modules files are added. If undefined defaults to the main target only.
+ */
+ xcodeProjectTargets?: string[];
};
};
/**
diff --git a/packages/@expo/inline-modules/CHANGELOG.md b/packages/@expo/inline-modules/CHANGELOG.md
index d3c8c0eeae9fe6..b16c6fd4f2303a 100644
--- a/packages/@expo/inline-modules/CHANGELOG.md
+++ b/packages/@expo/inline-modules/CHANGELOG.md
@@ -6,6 +6,8 @@
### 🎉 New features
+- Add option to specify targets to use with inline modules ([#46698](https://github.com/expo/expo/pull/46698) by [@HubertBer](https://github.com/HubertBer))
+
### 🐛 Bug fixes
- Fix inline modules not regiestering for all of the targets on iOS, leading to [compilation errors when using expo-widgets #46219](https://github.com/expo/expo/issues/46219) ([#XXXXXX](https://github.com/expo/expo/pull/XXXXXX) by [@HubertBer](https://github.com/HubertBer)) ([#46484](https://github.com/expo/expo/pull/46484) by [@HubertBer](https://github.com/HubertBer))
diff --git a/packages/@expo/inline-modules/build/xcodeProjectUpdates.d.ts b/packages/@expo/inline-modules/build/xcodeProjectUpdates.d.ts
index 3cdb0dbd81c47e..fb78040627af14 100644
--- a/packages/@expo/inline-modules/build/xcodeProjectUpdates.d.ts
+++ b/packages/@expo/inline-modules/build/xcodeProjectUpdates.d.ts
@@ -1,5 +1,11 @@
export interface InlineModulesXcodeParams {
watchedDirectories: string[];
+ /**
+ * List of targets to which inline modules files are added. If undefined defaults to the main target only.
+ */
+ xcodeProjectTargets?: string[];
+ /** app config name */
+ name: string;
}
/**
* Add watched directories as PBXFileSystemSynchronizedRootGroups to pbxproj file in the project and save the changes.
diff --git a/packages/@expo/inline-modules/build/xcodeProjectUpdates.js b/packages/@expo/inline-modules/build/xcodeProjectUpdates.js
index 282d95b3a65104..aa303441b67a1e 100644
--- a/packages/@expo/inline-modules/build/xcodeProjectUpdates.js
+++ b/packages/@expo/inline-modules/build/xcodeProjectUpdates.js
@@ -7,11 +7,60 @@ exports.updateXcodeProject = updateXcodeProject;
const config_plugins_1 = require("@expo/config-plugins");
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
+function escapeXMLCharacters(original) {
+ const noAmps = original.replace('&', '&');
+ const noLt = noAmps.replace('<', '<');
+ const noGt = noLt.replace('>', '>');
+ const noApos = noGt.replace('"', '\\"');
+ return noApos.replace("'", "\\'");
+}
+// Note that this main target name is based on how `@expo/cli/src/prebuild/renameTemplateAppNameAsync.ts` preprocesses the ios project template.
+// It is neccesary to match the target name in the path to ExpoModulesProvider.swift for the main target as is used when generating it.
+function getMainTargetName(config) {
+ const name = config.name;
+ const safeName = escapeXMLCharacters(name);
+ return config_plugins_1.IOSConfig.XcodeUtils.sanitizedName(safeName);
+}
+function getNativeTargetSynchronizedGroupsMap(pbxProject) {
+ const objects = pbxProject.hash.project.objects;
+ const nativeTargetSynchronizedGroups = new Map();
+ for (const target of pbxProject.getFirstProject().firstProject.targets) {
+ const nativeTargetGroup = objects.PBXNativeTarget[target.value];
+ const synchronizedGroups = new Set();
+ if (nativeTargetGroup.fileSystemSynchronizedGroups) {
+ for (const synchronizedGroup of nativeTargetGroup.fileSystemSynchronizedGroups) {
+ synchronizedGroups.add(synchronizedGroup.value);
+ }
+ }
+ nativeTargetSynchronizedGroups.set(target.value, synchronizedGroups);
+ }
+ return nativeTargetSynchronizedGroups;
+}
+function prepareSynchronizedRootGroups(pbxProject) {
+ const objects = pbxProject.hash.project.objects;
+ const fsSynchronizedRootGroups = new Map();
+ if (objects.PBXFileSystemSynchronizedRootGroup) {
+ for (const key of Object.keys(objects.PBXFileSystemSynchronizedRootGroup)) {
+ if (key.endsWith('_comment')) {
+ continue;
+ }
+ const groupObject = objects.PBXFileSystemSynchronizedRootGroup[key];
+ fsSynchronizedRootGroups.set(groupObject.path, key);
+ }
+ }
+ else {
+ objects.PBXFileSystemSynchronizedRootGroup = {};
+ }
+ return { fsSynchronizedRootGroups };
+}
/**
* Add watched directories as PBXFileSystemSynchronizedRootGroups to pbxproj file in the project and save the changes.
*/
async function updateXcodeProject(projectRoot, inlineModulesXcodeParams) {
const swiftWatchedDirectories = inlineModulesXcodeParams.watchedDirectories;
+ const xcodeProjectTargets = inlineModulesXcodeParams.xcodeProjectTargets
+ ? new Set(inlineModulesXcodeParams.xcodeProjectTargets)
+ : undefined;
// Only perform changes to pbxproj if necessary
if (swiftWatchedDirectories.length === 0) {
return;
@@ -20,25 +69,28 @@ async function updateXcodeProject(projectRoot, inlineModulesXcodeParams) {
const mainGroupUUID = pbxProject.getFirstProject().firstProject.mainGroup;
const objects = pbxProject.hash.project.objects;
const projectRootRelativeToIos = '..';
- const fsSynchronizedRootGroups = new Set();
- if (objects.PBXFileSystemSynchronizedRootGroup) {
- for (const key of Object.keys(objects.PBXFileSystemSynchronizedRootGroup)) {
- if (key.endsWith('_comment')) {
- continue;
- }
- fsSynchronizedRootGroups.add(objects.PBXFileSystemSynchronizedRootGroup[key].path);
+ const pbxNativeTarget = pbxProject.hash.project.objects.PBXNativeTarget;
+ const nativeTargetSynchronizedGroups = getNativeTargetSynchronizedGroupsMap(pbxProject);
+ const addWatchedDirectoryToTarget = (targetUUID, nativeTargetGroup, dir, dirUUID) => {
+ if (!nativeTargetSynchronizedGroups.has(targetUUID)) {
+ nativeTargetSynchronizedGroups.set(targetUUID, new Set());
}
- }
- else {
- objects.PBXFileSystemSynchronizedRootGroup = {};
- }
- let projectHasChanged = false;
- for (const dir of swiftWatchedDirectories) {
+ const targetSynchronizedGroups = nativeTargetSynchronizedGroups.get(targetUUID);
+ if (targetSynchronizedGroups.has(dirUUID)) {
+ return;
+ }
+ if (!nativeTargetGroup.fileSystemSynchronizedGroups) {
+ nativeTargetGroup.fileSystemSynchronizedGroups = [];
+ }
+ nativeTargetGroup.fileSystemSynchronizedGroups.push({ value: dirUUID, comment: dir });
+ targetSynchronizedGroups.add(dirUUID);
+ };
+ const { fsSynchronizedRootGroups } = prepareSynchronizedRootGroups(pbxProject);
+ const getOrCreateWatchedDirectoryUUID = (dir) => {
const dirRelativeToIos = path_1.default.join(projectRootRelativeToIos, dir);
if (fsSynchronizedRootGroups.has(dirRelativeToIos)) {
- continue;
+ return fsSynchronizedRootGroups.get(dirRelativeToIos);
}
- projectHasChanged = true;
const newUUID = pbxProject.generateUuid();
objects.PBXGroup[mainGroupUUID].children.push({
value: newUUID,
@@ -52,16 +104,26 @@ async function updateXcodeProject(projectRoot, inlineModulesXcodeParams) {
path: dirRelativeToIos,
sourceTree: 'SOURCE_ROOT',
};
- for (const target of pbxProject.getFirstProject().firstProject.targets) {
+ return newUUID;
+ };
+ const targetsToUpdate = pbxProject
+ .getFirstProject()
+ .firstProject.targets.filter((target) => {
+ const targetUuid = target.value;
+ const targetName = pbxNativeTarget[targetUuid].name;
+ if (!xcodeProjectTargets) {
+ // If the xcodeProjectTargets are not provided, default to the main target
+ return targetName === getMainTargetName(inlineModulesXcodeParams);
+ }
+ return xcodeProjectTargets.has(targetName);
+ });
+ for (const watchedDirectory of swiftWatchedDirectories) {
+ const dirUUID = getOrCreateWatchedDirectoryUUID(watchedDirectory);
+ for (const target of targetsToUpdate) {
const nativeTargetGroup = objects.PBXNativeTarget[target.value];
- if (!nativeTargetGroup.fileSystemSynchronizedGroups) {
- nativeTargetGroup.fileSystemSynchronizedGroups = [];
- }
- nativeTargetGroup.fileSystemSynchronizedGroups.push({ value: newUUID, comment: dir });
+ addWatchedDirectoryToTarget(target.value, nativeTargetGroup, watchedDirectory, dirUUID);
}
}
- if (projectHasChanged) {
- await fs_1.default.promises.writeFile(pbxProject.filepath, pbxProject.writeSync());
- }
+ await fs_1.default.promises.writeFile(pbxProject.filepath, pbxProject.writeSync());
}
//# sourceMappingURL=xcodeProjectUpdates.js.map
\ No newline at end of file
diff --git a/packages/@expo/inline-modules/build/xcodeProjectUpdates.js.map b/packages/@expo/inline-modules/build/xcodeProjectUpdates.js.map
index 0201c93e2b3558..f7d1fe77ead1cb 100644
--- a/packages/@expo/inline-modules/build/xcodeProjectUpdates.js.map
+++ b/packages/@expo/inline-modules/build/xcodeProjectUpdates.js.map
@@ -1 +1 @@
-{"version":3,"file":"xcodeProjectUpdates.js","sourceRoot":"","sources":["../src/xcodeProjectUpdates.ts"],"names":[],"mappings":";;;;;AAWA,gDA+DC;AA1ED,yDAAiD;AACjD,4CAAoB;AACpB,gDAAwB;AAMxB;;GAEG;AACI,KAAK,UAAU,kBAAkB,CACtC,WAAmB,EACnB,wBAAkD;IAElD,MAAM,uBAAuB,GAAG,wBAAwB,CAAC,kBAAkB,CAAC;IAC5E,+CAA+C;IAC/C,IAAI,uBAAuB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzC,OAAO;IACT,CAAC;IAED,MAAM,UAAU,GAAG,0BAAS,CAAC,UAAU,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;IAChE,MAAM,aAAa,GAAG,UAAU,CAAC,eAAe,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC;IAC1E,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;IAChD,MAAM,wBAAwB,GAAG,IAAI,CAAC;IAEtC,MAAM,wBAAwB,GAAgB,IAAI,GAAG,EAAU,CAAC;IAChE,IAAI,OAAO,CAAC,kCAAkC,EAAE,CAAC;QAC/C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,kCAAkC,CAAC,EAAE,CAAC;YAC1E,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC7B,SAAS;YACX,CAAC;YACD,wBAAwB,CAAC,GAAG,CAAC,OAAO,CAAC,kCAAkC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;QACrF,CAAC;IACH,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,kCAAkC,GAAG,EAAE,CAAC;IAClD,CAAC;IAED,IAAI,iBAAiB,GAAG,KAAK,CAAC;IAC9B,KAAK,MAAM,GAAG,IAAI,uBAAuB,EAAE,CAAC;QAC1C,MAAM,gBAAgB,GAAG,cAAI,CAAC,IAAI,CAAC,wBAAwB,EAAE,GAAG,CAAC,CAAC;QAClE,IAAI,wBAAwB,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACnD,SAAS;QACX,CAAC;QAED,iBAAiB,GAAG,IAAI,CAAC;QAEzB,MAAM,OAAO,GAAG,UAAU,CAAC,YAAY,EAAE,CAAC;QAC1C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;YAC5C,KAAK,EAAE,OAAO;YACd,OAAO,EAAE,GAAG;SACb,CAAC,CAAC;QAEH,OAAO,CAAC,kCAAkC,CAAC,OAAO,CAAC,GAAG;YACpD,GAAG,EAAE,oCAAoC;YACzC,iBAAiB,EAAE,EAAE;YACrB,eAAe,EAAE,EAAE;YACnB,IAAI,EAAE,GAAG;YACT,IAAI,EAAE,gBAAgB;YACtB,UAAU,EAAE,aAAa;SAC1B,CAAC;QAEF,KAAK,MAAM,MAAM,IAAI,UAAU,CAAC,eAAe,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;YACvE,MAAM,iBAAiB,GAAG,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAChE,IAAI,CAAC,iBAAiB,CAAC,4BAA4B,EAAE,CAAC;gBACpD,iBAAiB,CAAC,4BAA4B,GAAG,EAAE,CAAC;YACtD,CAAC;YACD,iBAAiB,CAAC,4BAA4B,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;QACxF,CAAC;IACH,CAAC;IAED,IAAI,iBAAiB,EAAE,CAAC;QACtB,MAAM,YAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,SAAS,EAAE,CAAC,CAAC;IAC3E,CAAC;AACH,CAAC"}
\ No newline at end of file
+{"version":3,"file":"xcodeProjectUpdates.js","sourceRoot":"","sources":["../src/xcodeProjectUpdates.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/packages/@expo/inline-modules/src/xcodeProjectUpdates.ts b/packages/@expo/inline-modules/src/xcodeProjectUpdates.ts
index f705c675d84c6e..1988cf6f7bd6cc 100644
--- a/packages/@expo/inline-modules/src/xcodeProjectUpdates.ts
+++ b/packages/@expo/inline-modules/src/xcodeProjectUpdates.ts
@@ -1,9 +1,73 @@
-import { IOSConfig } from '@expo/config-plugins';
+import { IOSConfig, type XcodeProject } from '@expo/config-plugins';
import fs from 'fs';
import path from 'path';
export interface InlineModulesXcodeParams {
watchedDirectories: string[];
+ /**
+ * List of targets to which inline modules files are added. If undefined defaults to the main target only.
+ */
+ xcodeProjectTargets?: string[];
+ /** app config name */
+ name: string;
+}
+
+type UUID = string;
+interface FileSystemSynchronizedGroup {
+ fileSystemSynchronizedGroups?: { value: string; comment?: string }[];
+}
+
+function escapeXMLCharacters(original: string): string {
+ const noAmps = original.replace('&', '&');
+ const noLt = noAmps.replace('<', '<');
+ const noGt = noLt.replace('>', '>');
+ const noApos = noGt.replace('"', '\\"');
+ return noApos.replace("'", "\\'");
+}
+
+// Note that this main target name is based on how `@expo/cli/src/prebuild/renameTemplateAppNameAsync.ts` preprocesses the ios project template.
+// It is neccesary to match the target name in the path to ExpoModulesProvider.swift for the main target as is used when generating it.
+function getMainTargetName(config: InlineModulesXcodeParams): string {
+ const name = config.name;
+ const safeName = escapeXMLCharacters(name);
+ return IOSConfig.XcodeUtils.sanitizedName(safeName);
+}
+
+function getNativeTargetSynchronizedGroupsMap(pbxProject: XcodeProject) {
+ const objects = pbxProject.hash.project.objects;
+ const nativeTargetSynchronizedGroups = new Map>();
+
+ for (const target of pbxProject.getFirstProject().firstProject.targets) {
+ const nativeTargetGroup = objects.PBXNativeTarget[target.value];
+ const synchronizedGroups = new Set();
+
+ if (nativeTargetGroup.fileSystemSynchronizedGroups) {
+ for (const synchronizedGroup of nativeTargetGroup.fileSystemSynchronizedGroups) {
+ synchronizedGroups.add(synchronizedGroup.value);
+ }
+ }
+ nativeTargetSynchronizedGroups.set(target.value, synchronizedGroups);
+ }
+ return nativeTargetSynchronizedGroups;
+}
+
+function prepareSynchronizedRootGroups(pbxProject: XcodeProject): {
+ fsSynchronizedRootGroups: Map;
+} {
+ const objects = pbxProject.hash.project.objects;
+ const fsSynchronizedRootGroups = new Map();
+ if (objects.PBXFileSystemSynchronizedRootGroup) {
+ for (const key of Object.keys(objects.PBXFileSystemSynchronizedRootGroup)) {
+ if (key.endsWith('_comment')) {
+ continue;
+ }
+ const groupObject = objects.PBXFileSystemSynchronizedRootGroup[key];
+ fsSynchronizedRootGroups.set(groupObject.path, key);
+ }
+ } else {
+ objects.PBXFileSystemSynchronizedRootGroup = {};
+ }
+ return { fsSynchronizedRootGroups };
}
/**
@@ -14,6 +78,10 @@ export async function updateXcodeProject(
inlineModulesXcodeParams: InlineModulesXcodeParams
): Promise {
const swiftWatchedDirectories = inlineModulesXcodeParams.watchedDirectories;
+ const xcodeProjectTargets = inlineModulesXcodeParams.xcodeProjectTargets
+ ? new Set(inlineModulesXcodeParams.xcodeProjectTargets)
+ : undefined;
+
// Only perform changes to pbxproj if necessary
if (swiftWatchedDirectories.length === 0) {
return;
@@ -23,28 +91,38 @@ export async function updateXcodeProject(
const mainGroupUUID = pbxProject.getFirstProject().firstProject.mainGroup;
const objects = pbxProject.hash.project.objects;
const projectRootRelativeToIos = '..';
+ const pbxNativeTarget = pbxProject.hash.project.objects.PBXNativeTarget;
- const fsSynchronizedRootGroups: Set = new Set();
- if (objects.PBXFileSystemSynchronizedRootGroup) {
- for (const key of Object.keys(objects.PBXFileSystemSynchronizedRootGroup)) {
- if (key.endsWith('_comment')) {
- continue;
- }
- fsSynchronizedRootGroups.add(objects.PBXFileSystemSynchronizedRootGroup[key].path);
+ const nativeTargetSynchronizedGroups = getNativeTargetSynchronizedGroupsMap(pbxProject);
+ const addWatchedDirectoryToTarget = (
+ targetUUID: UUID,
+ nativeTargetGroup: FileSystemSynchronizedGroup,
+ dir: string,
+ dirUUID: UUID
+ ) => {
+ if (!nativeTargetSynchronizedGroups.has(targetUUID)) {
+ nativeTargetSynchronizedGroups.set(targetUUID, new Set());
}
- } else {
- objects.PBXFileSystemSynchronizedRootGroup = {};
- }
- let projectHasChanged = false;
- for (const dir of swiftWatchedDirectories) {
+ const targetSynchronizedGroups = nativeTargetSynchronizedGroups.get(targetUUID) as Set;
+ if (targetSynchronizedGroups.has(dirUUID)) {
+ return;
+ }
+
+ if (!nativeTargetGroup.fileSystemSynchronizedGroups) {
+ nativeTargetGroup.fileSystemSynchronizedGroups = [];
+ }
+ nativeTargetGroup.fileSystemSynchronizedGroups.push({ value: dirUUID, comment: dir });
+ targetSynchronizedGroups.add(dirUUID);
+ };
+
+ const { fsSynchronizedRootGroups } = prepareSynchronizedRootGroups(pbxProject);
+ const getOrCreateWatchedDirectoryUUID = (dir: string) => {
const dirRelativeToIos = path.join(projectRootRelativeToIos, dir);
if (fsSynchronizedRootGroups.has(dirRelativeToIos)) {
- continue;
+ return fsSynchronizedRootGroups.get(dirRelativeToIos);
}
- projectHasChanged = true;
-
const newUUID = pbxProject.generateUuid();
objects.PBXGroup[mainGroupUUID].children.push({
value: newUUID,
@@ -59,17 +137,29 @@ export async function updateXcodeProject(
path: dirRelativeToIos,
sourceTree: 'SOURCE_ROOT',
};
+ return newUUID;
+ };
- for (const target of pbxProject.getFirstProject().firstProject.targets) {
- const nativeTargetGroup = objects.PBXNativeTarget[target.value];
- if (!nativeTargetGroup.fileSystemSynchronizedGroups) {
- nativeTargetGroup.fileSystemSynchronizedGroups = [];
+ const targetsToUpdate = pbxProject
+ .getFirstProject()
+ .firstProject.targets.filter((target: { value: UUID; comment: string }) => {
+ const targetUuid = target.value;
+ const targetName = pbxNativeTarget[targetUuid].name;
+ if (!xcodeProjectTargets) {
+ // If the xcodeProjectTargets are not provided, default to the main target
+ return targetName === getMainTargetName(inlineModulesXcodeParams);
}
- nativeTargetGroup.fileSystemSynchronizedGroups.push({ value: newUUID, comment: dir });
+ return xcodeProjectTargets.has(targetName);
+ });
+
+ for (const watchedDirectory of swiftWatchedDirectories) {
+ const dirUUID = getOrCreateWatchedDirectoryUUID(watchedDirectory);
+
+ for (const target of targetsToUpdate) {
+ const nativeTargetGroup = objects.PBXNativeTarget[target.value];
+ addWatchedDirectoryToTarget(target.value, nativeTargetGroup, watchedDirectory, dirUUID);
}
}
- if (projectHasChanged) {
- await fs.promises.writeFile(pbxProject.filepath, pbxProject.writeSync());
- }
+ await fs.promises.writeFile(pbxProject.filepath, pbxProject.writeSync());
}
diff --git a/packages/@expo/prebuild-config/CHANGELOG.md b/packages/@expo/prebuild-config/CHANGELOG.md
index cf76fb664806fa..2e6c52734bed97 100644
--- a/packages/@expo/prebuild-config/CHANGELOG.md
+++ b/packages/@expo/prebuild-config/CHANGELOG.md
@@ -6,6 +6,8 @@
### 🎉 New features
+- Add option to specify targets to use with inline modules, add new option to podfile.properties ([#46698](https://github.com/expo/expo/pull/46698) by [@HubertBer](https://github.com/HubertBer))
+
### 🐛 Bug fixes
- Generated iOS projects now include a `SceneDelegate` and `UIApplicationSceneManifest` for the scene-based life cycle. ([#46734](https://github.com/expo/expo/pull/46734) by [@alanjhughes](https://github.com/alanjhughes))
diff --git a/packages/@expo/prebuild-config/build/plugins/unversioned/expo-inline-modules/withInlineModules.js b/packages/@expo/prebuild-config/build/plugins/unversioned/expo-inline-modules/withInlineModules.js
index 789d2254516672..b6602b09ea2c01 100644
--- a/packages/@expo/prebuild-config/build/plugins/unversioned/expo-inline-modules/withInlineModules.js
+++ b/packages/@expo/prebuild-config/build/plugins/unversioned/expo-inline-modules/withInlineModules.js
@@ -17,6 +17,21 @@ const {
const {
createBuildPodfilePropsConfigPlugin
} = _configPlugins().IOSConfig.BuildProperties;
+function escapeXMLCharacters(original) {
+ const noAmps = original.replace('&', '&');
+ const noLt = noAmps.replace('<', '<');
+ const noGt = noLt.replace('>', '>');
+ const noApos = noGt.replace('"', '\\"');
+ return noApos.replace("'", "\\'");
+}
+
+// Note that this main target name is based on how `@expo/cli/src/prebuild/renameTemplateAppNameAsync.ts` preprocesses the ios project template.
+// It is neccesary to match the target name in the path to ExpoModulesProvider.swift for the main target as is used when generating it.
+function getMainTargetName(config) {
+ const name = config.name;
+ const safeName = escapeXMLCharacters(name);
+ return _configPlugins().IOSConfig.XcodeUtils.sanitizedName(safeName);
+}
const withInlineModules = (config, props) => {
config = createBuildGradlePropsConfigPlugin([{
propName: 'expo.inlineModules.watchedDirectories',
@@ -35,6 +50,20 @@ const withInlineModules = (config, props) => {
}
return JSON.stringify(conf.experiments?.inlineModules?.watchedDirectories ?? []);
}
+ }, {
+ propName: 'expo.inlineModules.xcodeProjectTargets',
+ propValueGetter: conf => {
+ const xcodeProjectTargets = conf.experiments?.inlineModules?.xcodeProjectTargets;
+ if (!xcodeProjectTargets) {
+ return JSON.stringify({
+ mainTarget: getMainTargetName(config),
+ targets: []
+ });
+ }
+ return JSON.stringify({
+ targets: xcodeProjectTargets
+ });
+ }
}], 'withIosInlineModules')(config);
return config;
};
diff --git a/packages/@expo/prebuild-config/build/plugins/unversioned/expo-inline-modules/withInlineModules.js.map b/packages/@expo/prebuild-config/build/plugins/unversioned/expo-inline-modules/withInlineModules.js.map
index 7e99b9d53322fa..2b04c46cc75544 100644
--- a/packages/@expo/prebuild-config/build/plugins/unversioned/expo-inline-modules/withInlineModules.js.map
+++ b/packages/@expo/prebuild-config/build/plugins/unversioned/expo-inline-modules/withInlineModules.js.map
@@ -1 +1 @@
-{"version":3,"file":"withInlineModules.js","names":["_configPlugins","data","require","createBuildGradlePropsConfigPlugin","AndroidConfig","BuildProperties","createBuildPodfilePropsConfigPlugin","IOSConfig","withInlineModules","config","props","propName","propValueGetter","conf","experiments","inlineModules","JSON","stringify","watchedDirectories","exports","_default","default"],"sources":["../../../../src/plugins/unversioned/expo-inline-modules/withInlineModules.ts"],"sourcesContent":["import { AndroidConfig, IOSConfig } from '@expo/config-plugins';\nimport type { ExpoConfig } from '@expo/config-types';\n\nconst { createBuildGradlePropsConfigPlugin } = AndroidConfig.BuildProperties;\nconst { createBuildPodfilePropsConfigPlugin } = IOSConfig.BuildProperties;\n\nexport const withInlineModules = (config: ExpoConfig, props: any) => {\n config = createBuildGradlePropsConfigPlugin(\n [\n {\n propName: 'expo.inlineModules.watchedDirectories',\n propValueGetter: (conf) => {\n if (!conf.experiments?.inlineModules) {\n return JSON.stringify([]);\n }\n return JSON.stringify(conf.experiments?.inlineModules?.watchedDirectories ?? []);\n },\n },\n ],\n 'withAndroidInlineModules'\n )(config);\n\n config = createBuildPodfilePropsConfigPlugin(\n [\n {\n propName: 'expo.inlineModules.watchedDirectories',\n propValueGetter: (conf) => {\n if (!conf.experiments?.inlineModules) {\n return JSON.stringify([]);\n }\n return JSON.stringify(conf.experiments?.inlineModules?.watchedDirectories ?? []);\n },\n },\n ],\n 'withIosInlineModules'\n )(config);\n\n return config;\n};\n\nexport default withInlineModules;\n"],"mappings":";;;;;;AAAA,SAAAA,eAAA;EAAA,MAAAC,IAAA,GAAAC,OAAA;EAAAF,cAAA,YAAAA,CAAA;IAAA,OAAAC,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AAGA,MAAM;EAAEE;AAAmC,CAAC,GAAGC,8BAAa,CAACC,eAAe;AAC5E,MAAM;EAAEC;AAAoC,CAAC,GAAGC,0BAAS,CAACF,eAAe;AAElE,MAAMG,iBAAiB,GAAGA,CAACC,MAAkB,EAAEC,KAAU,KAAK;EACnED,MAAM,GAAGN,kCAAkC,CACzC,CACE;IACEQ,QAAQ,EAAE,uCAAuC;IACjDC,eAAe,EAAGC,IAAI,IAAK;MACzB,IAAI,CAACA,IAAI,CAACC,WAAW,EAAEC,aAAa,EAAE;QACpC,OAAOC,IAAI,CAACC,SAAS,CAAC,EAAE,CAAC;MAC3B;MACA,OAAOD,IAAI,CAACC,SAAS,CAACJ,IAAI,CAACC,WAAW,EAAEC,aAAa,EAAEG,kBAAkB,IAAI,EAAE,CAAC;IAClF;EACF,CAAC,CACF,EACD,0BACF,CAAC,CAACT,MAAM,CAAC;EAETA,MAAM,GAAGH,mCAAmC,CAC1C,CACE;IACEK,QAAQ,EAAE,uCAAuC;IACjDC,eAAe,EAAGC,IAAI,IAAK;MACzB,IAAI,CAACA,IAAI,CAACC,WAAW,EAAEC,aAAa,EAAE;QACpC,OAAOC,IAAI,CAACC,SAAS,CAAC,EAAE,CAAC;MAC3B;MACA,OAAOD,IAAI,CAACC,SAAS,CAACJ,IAAI,CAACC,WAAW,EAAEC,aAAa,EAAEG,kBAAkB,IAAI,EAAE,CAAC;IAClF;EACF,CAAC,CACF,EACD,sBACF,CAAC,CAACT,MAAM,CAAC;EAET,OAAOA,MAAM;AACf,CAAC;AAACU,OAAA,CAAAX,iBAAA,GAAAA,iBAAA;AAAA,IAAAY,QAAA,GAAAD,OAAA,CAAAE,OAAA,GAEab,iBAAiB","ignoreList":[]}
\ No newline at end of file
+{"version":3,"file":"withInlineModules.js","names":["_configPlugins","data","require","createBuildGradlePropsConfigPlugin","AndroidConfig","BuildProperties","createBuildPodfilePropsConfigPlugin","IOSConfig","escapeXMLCharacters","original","noAmps","replace","noLt","noGt","noApos","getMainTargetName","config","name","safeName","XcodeUtils","sanitizedName","withInlineModules","props","propName","propValueGetter","conf","experiments","inlineModules","JSON","stringify","watchedDirectories","xcodeProjectTargets","mainTarget","targets","exports","_default","default"],"sources":["../../../../src/plugins/unversioned/expo-inline-modules/withInlineModules.ts"],"sourcesContent":["import { AndroidConfig, IOSConfig } from '@expo/config-plugins';\nimport type { ExpoConfig } from '@expo/config-types';\n\nconst { createBuildGradlePropsConfigPlugin } = AndroidConfig.BuildProperties;\nconst { createBuildPodfilePropsConfigPlugin } = IOSConfig.BuildProperties;\n\nfunction escapeXMLCharacters(original: string): string {\n const noAmps = original.replace('&', '&');\n const noLt = noAmps.replace('<', '<');\n const noGt = noLt.replace('>', '>');\n const noApos = noGt.replace('\"', '\\\\\"');\n return noApos.replace(\"'\", \"\\\\'\");\n}\n\n// Note that this main target name is based on how `@expo/cli/src/prebuild/renameTemplateAppNameAsync.ts` preprocesses the ios project template.\n// It is neccesary to match the target name in the path to ExpoModulesProvider.swift for the main target as is used when generating it.\nfunction getMainTargetName(config: ExpoConfig): string {\n const name = config.name;\n const safeName = escapeXMLCharacters(name);\n return IOSConfig.XcodeUtils.sanitizedName(safeName);\n}\n\nexport const withInlineModules = (config: ExpoConfig, props: any) => {\n config = createBuildGradlePropsConfigPlugin(\n [\n {\n propName: 'expo.inlineModules.watchedDirectories',\n propValueGetter: (conf) => {\n if (!conf.experiments?.inlineModules) {\n return JSON.stringify([]);\n }\n return JSON.stringify(conf.experiments?.inlineModules?.watchedDirectories ?? []);\n },\n },\n ],\n 'withAndroidInlineModules'\n )(config);\n\n config = createBuildPodfilePropsConfigPlugin(\n [\n {\n propName: 'expo.inlineModules.watchedDirectories',\n propValueGetter: (conf) => {\n if (!conf.experiments?.inlineModules) {\n return JSON.stringify([]);\n }\n return JSON.stringify(conf.experiments?.inlineModules?.watchedDirectories ?? []);\n },\n },\n {\n propName: 'expo.inlineModules.xcodeProjectTargets',\n propValueGetter: (conf) => {\n const xcodeProjectTargets = conf.experiments?.inlineModules?.xcodeProjectTargets;\n if (!xcodeProjectTargets) {\n return JSON.stringify({ mainTarget: getMainTargetName(config), targets: [] });\n }\n return JSON.stringify({ targets: xcodeProjectTargets });\n },\n },\n ],\n 'withIosInlineModules'\n )(config);\n\n return config;\n};\n\nexport default withInlineModules;\n"],"mappings":";;;;;;AAAA,SAAAA,eAAA;EAAA,MAAAC,IAAA,GAAAC,OAAA;EAAAF,cAAA,YAAAA,CAAA;IAAA,OAAAC,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AAGA,MAAM;EAAEE;AAAmC,CAAC,GAAGC,8BAAa,CAACC,eAAe;AAC5E,MAAM;EAAEC;AAAoC,CAAC,GAAGC,0BAAS,CAACF,eAAe;AAEzE,SAASG,mBAAmBA,CAACC,QAAgB,EAAU;EACrD,MAAMC,MAAM,GAAGD,QAAQ,CAACE,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC;EAC7C,MAAMC,IAAI,GAAGF,MAAM,CAACC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC;EACxC,MAAME,IAAI,GAAGD,IAAI,CAACD,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC;EACtC,MAAMG,MAAM,GAAGD,IAAI,CAACF,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC;EACvC,OAAOG,MAAM,CAACH,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC;AACnC;;AAEA;AACA;AACA,SAASI,iBAAiBA,CAACC,MAAkB,EAAU;EACrD,MAAMC,IAAI,GAAGD,MAAM,CAACC,IAAI;EACxB,MAAMC,QAAQ,GAAGV,mBAAmB,CAACS,IAAI,CAAC;EAC1C,OAAOV,0BAAS,CAACY,UAAU,CAACC,aAAa,CAACF,QAAQ,CAAC;AACrD;AAEO,MAAMG,iBAAiB,GAAGA,CAACL,MAAkB,EAAEM,KAAU,KAAK;EACnEN,MAAM,GAAGb,kCAAkC,CACzC,CACE;IACEoB,QAAQ,EAAE,uCAAuC;IACjDC,eAAe,EAAGC,IAAI,IAAK;MACzB,IAAI,CAACA,IAAI,CAACC,WAAW,EAAEC,aAAa,EAAE;QACpC,OAAOC,IAAI,CAACC,SAAS,CAAC,EAAE,CAAC;MAC3B;MACA,OAAOD,IAAI,CAACC,SAAS,CAACJ,IAAI,CAACC,WAAW,EAAEC,aAAa,EAAEG,kBAAkB,IAAI,EAAE,CAAC;IAClF;EACF,CAAC,CACF,EACD,0BACF,CAAC,CAACd,MAAM,CAAC;EAETA,MAAM,GAAGV,mCAAmC,CAC1C,CACE;IACEiB,QAAQ,EAAE,uCAAuC;IACjDC,eAAe,EAAGC,IAAI,IAAK;MACzB,IAAI,CAACA,IAAI,CAACC,WAAW,EAAEC,aAAa,EAAE;QACpC,OAAOC,IAAI,CAACC,SAAS,CAAC,EAAE,CAAC;MAC3B;MACA,OAAOD,IAAI,CAACC,SAAS,CAACJ,IAAI,CAACC,WAAW,EAAEC,aAAa,EAAEG,kBAAkB,IAAI,EAAE,CAAC;IAClF;EACF,CAAC,EACD;IACEP,QAAQ,EAAE,wCAAwC;IAClDC,eAAe,EAAGC,IAAI,IAAK;MACzB,MAAMM,mBAAmB,GAAGN,IAAI,CAACC,WAAW,EAAEC,aAAa,EAAEI,mBAAmB;MAChF,IAAI,CAACA,mBAAmB,EAAE;QACxB,OAAOH,IAAI,CAACC,SAAS,CAAC;UAAEG,UAAU,EAAEjB,iBAAiB,CAACC,MAAM,CAAC;UAAEiB,OAAO,EAAE;QAAG,CAAC,CAAC;MAC/E;MACA,OAAOL,IAAI,CAACC,SAAS,CAAC;QAAEI,OAAO,EAAEF;MAAoB,CAAC,CAAC;IACzD;EACF,CAAC,CACF,EACD,sBACF,CAAC,CAACf,MAAM,CAAC;EAET,OAAOA,MAAM;AACf,CAAC;AAACkB,OAAA,CAAAb,iBAAA,GAAAA,iBAAA;AAAA,IAAAc,QAAA,GAAAD,OAAA,CAAAE,OAAA,GAEaf,iBAAiB","ignoreList":[]}
\ No newline at end of file
diff --git a/packages/@expo/prebuild-config/src/plugins/__tests__/__snapshots__/withDefaultPlugins-test.ts.snap b/packages/@expo/prebuild-config/src/plugins/__tests__/__snapshots__/withDefaultPlugins-test.ts.snap
index 66413a9c66e3c1..6ff630f1decdc1 100644
--- a/packages/@expo/prebuild-config/src/plugins/__tests__/__snapshots__/withDefaultPlugins-test.ts.snap
+++ b/packages/@expo/prebuild-config/src/plugins/__tests__/__snapshots__/withDefaultPlugins-test.ts.snap
@@ -916,6 +916,7 @@ exports[`built-in plugins introspects mods 1`] = `
"podfileProperties": {
"EX_DEV_CLIENT_NETWORK_INSPECTOR": "true",
"expo.inlineModules.watchedDirectories": "[]",
+ "expo.inlineModules.xcodeProjectTargets": "{"mainTarget":"mycoolapp","targets":[]}",
"expo.jsEngine": "hermes",
"ios.deploymentTarget": "15.1",
},
@@ -1554,6 +1555,7 @@ exports[`built-in plugins introspects mods in a managed project 1`] = `
},
"podfileProperties": {
"expo.inlineModules.watchedDirectories": "[]",
+ "expo.inlineModules.xcodeProjectTargets": "{"mainTarget":"mycoolapp","targets":[]}",
"ios.deploymentTarget": "15.1",
},
},
diff --git a/packages/@expo/prebuild-config/src/plugins/unversioned/expo-inline-modules/withInlineModules.ts b/packages/@expo/prebuild-config/src/plugins/unversioned/expo-inline-modules/withInlineModules.ts
index 9c577d821c016d..182553e3df2fb4 100644
--- a/packages/@expo/prebuild-config/src/plugins/unversioned/expo-inline-modules/withInlineModules.ts
+++ b/packages/@expo/prebuild-config/src/plugins/unversioned/expo-inline-modules/withInlineModules.ts
@@ -4,6 +4,22 @@ import type { ExpoConfig } from '@expo/config-types';
const { createBuildGradlePropsConfigPlugin } = AndroidConfig.BuildProperties;
const { createBuildPodfilePropsConfigPlugin } = IOSConfig.BuildProperties;
+function escapeXMLCharacters(original: string): string {
+ const noAmps = original.replace('&', '&');
+ const noLt = noAmps.replace('<', '<');
+ const noGt = noLt.replace('>', '>');
+ const noApos = noGt.replace('"', '\\"');
+ return noApos.replace("'", "\\'");
+}
+
+// Note that this main target name is based on how `@expo/cli/src/prebuild/renameTemplateAppNameAsync.ts` preprocesses the ios project template.
+// It is neccesary to match the target name in the path to ExpoModulesProvider.swift for the main target as is used when generating it.
+function getMainTargetName(config: ExpoConfig): string {
+ const name = config.name;
+ const safeName = escapeXMLCharacters(name);
+ return IOSConfig.XcodeUtils.sanitizedName(safeName);
+}
+
export const withInlineModules = (config: ExpoConfig, props: any) => {
config = createBuildGradlePropsConfigPlugin(
[
@@ -31,6 +47,16 @@ export const withInlineModules = (config: ExpoConfig, props: any) => {
return JSON.stringify(conf.experiments?.inlineModules?.watchedDirectories ?? []);
},
},
+ {
+ propName: 'expo.inlineModules.xcodeProjectTargets',
+ propValueGetter: (conf) => {
+ const xcodeProjectTargets = conf.experiments?.inlineModules?.xcodeProjectTargets;
+ if (!xcodeProjectTargets) {
+ return JSON.stringify({ mainTarget: getMainTargetName(config), targets: [] });
+ }
+ return JSON.stringify({ targets: xcodeProjectTargets });
+ },
+ },
],
'withIosInlineModules'
)(config);
diff --git a/packages/expo-dev-launcher/CHANGELOG.md b/packages/expo-dev-launcher/CHANGELOG.md
index d20f3b6295d8ee..2bd3ec7b3ef620 100644
--- a/packages/expo-dev-launcher/CHANGELOG.md
+++ b/packages/expo-dev-launcher/CHANGELOG.md
@@ -12,6 +12,10 @@
- [iOS] Cleared the deep-link URL from cached `launchOptions` after it is consumed ([#46265](https://github.com/expo/expo/pull/46265) by [@gabrieldonadel](https://github.com/gabrieldonadel))
- [Android] Fixed a crash when cold-launching a development build from a deep link that carries intent categories (e.g. an App Link opened from a browser). ([#46314](https://github.com/expo/expo/pull/46314) by [@lilianchiassai-fc](https://github.com/lilianchiassai-fc) & [#46328](https://github.com/expo/expo/pull/46328) by [@lukmccall](https://github.com/lukmccall))
- [Android] Discover packagers across all connected networks on Android 33+. ([#46487](https://github.com/expo/expo/pull/46487) by [@lukmccall](https://github.com/lukmccall))
+- [iOS] Present Local Network permission as a status row instead of a toggle, and make the Settings debug actions native, full-row-tappable list rows. ([#46758](https://github.com/expo/expo/pull/46758) by [@alanjhughes](https://github.com/alanjhughes))
+- [iOS] Improve the Updates tab empty state with clearer guidance on how to publish an update. ([#46759](https://github.com/expo/expo/pull/46759) by [@alanjhughes](https://github.com/alanjhughes))
+- [iOS] Present the development server info dialog as a native sheet. ([#46760](https://github.com/expo/expo/pull/46760) by [@alanjhughes](https://github.com/alanjhughes))
+- [iOS] Reduce accidental logout in the account selector with a confirmation step and a less prominent button, and add more spacing around the header title. ([#46761](https://github.com/expo/expo/pull/46761) by [@alanjhughes](https://github.com/alanjhughes))
### 💡 Others
diff --git a/packages/expo-dev-launcher/ios/SwiftUI/AccountSheet.swift b/packages/expo-dev-launcher/ios/SwiftUI/AccountSheet.swift
index e960084ead32e4..769d015202300c 100644
--- a/packages/expo-dev-launcher/ios/SwiftUI/AccountSheet.swift
+++ b/packages/expo-dev-launcher/ios/SwiftUI/AccountSheet.swift
@@ -5,6 +5,7 @@ import SwiftUI
struct AccountSheet: View {
@Environment(\.dismiss) private var dismiss
@EnvironmentObject var viewModel: DevLauncherViewModel
+ @State private var showingLogoutConfirmation = false
var body: some View {
VStack(spacing: 0) {
@@ -26,7 +27,7 @@ struct AccountSheet: View {
loginSignupCard
}
}
- .padding(.horizontal, 16)
+ .padding(.horizontal, 20)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
#if !os(tvOS) && !os(macOS)
@@ -53,7 +54,7 @@ struct AccountSheet: View {
.frame(width: 44, height: 44)
}
}
- .padding(.horizontal, 16)
+ .padding(.horizontal, 20)
.padding(.top, 8)
}
}
@@ -76,19 +77,32 @@ struct AccountSheet: View {
}
}
- Button {
+ logOutButton
+ }
+ }
+
+ private var logOutButton: some View {
+ Button(role: .destructive) {
+ showingLogoutConfirmation = true
+ }
+ label: {
+ Text("Log out")
+ .font(.headline)
+ .foregroundColor(.red)
+ .frame(maxWidth: .infinity)
+ .padding(.vertical, 12)
+ }
+ .background(Color.expoSecondarySystemBackground)
+ .cornerRadius(12)
+ .confirmationDialog(
+ "Are you sure you want to log out?",
+ isPresented: $showingLogoutConfirmation,
+ titleVisibility: .visible
+ ) {
+ Button("Log out", role: .destructive) {
viewModel.signOut()
}
- label: {
- Text("Log out")
- .font(.headline)
- .fontWeight(.bold)
- .foregroundColor(.white)
- .frame(maxWidth: .infinity)
- .padding(.vertical, 12)
- }
- .background(Color.black)
- .cornerRadius(12)
+ Button("Cancel", role: .cancel) {}
}
}
diff --git a/packages/expo-dev-launcher/ios/SwiftUI/DevLauncherViewController.swift b/packages/expo-dev-launcher/ios/SwiftUI/DevLauncherViewController.swift
index 174f38e7839888..a125ddad3455de 100644
--- a/packages/expo-dev-launcher/ios/SwiftUI/DevLauncherViewController.swift
+++ b/packages/expo-dev-launcher/ios/SwiftUI/DevLauncherViewController.swift
@@ -69,7 +69,7 @@ import ExpoModulesCore
hostingController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
hostingController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
hostingController.view.topAnchor.constraint(equalTo: view.topAnchor),
- hostingController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
+ hostingController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
#if !os(macOS)
diff --git a/packages/expo-dev-launcher/ios/SwiftUI/DevLauncherViews.swift b/packages/expo-dev-launcher/ios/SwiftUI/DevLauncherViews.swift
index f7e8d3cf0fe69f..f038eaa710f921 100644
--- a/packages/expo-dev-launcher/ios/SwiftUI/DevLauncherViews.swift
+++ b/packages/expo-dev-launcher/ios/SwiftUI/DevLauncherViews.swift
@@ -13,7 +13,7 @@ public struct DevLauncherRootView: View {
|| UserDefaults.standard.bool(forKey: "expo.devlauncher.hasGrantedNetworkPermission")
_hasCompletedPermissionFlow = State(initialValue: shouldSkipPermissionFlow)
}
-
+
private static var isSimulator: Bool {
#if targetEnvironment(simulator)
return true
@@ -31,7 +31,7 @@ public struct DevLauncherRootView: View {
mainContent
}
}
-
+
@ViewBuilder
private var mainContent: some View {
let tabView = TabView {
diff --git a/packages/expo-dev-launcher/ios/SwiftUI/DevServerInfoModal.swift b/packages/expo-dev-launcher/ios/SwiftUI/DevServerInfoModal.swift
index 4792ff7673cb9b..f70c41dd995bf4 100644
--- a/packages/expo-dev-launcher/ios/SwiftUI/DevServerInfoModal.swift
+++ b/packages/expo-dev-launcher/ios/SwiftUI/DevServerInfoModal.swift
@@ -3,50 +3,35 @@
import SwiftUI
struct DevServerInfoModal: View {
- @Binding var showingInfoDialog: Bool
+ @Environment(\.dismiss) private var dismiss
var body: some View {
- Group {
- if #available(iOS 15.0, tvOS 16.0, *) {
- if showingInfoDialog {
- Color.black.opacity(0.4)
- .ignoresSafeArea(.all)
- .onTapGesture {
- showingInfoDialog = false
- }
- content
- }
- }
- }
- .animation(.easeInOut(duration: 0.3), value: showingInfoDialog)
- }
-
- private var content: some View {
- VStack(spacing: 16) {
+ VStack(alignment: .leading, spacing: 16) {
header
- Divider()
info
+ Spacer()
}
.padding(20)
- .background(Color.expoSystemBackground)
- .clipShape(RoundedRectangle(cornerRadius: 16))
- .shadow(color: .black.opacity(0.1), radius: 10, x: 0, y: 5)
- .padding(.horizontal, 40)
+ .frame(maxWidth: .infinity, alignment: .leading)
+ #if os(iOS)
+ .presentationDetents([.medium])
+ #endif
}
private var header: some View {
HStack {
Text("Development Servers")
- .font(.headline)
- .fontWeight(.semibold)
+ .font(.title2)
+ .fontWeight(.bold)
Spacer()
Button {
- showingInfoDialog = false
+ dismiss()
} label: {
- Image(systemName: "xmark")
- .font(.title3)
+ Image(systemName: "xmark.circle.fill")
+ .font(.title2)
.foregroundColor(.secondary)
}
+ .buttonStyle(.plain)
}
}
diff --git a/packages/expo-dev-launcher/ios/SwiftUI/DevServersView.swift b/packages/expo-dev-launcher/ios/SwiftUI/DevServersView.swift
index 1080845fd0832d..f29edd3ed25cc7 100644
--- a/packages/expo-dev-launcher/ios/SwiftUI/DevServersView.swift
+++ b/packages/expo-dev-launcher/ios/SwiftUI/DevServersView.swift
@@ -143,13 +143,17 @@ struct DevServersView: View {
Text("Load embedded bundle")
.foregroundColor(.primary)
Spacer()
- if viewModel.isLoadingLocalBundle {
- ProgressView()
- } else {
- Image(systemName: "chevron.right")
- .font(.caption)
- .foregroundColor(.secondary)
+ Group {
+ if viewModel.isLoadingLocalBundle {
+ ProgressView()
+ .controlSize(.small)
+ } else {
+ Image(systemName: "chevron.right")
+ .font(.caption)
+ .foregroundColor(.secondary)
+ }
}
+ .frame(width: 20, height: 20)
}
.padding()
.background(Color.expoSecondarySystemBackground)
@@ -232,13 +236,17 @@ struct DevServerRow: View {
Spacer()
- if viewModel.isLoadingServer {
- ProgressView()
- } else {
- Image(systemName: "chevron.right")
- .font(.caption)
- .foregroundColor(.secondary)
+ Group {
+ if viewModel.isLoadingServer {
+ ProgressView()
+ .controlSize(.small)
+ } else {
+ Image(systemName: "chevron.right")
+ .font(.caption)
+ .foregroundColor(.secondary)
+ }
}
+ .frame(width: 20, height: 20)
}
.padding()
.background(Color.expoSecondarySystemBackground)
diff --git a/packages/expo-dev-launcher/ios/SwiftUI/HomeTabView.swift b/packages/expo-dev-launcher/ios/SwiftUI/HomeTabView.swift
index c4ed744140b6a4..f785bbeaa1d40c 100644
--- a/packages/expo-dev-launcher/ios/SwiftUI/HomeTabView.swift
+++ b/packages/expo-dev-launcher/ios/SwiftUI/HomeTabView.swift
@@ -59,9 +59,9 @@ struct HomeTabView: View {
#if os(tvOS)
.background()
#endif
- .overlay(
- DevServerInfoModal(showingInfoDialog: $showingInfoDialog)
- )
+ .sheet(isPresented: $showingInfoDialog) {
+ DevServerInfoModal()
+ }
}
private var crashReportBanner: some View {
diff --git a/packages/expo-dev-launcher/ios/SwiftUI/NetworkUtilities.swift b/packages/expo-dev-launcher/ios/SwiftUI/NetworkUtilities.swift
index 68ac1f9e512910..3958cc7f51ac52 100644
--- a/packages/expo-dev-launcher/ios/SwiftUI/NetworkUtilities.swift
+++ b/packages/expo-dev-launcher/ios/SwiftUI/NetworkUtilities.swift
@@ -33,7 +33,7 @@ func buildHttpHost(endpoint: NWEndpoint) -> String? {
private final class AtomicFlag: @unchecked Sendable {
private var _value = false
private let lock = NSLock()
-
+
func testAndSet() -> Bool {
lock.lock()
defer { lock.unlock() }
@@ -51,7 +51,7 @@ func connectionStart(
try await withTaskCancellationHandler {
try await withCheckedThrowingContinuation { (cont: CheckedContinuation) in
let didResume = AtomicFlag()
-
+
let timeoutWork = DispatchWorkItem { [weak connection] in
guard didResume.testAndSet() else { return }
connection?.stateUpdateHandler = nil
@@ -59,7 +59,7 @@ func connectionStart(
cont.resume(throwing: ConnectionError.failedConnection)
}
queue.asyncAfter(deadline: .now() + timeout, execute: timeoutWork)
-
+
connection.stateUpdateHandler = { [weak connection] state in
switch state {
case .ready:
diff --git a/packages/expo-dev-launcher/ios/SwiftUI/SettingsTabView.swift b/packages/expo-dev-launcher/ios/SwiftUI/SettingsTabView.swift
index b7ba1bf9044cf3..276d94c425bf80 100644
--- a/packages/expo-dev-launcher/ios/SwiftUI/SettingsTabView.swift
+++ b/packages/expo-dev-launcher/ios/SwiftUI/SettingsTabView.swift
@@ -48,10 +48,14 @@ struct SettingsTabView: View {
Text("system".uppercased())
.font(.caption)
.foregroundColor(.primary.opacity(0.6))
- Divider()
- version
- Divider()
- copyToClipboardButton
+
+ VStack(spacing: 0) {
+ version
+ Divider()
+ copyToClipboardButton
+ }
+ .background(Color.expoSecondarySystemBackground)
+ .cornerRadius(12)
}
if isAdminUser {
@@ -139,33 +143,37 @@ struct SettingsTabView: View {
Text(viewModel.buildInfo["appVersion"] as? String ?? "")
.foregroundColor(.secondary)
}
+ .padding(.horizontal)
.padding(.vertical, 12)
}
private var copyToClipboardButton: some View {
- HStack {
#if os(tvOS)
- Button("Clipboard not available on tvOS") {}
+ Text("Clipboard not available on tvOS")
+ .padding(.horizontal)
+ .padding(.vertical, 12)
#else
- Button(showCopiedMessage ? "Copied to clipboard!" : "Copy system info") {
- let buildInfoJSON = createBuildInfoJSON()
- let clipboard = UIPasteboard.general
- clipboard.string = buildInfoJSON
- showCopiedMessage = true
-
- DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
- showCopiedMessage = false
- }
+ Button {
+ UIPasteboard.general.string = createBuildInfoJSON()
+ showCopiedMessage = true
+
+ DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
+ showCopiedMessage = false
}
- Spacer()
- Image(systemName: "clipboard")
- .resizable()
- .scaledToFit()
- .frame(width: 16, height: 16)
- .foregroundColor(.blue)
-#endif
+ } label: {
+ HStack {
+ Text(showCopiedMessage ? "Copied to clipboard!" : "Copy system info")
+ Spacer()
+ Image(systemName: showCopiedMessage ? "checkmark" : "clipboard")
+ .foregroundColor(.secondary)
+ }
+ .contentShape(Rectangle())
}
+ .buttonStyle(.plain)
+ .foregroundColor(showCopiedMessage ? .green : .primary)
+ .padding(.horizontal)
.padding(.vertical, 12)
+#endif
}
private var isAdminUser: Bool {
@@ -173,37 +181,74 @@ struct SettingsTabView: View {
}
private var debugSettings: some View {
- Section("Debug Settings") {
- Button(showCacheClearedMessage ? "Network cache cleared!" : "Clear network cache") {
- clearNetworkCache()
+ VStack(alignment: .leading, spacing: 8) {
+ Text("Debug Settings".uppercased())
+ .font(.caption)
+ .foregroundColor(.primary.opacity(0.6))
+
+ VStack(spacing: 0) {
+ clearNetworkCacheRow
+ Divider()
+ defaultPageSizeRow
}
- .foregroundColor(showCacheClearedMessage ? .green : nil)
+ .background(Color.expoSecondarySystemBackground)
+ .cornerRadius(12)
+ }
+ }
- VStack(alignment: .leading) {
- Text("Default Page Size")
- Text("Sets the number of items fetched for branches and updates")
- .foregroundStyle(.secondary)
- .font(.footnote)
- Picker("", selection: $defaultPageSize) {
- Text("1").tag(1)
- Text("5").tag(5)
- Text("10").tag(10)
- }
- .pickerStyle(.segmented)
+ private var clearNetworkCacheRow: some View {
+ Button {
+ clearNetworkCache()
+ } label: {
+ HStack {
+ Text(showCacheClearedMessage ? "Network cache cleared!" : "Clear network cache")
+ Spacer()
+ Image(systemName: showCacheClearedMessage ? "checkmark" : "trash")
+ .foregroundColor(showCacheClearedMessage ? .green : .secondary)
+ }
+ .contentShape(Rectangle())
+ }
+ .buttonStyle(.plain)
+ .foregroundColor(showCacheClearedMessage ? .green : .primary)
+ .padding(.horizontal)
+ .padding(.vertical, 12)
+ }
+
+ private var defaultPageSizeRow: some View {
+ VStack(alignment: .leading, spacing: 4) {
+ Text("Default Page Size")
+ Text("Sets the number of items fetched for branches and updates")
+ .foregroundStyle(.secondary)
+ .font(.footnote)
+ Picker("", selection: $defaultPageSize) {
+ Text("1").tag(1)
+ Text("5").tag(5)
+ Text("10").tag(10)
}
+ .pickerStyle(.segmented)
}
+ .padding(.horizontal)
+ .padding(.vertical, 12)
}
private var easUpdateConfig: some View {
- Section("EAS Update Configuration") {
+ VStack(alignment: .leading, spacing: 8) {
+ Text("EAS Update Configuration".uppercased())
+ .font(.caption)
+ .foregroundColor(.primary.opacity(0.6))
+
VStack(alignment: .leading, spacing: 8) {
Text(createEASConfigJSON())
.font(.system(.caption, design: .monospaced))
#if !os(tvOS)
.textSelection(.enabled)
#endif
- .padding(.vertical, 4)
}
+ .frame(maxWidth: .infinity, alignment: .leading)
+ .padding(.horizontal)
+ .padding(.vertical, 12)
+ .background(Color.expoSecondarySystemBackground)
+ .cornerRadius(12)
}
}
@@ -233,36 +278,70 @@ struct SettingsTabView: View {
}
#if !targetEnvironment(simulator)
+ private var localNetworkStatus: (text: String, icon: String, color: Color)? {
+ switch viewModel.permissionStatus {
+ case .granted:
+ return ("Allowed", "checkmark.circle.fill", .green)
+ case .denied:
+ return ("Not allowed", "xmark.circle.fill", .red)
+ case .checking, .unknown:
+ return nil
+ }
+ }
+
private var localNetworkDebugSettings: some View {
VStack(alignment: .leading, spacing: 8) {
VStack(spacing: 0) {
- Toggle("Local Network", isOn: .constant(viewModel.permissionStatus == .granted))
- .disabled(true)
- .padding()
+ localNetworkStatusRow
if viewModel.permissionStatus == .denied {
Divider()
-
- #if os(iOS)
- Button {
- if let url = URL(string: UIApplication.openSettingsURLString) {
- UIApplication.shared.open(url)
- }
- } label: {
- HStack {
- Text("Open App Settings")
- Spacer()
- Image(systemName: "gear")
- .foregroundColor(.blue)
- }
- }
- .padding()
- #endif
+ openAppSettingsRow
}
}
.background(Color.expoSecondarySystemBackground)
.cornerRadius(12)
}
}
+
+ private var localNetworkStatusRow: some View {
+ HStack {
+ Text("Local Network")
+ Spacer()
+ if let status = localNetworkStatus {
+ Text(status.text)
+ .foregroundColor(.secondary)
+ Image(systemName: status.icon)
+ .foregroundColor(status.color)
+ } else {
+ ProgressView()
+ }
+ }
+ .padding(.horizontal)
+ .padding(.vertical, 12)
+ }
+
+ @ViewBuilder
+ private var openAppSettingsRow: some View {
+ #if os(iOS)
+ Button {
+ if let url = URL(string: UIApplication.openSettingsURLString) {
+ UIApplication.shared.open(url)
+ }
+ } label: {
+ HStack {
+ Text("Open App Settings")
+ Spacer()
+ Image(systemName: "gear")
+ .foregroundColor(.secondary)
+ }
+ .contentShape(Rectangle())
+ }
+ .buttonStyle(.plain)
+ .foregroundColor(.primary)
+ .padding(.horizontal)
+ .padding(.vertical, 12)
+ #endif
+ }
#endif
}
diff --git a/packages/expo-dev-launcher/ios/SwiftUI/UpdatesTab/UpdatesListView.swift b/packages/expo-dev-launcher/ios/SwiftUI/UpdatesTab/UpdatesListView.swift
index 9622dd1b7bd7be..5a9c159252bd4f 100644
--- a/packages/expo-dev-launcher/ios/SwiftUI/UpdatesTab/UpdatesListView.swift
+++ b/packages/expo-dev-launcher/ios/SwiftUI/UpdatesTab/UpdatesListView.swift
@@ -172,22 +172,44 @@ struct UpdatesListView: View {
}
private var emptyUpdates: some View {
- Section {
- VStack(spacing: 16) {
- Image(systemName: "tray")
- .font(.largeTitle)
- .foregroundColor(.gray)
-
- Text("No updates available")
- .font(.headline)
-
- Text(filterByCompatibility ? "No compatible updates found for this runtime version." : "No updates found.")
- .font(.caption)
- .foregroundStyle(.secondary)
- .multilineTextAlignment(.center)
+ VStack(spacing: 16) {
+ Image(systemName: "tray")
+ .resizable()
+ .scaledToFit()
+ .frame(width: 44, height: 44)
+ .foregroundColor(.gray)
+
+ if filterByCompatibility {
+ VStack(spacing: 8) {
+ Text("No compatible updates")
+ .font(.headline)
+ .multilineTextAlignment(.center)
+
+ Text("No updates match this runtime version. Turn off \"Compatible only\" to see all updates.")
+ .font(.system(size: 14))
+ .multilineTextAlignment(.center)
+ .foregroundStyle(.secondary)
+ }
+ } else {
+ VStack(spacing: 8) {
+ Text("No updates yet")
+ .font(.headline)
+ .multilineTextAlignment(.center)
+
+ Text("Publish an update with EAS Update and it will appear here.")
+ .font(.system(size: 14))
+ .multilineTextAlignment(.center)
+ .foregroundStyle(.secondary)
+
+ if let destination = URL(string: "https://docs.expo.dev/eas-update/getting-started/") {
+ Link("Learn how to publish", destination: destination)
+ .font(.system(size: 14))
+ .foregroundColor(.blue)
+ }
+ }
}
- .padding()
}
+ .padding()
}
}
// swiftlint:enable closure_body_length
diff --git a/packages/expo-dev-menu/CHANGELOG.md b/packages/expo-dev-menu/CHANGELOG.md
index 40845c7bf21b43..61970e7432876d 100644
--- a/packages/expo-dev-menu/CHANGELOG.md
+++ b/packages/expo-dev-menu/CHANGELOG.md
@@ -8,6 +8,8 @@
### 🐛 Bug fixes
+- [iOS] Show the floating Tools button at its final position instead of animating in from the top-left corner. ([#46762](https://github.com/expo/expo/pull/46762) by [@alanjhughes](https://github.com/alanjhughes))
+
### 💡 Others
## 56.0.15 — 2026-05-26
diff --git a/packages/expo-dev-menu/ios/FAB/DevMenuFABView.swift b/packages/expo-dev-menu/ios/FAB/DevMenuFABView.swift
index bd6a82066c8d8f..d9b523c510a639 100644
--- a/packages/expo-dev-menu/ios/FAB/DevMenuFABView.swift
+++ b/packages/expo-dev-menu/ios/FAB/DevMenuFABView.swift
@@ -134,6 +134,7 @@ struct DevMenuFABView: View {
@State private var isDragging = false
@State private var isPressed = false
@State private var dragStartPosition: CGPoint = .zero
+ @State private var didPosition = false
// Get safe area from window since .ignoresSafeArea() may zero out geometry values
private var windowSafeArea: UIEdgeInsets {
@@ -169,23 +170,7 @@ struct DevMenuFABView: View {
.position(x: currentFrame.midX, y: currentFrame.midY)
.gesture(dragGesture(bounds: geometry.size, safeArea: safeArea))
.onAppear {
- let initialPos: CGPoint
- if let storedPos = Self.loadStoredPosition() {
- let margin = FABConstants.margin
- let minX = margin / 2
- let maxX = geometry.size.width - fabSize.width - margin / 2
- let minY = safeArea.top + FABConstants.verticalPadding
- let maxY = geometry.size.height - fabSize.height - safeArea.bottom - FABConstants.verticalPadding
-
- initialPos = CGPoint(
- x: storedPos.x.clamped(to: minX...maxX),
- y: storedPos.y.clamped(to: minY...maxY)
- )
- } else {
- initialPos = defaultPosition(bounds: geometry.size, safeArea: safeArea)
- }
- position = initialPos
- onFrameChange(CGRect(origin: initialPos, size: fabSize))
+ placeInitially(bounds: geometry.size, safeArea: safeArea)
}
.onChange(of: geometry.size) { newSize in
let newPos = snapToEdge(
@@ -197,7 +182,7 @@ struct DevMenuFABView: View {
position = newPos
onFrameChange(CGRect(origin: newPos, size: fabSize))
}
- .animation(isDragging ? dragSpring : FABConstants.snapAnimation, value: position)
+ .animation(didPosition ? (isDragging ? dragSpring : FABConstants.snapAnimation) : nil, value: position)
}
.ignoresSafeArea()
}
@@ -251,6 +236,31 @@ struct DevMenuFABView: View {
}
}
+ private func placeInitially(bounds: CGSize, safeArea: EdgeInsets) {
+ let initialPos: CGPoint
+ if let storedPos = Self.loadStoredPosition() {
+ let margin = FABConstants.margin
+ let minX = margin / 2
+ let maxX = bounds.width - fabSize.width - margin / 2
+ let minY = safeArea.top + FABConstants.verticalPadding
+ let maxY = bounds.height - fabSize.height - safeArea.bottom - FABConstants.verticalPadding
+
+ initialPos = CGPoint(
+ x: storedPos.x.clamped(to: minX...maxX),
+ y: storedPos.y.clamped(to: minY...maxY)
+ )
+ } else {
+ initialPos = defaultPosition(bounds: bounds, safeArea: safeArea)
+ }
+ position = initialPos
+ onFrameChange(CGRect(origin: initialPos, size: fabSize))
+ // Enable position animations only after the initial placement so the
+ // button appears at its final spot instead of sliding in from (0, 0).
+ DispatchQueue.main.async {
+ didPosition = true
+ }
+ }
+
private func defaultPosition(bounds: CGSize, safeArea: EdgeInsets) -> CGPoint {
CGPoint(
x: bounds.width - fabSize.width - FABConstants.margin / 2,
diff --git a/packages/expo-media-library/CHANGELOG.md b/packages/expo-media-library/CHANGELOG.md
index 25aa9ad376f31c..207289ccec0576 100644
--- a/packages/expo-media-library/CHANGELOG.md
+++ b/packages/expo-media-library/CHANGELOG.md
@@ -6,6 +6,7 @@
### 🎉 New features
+- Add filtering by `isFavorite` to `Query` ([#45769](https://github.com/expo/expo/pull/45769) by [@Wenszel](https://github.com/Wenszel))
- Add `Query.exeForMetadata()` for cheap bulk fetch ([#46485](https://github.com/expo/expo/pull/46485) by [@Wenszel](https://github.com/Wenszel))
### 🐛 Bug fixes
diff --git a/packages/expo-media-library/android/src/main/java/expo/modules/medialibrary/next/MediaLibraryNextModule.kt b/packages/expo-media-library/android/src/main/java/expo/modules/medialibrary/next/MediaLibraryNextModule.kt
index 2f7b9f4aad22cc..f5118b660dceff 100644
--- a/packages/expo-media-library/android/src/main/java/expo/modules/medialibrary/next/MediaLibraryNextModule.kt
+++ b/packages/expo-media-library/android/src/main/java/expo/modules/medialibrary/next/MediaLibraryNextModule.kt
@@ -9,6 +9,7 @@ import expo.modules.kotlin.functions.Coroutine
import expo.modules.kotlin.modules.Module
import expo.modules.kotlin.modules.ModuleDefinition
import expo.modules.kotlin.types.Either
+import expo.modules.kotlin.types.EitherOfThree
import expo.modules.kotlin.types.toKClass
import expo.modules.medialibrary.next.objects.album.Album
import expo.modules.medialibrary.next.objects.album.AlbumQuery
@@ -260,11 +261,11 @@ class MediaLibraryNextModule : Module() {
self.album(album)
}
- Function("eq") { self: Query, field: AssetField, value: Either ->
+ Function("eq") { self: Query, field: AssetField, value: EitherOfThree ->
self.eq(field, MediaStoreQueryFormatter.parse(field, value))
}
- Function("within") { self: Query, field: AssetField, values: List> ->
+ Function("within") { self: Query, field: AssetField, values: List> ->
val stringValues = values.map { value -> MediaStoreQueryFormatter.parse(field, value) }
self.within(field, stringValues)
}
diff --git a/packages/expo-media-library/android/src/main/java/expo/modules/medialibrary/next/objects/query/MediaStoreQueryFormatter.kt b/packages/expo-media-library/android/src/main/java/expo/modules/medialibrary/next/objects/query/MediaStoreQueryFormatter.kt
index 03e8b81a2c2212..03277ca2a78ee8 100644
--- a/packages/expo-media-library/android/src/main/java/expo/modules/medialibrary/next/objects/query/MediaStoreQueryFormatter.kt
+++ b/packages/expo-media-library/android/src/main/java/expo/modules/medialibrary/next/objects/query/MediaStoreQueryFormatter.kt
@@ -1,6 +1,6 @@
package expo.modules.medialibrary.next.objects.query
-import expo.modules.kotlin.types.Either
+import expo.modules.kotlin.types.EitherOfThree
import expo.modules.medialibrary.next.objects.wrappers.MediaType
import expo.modules.medialibrary.next.records.AssetField
import kotlin.time.DurationUnit
@@ -8,10 +8,13 @@ import kotlin.time.toDuration
class MediaStoreQueryFormatter {
companion object {
- fun parse(field: AssetField, value: Either): String {
+ fun parse(field: AssetField, value: EitherOfThree): String {
if (value.`is`(MediaType::class)) {
return parse(value.get(MediaType::class))
}
+ if (value.`is`(Boolean::class)) {
+ return if (value.get(Boolean::class)) "1" else "0"
+ }
return parse(field, value.get(Long::class))
}
diff --git a/packages/expo-media-library/android/src/main/java/expo/modules/medialibrary/next/objects/query/Query.kt b/packages/expo-media-library/android/src/main/java/expo/modules/medialibrary/next/objects/query/Query.kt
index 9d83d49fd15a68..6cb9457f168fd4 100644
--- a/packages/expo-media-library/android/src/main/java/expo/modules/medialibrary/next/objects/query/Query.kt
+++ b/packages/expo-media-library/android/src/main/java/expo/modules/medialibrary/next/objects/query/Query.kt
@@ -36,11 +36,13 @@ class Query(
private var offset: Int? = null
fun eq(field: AssetField, value: String) = apply {
+ if (field == AssetField.IS_FAVORITE && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) return@apply
clauses.add("${field.toMediaStoreColumn()} = ?")
args.add(value)
}
fun within(field: AssetField, values: List) = apply {
+ if (field == AssetField.IS_FAVORITE && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) return@apply
val questionMarks = values.joinToString(", ") { "?" }
clauses.add("${field.toMediaStoreColumn()} IN ($questionMarks)")
args.addAll(values)
diff --git a/packages/expo-media-library/android/src/main/java/expo/modules/medialibrary/next/records/AssetField.kt b/packages/expo-media-library/android/src/main/java/expo/modules/medialibrary/next/records/AssetField.kt
index 9448bb4d0f753f..ea6f9854c58f06 100644
--- a/packages/expo-media-library/android/src/main/java/expo/modules/medialibrary/next/records/AssetField.kt
+++ b/packages/expo-media-library/android/src/main/java/expo/modules/medialibrary/next/records/AssetField.kt
@@ -9,7 +9,8 @@ enum class AssetField(val key: String) : Enumerable {
MEDIA_TYPE("mediaType"),
WIDTH("width"),
HEIGHT("height"),
- DURATION("duration");
+ DURATION("duration"),
+ IS_FAVORITE("isFavorite");
fun toMediaStoreColumn(): String =
when (this) {
@@ -19,5 +20,6 @@ enum class AssetField(val key: String) : Enumerable {
WIDTH -> MediaStore.MediaColumns.WIDTH
HEIGHT -> MediaStore.MediaColumns.HEIGHT
DURATION -> MediaStore.Video.VideoColumns.DURATION
+ IS_FAVORITE -> MediaStore.MediaColumns.IS_FAVORITE
}
}
diff --git a/packages/expo-media-library/build/types/AssetField.d.ts b/packages/expo-media-library/build/types/AssetField.d.ts
index c38988e145ea4a..7281333d329e0f 100644
--- a/packages/expo-media-library/build/types/AssetField.d.ts
+++ b/packages/expo-media-library/build/types/AssetField.d.ts
@@ -5,7 +5,8 @@ export declare enum AssetField {
MEDIA_TYPE = "mediaType",
WIDTH = "width",
HEIGHT = "height",
- DURATION = "duration"
+ DURATION = "duration",
+ IS_FAVORITE = "isFavorite"
}
export type AssetFieldValueMap = {
[AssetField.CREATION_TIME]: number;
@@ -14,5 +15,6 @@ export type AssetFieldValueMap = {
[AssetField.WIDTH]: number;
[AssetField.HEIGHT]: number;
[AssetField.DURATION]: number;
+ [AssetField.IS_FAVORITE]: boolean;
};
//# sourceMappingURL=AssetField.d.ts.map
\ No newline at end of file
diff --git a/packages/expo-media-library/build/types/AssetField.d.ts.map b/packages/expo-media-library/build/types/AssetField.d.ts.map
index ee7791de8dce04..99f9f50009aa41 100644
--- a/packages/expo-media-library/build/types/AssetField.d.ts.map
+++ b/packages/expo-media-library/build/types/AssetField.d.ts.map
@@ -1 +1 @@
-{"version":3,"file":"AssetField.d.ts","sourceRoot":"","sources":["../../src/types/AssetField.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,oBAAY,UAAU;IACpB,aAAa,iBAAiB;IAC9B,iBAAiB,qBAAqB;IACtC,UAAU,cAAc;IACxB,KAAK,UAAU;IACf,MAAM,WAAW;IACjB,QAAQ,aAAa;CACtB;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IACnC,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACvC,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,SAAS,CAAC;IACnC,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAC3B,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAC5B,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC/B,CAAC"}
\ No newline at end of file
+{"version":3,"file":"AssetField.d.ts","sourceRoot":"","sources":["../../src/types/AssetField.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,oBAAY,UAAU;IACpB,aAAa,iBAAiB;IAC9B,iBAAiB,qBAAqB;IACtC,UAAU,cAAc;IACxB,KAAK,UAAU;IACf,MAAM,WAAW;IACjB,QAAQ,aAAa;IACrB,WAAW,eAAe;CAC3B;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IACnC,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACvC,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,SAAS,CAAC;IACnC,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAC3B,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAC5B,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC9B,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;CACnC,CAAC"}
\ No newline at end of file
diff --git a/packages/expo-media-library/build/types/AssetField.js b/packages/expo-media-library/build/types/AssetField.js
index 263c15007acdec..b2013e1956f367 100644
--- a/packages/expo-media-library/build/types/AssetField.js
+++ b/packages/expo-media-library/build/types/AssetField.js
@@ -6,5 +6,6 @@ export var AssetField;
AssetField["WIDTH"] = "width";
AssetField["HEIGHT"] = "height";
AssetField["DURATION"] = "duration";
+ AssetField["IS_FAVORITE"] = "isFavorite";
})(AssetField || (AssetField = {}));
//# sourceMappingURL=AssetField.js.map
\ No newline at end of file
diff --git a/packages/expo-media-library/build/types/AssetField.js.map b/packages/expo-media-library/build/types/AssetField.js.map
index d30b29b4f2424b..31f2aa3275fb09 100644
--- a/packages/expo-media-library/build/types/AssetField.js.map
+++ b/packages/expo-media-library/build/types/AssetField.js.map
@@ -1 +1 @@
-{"version":3,"file":"AssetField.js","sourceRoot":"","sources":["../../src/types/AssetField.ts"],"names":[],"mappings":"AAEA,MAAM,CAAN,IAAY,UAOX;AAPD,WAAY,UAAU;IACpB,4CAA8B,CAAA;IAC9B,oDAAsC,CAAA;IACtC,sCAAwB,CAAA;IACxB,6BAAe,CAAA;IACf,+BAAiB,CAAA;IACjB,mCAAqB,CAAA;AACvB,CAAC,EAPW,UAAU,KAAV,UAAU,QAOrB","sourcesContent":["import type { MediaType } from './MediaType';\n\nexport enum AssetField {\n CREATION_TIME = 'creationTime',\n MODIFICATION_TIME = 'modificationTime',\n MEDIA_TYPE = 'mediaType',\n WIDTH = 'width',\n HEIGHT = 'height',\n DURATION = 'duration',\n}\n\nexport type AssetFieldValueMap = {\n [AssetField.CREATION_TIME]: number;\n [AssetField.MODIFICATION_TIME]: number;\n [AssetField.MEDIA_TYPE]: MediaType;\n [AssetField.WIDTH]: number;\n [AssetField.HEIGHT]: number;\n [AssetField.DURATION]: number;\n};\n"]}
\ No newline at end of file
+{"version":3,"file":"AssetField.js","sourceRoot":"","sources":["../../src/types/AssetField.ts"],"names":[],"mappings":"AAEA,MAAM,CAAN,IAAY,UAQX;AARD,WAAY,UAAU;IACpB,4CAA8B,CAAA;IAC9B,oDAAsC,CAAA;IACtC,sCAAwB,CAAA;IACxB,6BAAe,CAAA;IACf,+BAAiB,CAAA;IACjB,mCAAqB,CAAA;IACrB,wCAA0B,CAAA;AAC5B,CAAC,EARW,UAAU,KAAV,UAAU,QAQrB","sourcesContent":["import type { MediaType } from './MediaType';\n\nexport enum AssetField {\n CREATION_TIME = 'creationTime',\n MODIFICATION_TIME = 'modificationTime',\n MEDIA_TYPE = 'mediaType',\n WIDTH = 'width',\n HEIGHT = 'height',\n DURATION = 'duration',\n IS_FAVORITE = 'isFavorite',\n}\n\nexport type AssetFieldValueMap = {\n [AssetField.CREATION_TIME]: number;\n [AssetField.MODIFICATION_TIME]: number;\n [AssetField.MEDIA_TYPE]: MediaType;\n [AssetField.WIDTH]: number;\n [AssetField.HEIGHT]: number;\n [AssetField.DURATION]: number;\n [AssetField.IS_FAVORITE]: boolean;\n};\n"]}
\ No newline at end of file
diff --git a/packages/expo-media-library/ios/next/MediaLibraryNextModule.swift b/packages/expo-media-library/ios/next/MediaLibraryNextModule.swift
index 8aa825b6935211..5bc19513fb795e 100644
--- a/packages/expo-media-library/ios/next/MediaLibraryNextModule.swift
+++ b/packages/expo-media-library/ios/next/MediaLibraryNextModule.swift
@@ -140,11 +140,11 @@ public final class MediaLibraryNextModule: Module {
return Query(assetMapper: assetMapper)
}
- Function("eq") { (this: Query, assetField: AssetField, value: Either) in
+ Function("eq") { (this: Query, assetField: AssetField, value: EitherOfThree) in
try this.eq(assetField, value)
}
- Function("within") { (this: Query, assetField: AssetField, values: Either<[MediaTypeNext], [Int]>) in
+ Function("within") { (this: Query, assetField: AssetField, values: EitherOfThree<[MediaTypeNext], [Int], [Bool]>) in
try this.within(assetField, values)
}
diff --git a/packages/expo-media-library/ios/next/objects/Query/AssetField.swift b/packages/expo-media-library/ios/next/objects/Query/AssetField.swift
index 881d666b47cdac..ec0e6462cef1a7 100644
--- a/packages/expo-media-library/ios/next/objects/Query/AssetField.swift
+++ b/packages/expo-media-library/ios/next/objects/Query/AssetField.swift
@@ -7,6 +7,7 @@ enum AssetField: String, Enumerable {
case WIDTH = "width"
case HEIGHT = "height"
case DURATION = "duration"
+ case IS_FAVORITE = "isFavorite"
func photosKey() -> String {
switch self {
@@ -22,6 +23,8 @@ enum AssetField: String, Enumerable {
return "duration"
case .MEDIA_TYPE:
return "mediaType"
+ case .IS_FAVORITE:
+ return "isFavorite"
}
}
}
diff --git a/packages/expo-media-library/ios/next/objects/Query/PredicateBuilder.swift b/packages/expo-media-library/ios/next/objects/Query/PredicateBuilder.swift
index 0d756c752e6726..5fd05c1b179c36 100644
--- a/packages/expo-media-library/ios/next/objects/Query/PredicateBuilder.swift
+++ b/packages/expo-media-library/ios/next/objects/Query/PredicateBuilder.swift
@@ -28,21 +28,32 @@ class AssetFieldPredicateBuilder {
return NSPredicate(format: "\(assetField.photosKey()) \(symbol) %@", argumentArray: [nsValues])
}
- static func buildPredicate(assetField: AssetField, value: Either, symbol: String) throws -> NSPredicate {
- if let intVal = try? value.as(Int.self) {
+ static func buildPredicate(assetField: AssetField, value: Bool, symbol: String) -> NSPredicate {
+ return NSPredicate(format: "\(assetField.photosKey()) \(symbol) %@", argumentArray: [NSNumber(value: value)])
+ }
+
+ static func buildPredicate(assetField: AssetField, value: EitherOfThree, symbol: String) throws -> NSPredicate {
+ if let boolVal: Bool = value.get() {
+ return buildPredicate(assetField: assetField, value: boolVal, symbol: symbol)
+ }
+ if let intVal: Int = value.get() {
return buildPredicate(assetField: assetField, value: intVal, symbol: symbol)
}
- if let mediaVal = try? value.as(MediaTypeNext.self) {
+ if let mediaVal: MediaTypeNext = value.get() {
return buildPredicate(assetField: assetField, value: mediaVal, symbol: symbol)
}
throw PredicateBuilderException("Unsupported Either type for \(assetField)")
}
- static func buildPredicate(assetField: AssetField, values: Either<[MediaTypeNext], [Int]>, symbol: String) throws -> NSPredicate {
- if let intValues = try? values.as([Int].self) {
+ static func buildPredicate(assetField: AssetField, values: EitherOfThree<[MediaTypeNext], [Int], [Bool]>, symbol: String) throws -> NSPredicate {
+ if let boolValues: [Bool] = values.get() {
+ let nsValues = boolValues.map { NSNumber(value: $0) }
+ return NSPredicate(format: "\(assetField.photosKey()) \(symbol) %@", argumentArray: [nsValues])
+ }
+ if let intValues: [Int] = values.get() {
return buildPredicate(assetField: assetField, values: intValues, symbol: symbol)
}
- if let mediaValues = try? values.as([MediaTypeNext].self) {
+ if let mediaValues: [MediaTypeNext] = values.get() {
return buildPredicate(assetField: assetField, values: mediaValues, symbol: symbol)
}
throw PredicateBuilderException("Unsupported Either type for \(assetField)")
diff --git a/packages/expo-media-library/ios/next/objects/Query/Query.swift b/packages/expo-media-library/ios/next/objects/Query/Query.swift
index e8c1c7b48d1dbf..e4539b8e0db565 100644
--- a/packages/expo-media-library/ios/next/objects/Query/Query.swift
+++ b/packages/expo-media-library/ios/next/objects/Query/Query.swift
@@ -13,7 +13,7 @@ class Query: SharedObject {
self.assetMapper = assetMapper
}
- func eq(_ assetField: AssetField, _ value: Either) throws -> Query {
+ func eq(_ assetField: AssetField, _ value: EitherOfThree) throws -> Query {
let predicate = try AssetFieldPredicateBuilder.buildPredicate(
assetField: assetField,
value: value,
@@ -23,7 +23,7 @@ class Query: SharedObject {
return self
}
- func within(_ assetField: AssetField, _ values: Either<[MediaTypeNext], [Int]>) throws -> Query {
+ func within(_ assetField: AssetField, _ values: EitherOfThree<[MediaTypeNext], [Int], [Bool]>) throws -> Query {
let predicate = try AssetFieldPredicateBuilder.buildPredicate(
assetField: assetField,
values: values,
diff --git a/packages/expo-media-library/src/types/AssetField.ts b/packages/expo-media-library/src/types/AssetField.ts
index 9cc048ea69805d..2209ae2bbaff82 100644
--- a/packages/expo-media-library/src/types/AssetField.ts
+++ b/packages/expo-media-library/src/types/AssetField.ts
@@ -7,6 +7,7 @@ export enum AssetField {
WIDTH = 'width',
HEIGHT = 'height',
DURATION = 'duration',
+ IS_FAVORITE = 'isFavorite',
}
export type AssetFieldValueMap = {
@@ -16,4 +17,5 @@ export type AssetFieldValueMap = {
[AssetField.WIDTH]: number;
[AssetField.HEIGHT]: number;
[AssetField.DURATION]: number;
+ [AssetField.IS_FAVORITE]: boolean;
};
diff --git a/packages/expo-modules-autolinking/CHANGELOG.md b/packages/expo-modules-autolinking/CHANGELOG.md
index 5767831216e1ed..f94a78d464a324 100644
--- a/packages/expo-modules-autolinking/CHANGELOG.md
+++ b/packages/expo-modules-autolinking/CHANGELOG.md
@@ -6,6 +6,8 @@
### 🎉 New features
+- Add option to specify targets to use with inline modules ([#46698](https://github.com/expo/expo/pull/46698) by [@HubertBer](https://github.com/HubertBer))
+
### 🐛 Bug fixes
- Fixed build error for unresolvable `expo-modules-macros-plugin`. ([#46294](https://github.com/expo/expo/pull/46294) by [@kudo](https://github.com/kudo))
@@ -13,6 +15,7 @@
### 💡 Others
+- [Android] Make the autolinking Gradle plugin compatible with Android Gradle Plugin 9. ([#46766](https://github.com/expo/expo/pull/46766) by [@lukmccall](https://github.com/lukmccall))
- Add experimental `tvos` and `macos` resolution ([#46344](https://github.com/expo/expo/pull/46344) by [@kitten](https://github.com/kitten))
## 56.0.13 — 2026-05-26
diff --git a/packages/expo-modules-autolinking/android/expo-gradle-plugin/expo-autolinking-plugin/src/main/kotlin/expo/modules/plugin/ExpoAutolinkingPlugin.kt b/packages/expo-modules-autolinking/android/expo-gradle-plugin/expo-autolinking-plugin/src/main/kotlin/expo/modules/plugin/ExpoAutolinkingPlugin.kt
index 702910510628e3..9a0dd66aa11ac5 100644
--- a/packages/expo-modules-autolinking/android/expo-gradle-plugin/expo-autolinking-plugin/src/main/kotlin/expo/modules/plugin/ExpoAutolinkingPlugin.kt
+++ b/packages/expo-modules-autolinking/android/expo-gradle-plugin/expo-autolinking-plugin/src/main/kotlin/expo/modules/plugin/ExpoAutolinkingPlugin.kt
@@ -1,8 +1,8 @@
package expo.modules.plugin
+import com.android.build.api.dsl.ApplicationExtension
+import com.android.build.api.dsl.LibraryExtension
import com.android.build.api.variant.AndroidComponentsExtension
-import com.android.build.gradle.BaseExtension
-import com.android.build.gradle.internal.tasks.factory.dependsOn
import expo.modules.plugin.configuration.ExpoModule
import expo.modules.plugin.text.Colors
import expo.modules.plugin.text.withColor
@@ -84,7 +84,7 @@ open class ExpoAutolinkingPlugin : Plugin {
// Ensures that the task is executed before the build.
project.tasks
.named("preBuild", Task::class.java)
- .dependsOn(generatePackagesList)
+ .configure { it.dependsOn(generatePackagesList) }
// Adds the generated file to the source set.
project.extensions.getByType(AndroidComponentsExtension::class.java).finalizeDsl { ext ->
@@ -101,7 +101,7 @@ open class ExpoAutolinkingPlugin : Plugin {
}
fun getInlineModulesDir(project: Project): Provider {
- return project.layout.buildDirectory.dir("inline/modules");
+ return project.layout.buildDirectory.dir("inline/modules")
}
fun getPackageListFile(project: Project): Provider {
@@ -130,10 +130,10 @@ open class ExpoAutolinkingPlugin : Plugin {
project: Project,
appProject: Project
) {
- val appAndroid = appProject.extensions.findByName("android") as? BaseExtension ?: run {
+ val appAndroid = appProject.extensions.findByName("android") as? ApplicationExtension ?: run {
return
}
- val consumerAndroid = project.extensions.findByName("android") as? BaseExtension ?: run {
+ val consumerAndroid = project.extensions.findByName("android") as? LibraryExtension ?: run {
return
}
@@ -143,15 +143,15 @@ open class ExpoAutolinkingPlugin : Plugin {
private fun syncFlavorDimensions(
project: Project,
- consumerAndroid: BaseExtension,
- appAndroid: BaseExtension
+ consumerAndroid: LibraryExtension,
+ appAndroid: ApplicationExtension
): List {
val appDimensions = appAndroid
- .flavorDimensionList
+ .flavorDimensions
.takeIf { it.isNotEmpty() }
?: return emptyList()
- val consumerDimensions = (consumerAndroid.flavorDimensionList).toMutableList()
+ val consumerDimensions = (consumerAndroid.flavorDimensions).toMutableList()
val dimensionsAdded = appDimensions.any { dimension ->
if (dimension !in consumerDimensions) {
consumerDimensions.add(dimension)
@@ -162,7 +162,8 @@ open class ExpoAutolinkingPlugin : Plugin {
}
if (dimensionsAdded) {
- consumerAndroid.flavorDimensions(*consumerDimensions.toTypedArray())
+ consumerAndroid.flavorDimensions.clear()
+ consumerAndroid.flavorDimensions.addAll(consumerDimensions)
project.logger.quiet(" -> Copied/merged flavorDimensions: ${consumerDimensions.joinToString()}")
}
@@ -171,8 +172,8 @@ open class ExpoAutolinkingPlugin : Plugin {
private fun copyMissingProductFlavors(
project: Project,
- consumerAndroid: BaseExtension,
- appAndroid: BaseExtension,
+ consumerAndroid: LibraryExtension,
+ appAndroid: ApplicationExtension,
appDimensions: List
) {
val appFlavors = appAndroid.productFlavors
diff --git a/packages/expo-modules-autolinking/build/autolinking/generatePackageList.d.ts b/packages/expo-modules-autolinking/build/autolinking/generatePackageList.d.ts
index eaa41019287787..397dd9e8dcc405 100644
--- a/packages/expo-modules-autolinking/build/autolinking/generatePackageList.d.ts
+++ b/packages/expo-modules-autolinking/build/autolinking/generatePackageList.d.ts
@@ -4,6 +4,10 @@ interface GenerateModulesProviderParams {
targetPath: string;
entitlementPath: string | null;
watchedDirectories: string[];
+ inlineModulesTargets: {
+ mainTarget?: string;
+ targets: string[];
+ };
appRoot: string;
}
/** Generates ExpoModulesProvider file listing all packages to link (Apple-only)
diff --git a/packages/expo-modules-autolinking/build/autolinking/generatePackageList.js.map b/packages/expo-modules-autolinking/build/autolinking/generatePackageList.js.map
index a55cb0218d2a25..4222bb30e2d33c 100644
--- a/packages/expo-modules-autolinking/build/autolinking/generatePackageList.js.map
+++ b/packages/expo-modules-autolinking/build/autolinking/generatePackageList.js.map
@@ -1 +1 @@
-{"version":3,"file":"generatePackageList.js","sourceRoot":"","sources":["../../src/autolinking/generatePackageList.ts"],"names":[],"mappings":";;AAaA,oEAgBC;AA7BD,4CAAmE;AAWnE;GACG;AACI,KAAK,UAAU,4BAA4B,CAChD,OAA2B,EAC3B,MAAqC;IAErC,MAAM,eAAe,GAAG,IAAA,+CAAmC,EAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC7E,IAAI,CAAC,CAAC,8BAA8B,IAAI,eAAe,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CACb,8DAA8D,MAAM,CAAC,QAAQ,GAAG,CACjF,CAAC;IACJ,CAAC;IACD,MAAM,eAAe,CAAC,4BAA4B,CAChD,OAAgC,EAChC,MAAM,CAAC,UAAU,EACjB,MAAM,CAAC,eAAe,EACtB,MAAM,CACP,CAAC;AACJ,CAAC"}
\ No newline at end of file
+{"version":3,"file":"generatePackageList.js","sourceRoot":"","sources":["../../src/autolinking/generatePackageList.ts"],"names":[],"mappings":";;AAcA,oEAgBC;AA9BD,4CAAmE;AAYnE;GACG;AACI,KAAK,UAAU,4BAA4B,CAChD,OAA2B,EAC3B,MAAqC;IAErC,MAAM,eAAe,GAAG,IAAA,+CAAmC,EAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC7E,IAAI,CAAC,CAAC,8BAA8B,IAAI,eAAe,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CACb,8DAA8D,MAAM,CAAC,QAAQ,GAAG,CACjF,CAAC;IACJ,CAAC;IACD,MAAM,eAAe,CAAC,4BAA4B,CAChD,OAAgC,EAChC,MAAM,CAAC,UAAU,EACjB,MAAM,CAAC,eAAe,EACtB,MAAM,CACP,CAAC;AACJ,CAAC"}
\ No newline at end of file
diff --git a/packages/expo-modules-autolinking/build/commands/generateModulesProviderCommand.js b/packages/expo-modules-autolinking/build/commands/generateModulesProviderCommand.js
index b275bb85baee81..bf753fc4a09ef8 100644
--- a/packages/expo-modules-autolinking/build/commands/generateModulesProviderCommand.js
+++ b/packages/expo-modules-autolinking/build/commands/generateModulesProviderCommand.js
@@ -39,11 +39,13 @@ function generateModulesProviderCommand(cli) {
.then((file) => JSON.parse(file))
.catch(() => ({}));
const watchedDirectories = JSON.parse(podfileProperties['expo.inlineModules.watchedDirectories'] ?? '[]');
+ const inlineModulesTargets = JSON.parse(podfileProperties['expo.inlineModules.xcodeProjectTargets'] ?? '{"targets":[]}');
await (0, generatePackageList_1.generateModulesProviderAsync)(filteredModules, {
platform,
targetPath: commandArguments.target,
entitlementPath: commandArguments.entitlement ?? null,
watchedDirectories,
+ inlineModulesTargets,
appRoot,
});
});
diff --git a/packages/expo-modules-autolinking/build/commands/generateModulesProviderCommand.js.map b/packages/expo-modules-autolinking/build/commands/generateModulesProviderCommand.js.map
index 220700955ab760..20a4248200ccdf 100644
--- a/packages/expo-modules-autolinking/build/commands/generateModulesProviderCommand.js.map
+++ b/packages/expo-modules-autolinking/build/commands/generateModulesProviderCommand.js.map
@@ -1 +1 @@
-{"version":3,"file":"generateModulesProviderCommand.js","sourceRoot":"","sources":["../../src/commands/generateModulesProviderCommand.ts"],"names":[],"mappings":";;;;;AAsBA,wEAyDC;AA9ED,4CAAoB;AAGpB,6DAAoG;AACpG,4DAA8D;AAC9D,4EAAkF;AAClF,kEAAoE;AAcpE,0EAA0E;AAC1E,SAAgB,8BAA8B,CAAC,GAA8B;IAC3E,OAAO,IAAA,iDAA4B,EAAC,GAAG,CAAC,OAAO,CAAC,4CAA4C,CAAC,CAAC;SAC3F,MAAM,CACL,qBAAqB,EACrB,uEAAuE,CACxE;SACA,MAAM,CAAC,sBAAsB,EAAE,mDAAmD,CAAC;SACnF,MAAM,CACL,8BAA8B,EAC9B,qEAAqE,CACtE;SACA,MAAM,CAAC,mBAAmB,EAAE,iCAAiC,CAAC;SAC9D,MAAM,CAAC,uCAAuC,EAAE,sCAAsC,CAAC;SACvF,MAAM,CACL,KAAK,EAAE,WAA4B,EAAE,gBAAkD,EAAE,EAAE;QACzF,MAAM,QAAQ,GAAG,gBAAgB,CAAC,QAAQ,IAAI,OAAO,CAAC;QACtD,MAAM,wBAAwB,GAAG,IAAA,mDAA8B,EAAC;YAC9D,GAAG,gBAAgB;YACnB,WAAW;SACZ,CAAC,CAAC;QACH,MAAM,kBAAkB,GAAG,MAAM,wBAAwB,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAEvF,MAAM,OAAO,GAAG,gBAAgB,CAAC,OAAO,IAAI,CAAC,MAAM,wBAAwB,CAAC,UAAU,EAAE,CAAC,CAAC;QAC1F,MAAM,wBAAwB,GAAG,MAAM,IAAA,8BAAgB,EAAC;YACtD,kBAAkB,EAAE,MAAM,wBAAwB,CAAC,kBAAkB,CAAC,QAAQ,CAAC;YAC/E,OAAO;SACR,CAAC,CAAC;QACH,MAAM,yBAAyB,GAAG,MAAM,IAAA,oCAAmB,EACzD,wBAAwB,EACxB,kBAAkB,CACnB,CAAC;QAEF,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,gBAAgB,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;QAChE,MAAM,eAAe,GAAG,yBAAyB,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAClE,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CACvC,CAAC;QAEF,MAAM,iBAAiB,GAA6B,MAAM,YAAE,CAAC,QAAQ;aAClE,QAAQ,CAAC,gBAAgB,CAAC,yBAAyB,EAAE;YACpD,QAAQ,EAAE,MAAM;SACjB,CAAC;aACD,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;aAChC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAErB,MAAM,kBAAkB,GAAG,IAAI,CAAC,KAAK,CACnC,iBAAiB,CAAC,uCAAuC,CAAC,IAAI,IAAI,CACnE,CAAC;QAEF,MAAM,IAAA,kDAA4B,EAAC,eAAe,EAAE;YAClD,QAAQ;YACR,UAAU,EAAE,gBAAgB,CAAC,MAAM;YACnC,eAAe,EAAE,gBAAgB,CAAC,WAAW,IAAI,IAAI;YACrD,kBAAkB;YAClB,OAAO;SACR,CAAC,CAAC;IACL,CAAC,CACF,CAAC;AACN,CAAC"}
\ No newline at end of file
+{"version":3,"file":"generateModulesProviderCommand.js","sourceRoot":"","sources":["../../src/commands/generateModulesProviderCommand.ts"],"names":[],"mappings":";;;;;AAuBA,wEA8DC;AApFD,4CAAoB;AAGpB,6DAAoG;AACpG,4DAA8D;AAC9D,4EAAkF;AAClF,kEAAoE;AAepE,0EAA0E;AAC1E,SAAgB,8BAA8B,CAAC,GAA8B;IAC3E,OAAO,IAAA,iDAA4B,EAAC,GAAG,CAAC,OAAO,CAAC,4CAA4C,CAAC,CAAC;SAC3F,MAAM,CACL,qBAAqB,EACrB,uEAAuE,CACxE;SACA,MAAM,CAAC,sBAAsB,EAAE,mDAAmD,CAAC;SACnF,MAAM,CACL,8BAA8B,EAC9B,qEAAqE,CACtE;SACA,MAAM,CAAC,mBAAmB,EAAE,iCAAiC,CAAC;SAC9D,MAAM,CAAC,uCAAuC,EAAE,sCAAsC,CAAC;SACvF,MAAM,CACL,KAAK,EAAE,WAA4B,EAAE,gBAAkD,EAAE,EAAE;QACzF,MAAM,QAAQ,GAAG,gBAAgB,CAAC,QAAQ,IAAI,OAAO,CAAC;QACtD,MAAM,wBAAwB,GAAG,IAAA,mDAA8B,EAAC;YAC9D,GAAG,gBAAgB;YACnB,WAAW;SACZ,CAAC,CAAC;QACH,MAAM,kBAAkB,GAAG,MAAM,wBAAwB,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAEvF,MAAM,OAAO,GAAG,gBAAgB,CAAC,OAAO,IAAI,CAAC,MAAM,wBAAwB,CAAC,UAAU,EAAE,CAAC,CAAC;QAC1F,MAAM,wBAAwB,GAAG,MAAM,IAAA,8BAAgB,EAAC;YACtD,kBAAkB,EAAE,MAAM,wBAAwB,CAAC,kBAAkB,CAAC,QAAQ,CAAC;YAC/E,OAAO;SACR,CAAC,CAAC;QACH,MAAM,yBAAyB,GAAG,MAAM,IAAA,oCAAmB,EACzD,wBAAwB,EACxB,kBAAkB,CACnB,CAAC;QAEF,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,gBAAgB,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;QAChE,MAAM,eAAe,GAAG,yBAAyB,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAClE,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CACvC,CAAC;QAEF,MAAM,iBAAiB,GAA6B,MAAM,YAAE,CAAC,QAAQ;aAClE,QAAQ,CAAC,gBAAgB,CAAC,yBAAyB,EAAE;YACpD,QAAQ,EAAE,MAAM;SACjB,CAAC;aACD,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;aAChC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAErB,MAAM,kBAAkB,GAAG,IAAI,CAAC,KAAK,CACnC,iBAAiB,CAAC,uCAAuC,CAAC,IAAI,IAAI,CACnE,CAAC;QAEF,MAAM,oBAAoB,GAAG,IAAI,CAAC,KAAK,CACrC,iBAAiB,CAAC,wCAAwC,CAAC,IAAI,gBAAgB,CAChF,CAAC;QAEF,MAAM,IAAA,kDAA4B,EAAC,eAAe,EAAE;YAClD,QAAQ;YACR,UAAU,EAAE,gBAAgB,CAAC,MAAM;YACnC,eAAe,EAAE,gBAAgB,CAAC,WAAW,IAAI,IAAI;YACrD,kBAAkB;YAClB,oBAAoB;YACpB,OAAO;SACR,CAAC,CAAC;IACL,CAAC,CACF,CAAC;AACN,CAAC"}
\ No newline at end of file
diff --git a/packages/expo-modules-autolinking/build/inlineModules/iosInlineModules.d.ts b/packages/expo-modules-autolinking/build/inlineModules/iosInlineModules.d.ts
index 9597b038231b0e..5c7fe5caece58a 100644
--- a/packages/expo-modules-autolinking/build/inlineModules/iosInlineModules.d.ts
+++ b/packages/expo-modules-autolinking/build/inlineModules/iosInlineModules.d.ts
@@ -1,2 +1,9 @@
import type { ModuleIosConfig } from '../types';
export declare function getIosInlineModulesClassNames(watchedDirectories: string[], appRoot: string): Promise;
+export declare function isTargetInInlineModulesTargets({ targetPath, inlineModulesTargets, }: {
+ targetPath: string;
+ inlineModulesTargets: {
+ mainTarget?: string;
+ targets: string[];
+ };
+}): boolean;
diff --git a/packages/expo-modules-autolinking/build/inlineModules/iosInlineModules.js b/packages/expo-modules-autolinking/build/inlineModules/iosInlineModules.js
index 1282a090bde194..2114abfbf230ef 100644
--- a/packages/expo-modules-autolinking/build/inlineModules/iosInlineModules.js
+++ b/packages/expo-modules-autolinking/build/inlineModules/iosInlineModules.js
@@ -1,6 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getIosInlineModulesClassNames = getIosInlineModulesClassNames;
+exports.isTargetInInlineModulesTargets = isTargetInInlineModulesTargets;
const inlineModules_1 = require("./inlineModules");
async function getIosInlineModulesClassNames(watchedDirectories, appRoot) {
return (await (0, inlineModules_1.getMirrorStateObject)(watchedDirectories, appRoot)).swiftModuleClassNames.map((className) => {
@@ -10,4 +11,19 @@ async function getIosInlineModulesClassNames(watchedDirectories, appRoot) {
};
});
}
+function isTargetInInlineModulesTargets({ targetPath, inlineModulesTargets, }) {
+ const targetRegex = /\/Pods-(.+?)\/ExpoModulesProvider\.swift$/;
+ const match = targetPath.match(targetRegex);
+ if (!match) {
+ return false;
+ }
+ const targetName = match[1];
+ if (targetName === undefined) {
+ return false;
+ }
+ if (inlineModulesTargets.mainTarget) {
+ return targetName === inlineModulesTargets.mainTarget;
+ }
+ return inlineModulesTargets.targets.includes(targetName);
+}
//# sourceMappingURL=iosInlineModules.js.map
\ No newline at end of file
diff --git a/packages/expo-modules-autolinking/build/inlineModules/iosInlineModules.js.map b/packages/expo-modules-autolinking/build/inlineModules/iosInlineModules.js.map
index e9ed30b34a1933..77405d0bfe8f54 100644
--- a/packages/expo-modules-autolinking/build/inlineModules/iosInlineModules.js.map
+++ b/packages/expo-modules-autolinking/build/inlineModules/iosInlineModules.js.map
@@ -1 +1 @@
-{"version":3,"file":"iosInlineModules.js","sourceRoot":"","sources":["../../src/inlineModules/iosInlineModules.ts"],"names":[],"mappings":";;AAGA,sEAYC;AAdD,mDAAuD;AAEhD,KAAK,UAAU,6BAA6B,CACjD,kBAA4B,EAC5B,OAAe;IAEf,OAAO,CAAC,MAAM,IAAA,oCAAoB,EAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC,GAAG,CACxF,CAAC,SAAiB,EAAE,EAAE;QACpB,OAAO;YACL,KAAK,EAAE,SAAS;YAChB,IAAI,EAAE,IAAI;SACX,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
\ No newline at end of file
+{"version":3,"file":"iosInlineModules.js","sourceRoot":"","sources":["../../src/inlineModules/iosInlineModules.ts"],"names":[],"mappings":";;AAGA,sEAYC;AAED,wEAoBC;AApCD,mDAAuD;AAEhD,KAAK,UAAU,6BAA6B,CACjD,kBAA4B,EAC5B,OAAe;IAEf,OAAO,CAAC,MAAM,IAAA,oCAAoB,EAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC,GAAG,CACxF,CAAC,SAAiB,EAAE,EAAE;QACpB,OAAO;YACL,KAAK,EAAE,SAAS;YAChB,IAAI,EAAE,IAAI;SACX,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC;AAED,SAAgB,8BAA8B,CAAC,EAC7C,UAAU,EACV,oBAAoB,GAIrB;IACC,MAAM,WAAW,GAAG,2CAA2C,CAAC;IAChE,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAC5C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC5B,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,oBAAoB,CAAC,UAAU,EAAE,CAAC;QACpC,OAAO,UAAU,KAAK,oBAAoB,CAAC,UAAU,CAAC;IACxD,CAAC;IACD,OAAO,oBAAoB,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;AAC3D,CAAC"}
\ No newline at end of file
diff --git a/packages/expo-modules-autolinking/build/platforms/apple/apple.d.ts b/packages/expo-modules-autolinking/build/platforms/apple/apple.d.ts
index a1cf32b76efd39..c0b0f5b5fafaa6 100644
--- a/packages/expo-modules-autolinking/build/platforms/apple/apple.d.ts
+++ b/packages/expo-modules-autolinking/build/platforms/apple/apple.d.ts
@@ -12,6 +12,11 @@ export declare function resolveModuleAsync(packageName: string, revision: Packag
export declare function resolveExtraBuildDependenciesAsync(projectNativeRoot: string): Promise;
interface GenerateModulesProviderParams {
watchedDirectories: string[];
+ inlineModulesTargets: {
+ mainTarget?: string;
+ targets: string[];
+ };
+ targetPath: string;
appRoot: string;
}
/**
diff --git a/packages/expo-modules-autolinking/build/platforms/apple/apple.js b/packages/expo-modules-autolinking/build/platforms/apple/apple.js
index 9e9eafe32f1477..10052ed75f0c87 100644
--- a/packages/expo-modules-autolinking/build/platforms/apple/apple.js
+++ b/packages/expo-modules-autolinking/build/platforms/apple/apple.js
@@ -115,7 +115,9 @@ async function generatePackageListFileContentAsync(modules, className, entitleme
let modulesClassNames = []
.concat(...modulesToImport.map((module) => module.modules))
.filter(Boolean);
- modulesClassNames = modulesClassNames.concat(await (0, iosInlineModules_1.getIosInlineModulesClassNames)(params.watchedDirectories, params.appRoot));
+ if ((0, iosInlineModules_1.isTargetInInlineModulesTargets)(params)) {
+ modulesClassNames = modulesClassNames.concat(await (0, iosInlineModules_1.getIosInlineModulesClassNames)(params.watchedDirectories, params.appRoot));
+ }
const debugOnlyModulesClassNames = []
.concat(...debugOnlyModules.map((module) => module.modules))
.filter(Boolean);
diff --git a/packages/expo-modules-autolinking/build/platforms/apple/apple.js.map b/packages/expo-modules-autolinking/build/platforms/apple/apple.js.map
index 967ac660d7afab..2554ba22d28a00 100644
--- a/packages/expo-modules-autolinking/build/platforms/apple/apple.js.map
+++ b/packages/expo-modules-autolinking/build/platforms/apple/apple.js.map
@@ -1 +1 @@
-{"version":3,"file":"apple.js","sourceRoot":"","sources":["../../../src/platforms/apple/apple.ts"],"names":[],"mappings":";;;;;AAuBA,4CAIC;AAcD,kDASC;AAGD,gDAiCC;AAED,gFAcC;AASD,oEA0BC;AAyKD,8EASC;AA3TD,oEAA2C;AAC3C,4CAAoB;AACpB,gDAAwB;AAGxB,2EAAqF;AASrF,uCAAsE;AAEtE,MAAM,qBAAqB,GAAG,yBAAyB,CAAC;AACxD,MAAM,0BAA0B,GAAG,iBAAiB,CAAC;AAMrD,SAAgB,gBAAgB,CAC9B,OAA2B;IAE3B,OAAO,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAC5F,CAAC;AAED,MAAM,MAAM,GAAG,IAAI,CAAC;AAEpB,wDAAwD;AACxD,KAAK,UAAU,gBAAgB,CAAC,QAAyB;IACvD,MAAM,kBAAkB,GAAG,QAAQ,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAChE,IAAI,kBAAkB,IAAI,kBAAkB,CAAC,MAAM,EAAE,CAAC;QACpD,OAAO,kBAAkB,CAAC;IAC5B,CAAC;SAAM,CAAC;QACN,OAAO,MAAM,IAAA,8BAAsB,EAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;IAClG,CAAC;AACH,CAAC;AAED,SAAgB,mBAAmB,CACjC,IAA4B,EAC5B,gBAAsC;IAEtC,IAAI,gBAAgB,IAAI,gBAAgB,CAAC,MAAM,EAAE,CAAC;QAChD,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IACD,+FAA+F;IAC/F,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC,CAAC;AACtE,CAAC;AAED,uFAAuF;AAChF,KAAK,UAAU,kBAAkB,CACtC,WAAmB,EACnB,QAAyB,EACzB,WAA4C;IAE5C,MAAM,YAAY,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IACtD,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC9C,OAAO,EAAE,cAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,cAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAC9D,UAAU,EAAE,cAAI,CAAC,OAAO,CAAC,cAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;KAChE,CAAC,CAAC,CAAC;IAEJ,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,EAAE,qBAAqB,EAAE,CAAC,CAAC;IAC7F,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;IAE3D,OAAO;QACL,WAAW;QACX,IAAI;QACJ,gBAAgB;QAChB,KAAK,EAAE,WAAW,CAAC,KAAK;QACxB,OAAO,EACL,QAAQ,CAAC,MAAM;YACb,EAAE,YAAY,EAAE;aACf,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YACzF,EAAE;QACJ,sBAAsB,EAAE,QAAQ,CAAC,MAAM,EAAE,2BAA2B,EAAE,IAAI,EAAE;QAC5E,qBAAqB,EAAE,QAAQ,CAAC,MAAM,EAAE,0BAA0B,EAAE,IAAI,EAAE;QAC1E,SAAS,EAAE,QAAQ,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,KAAK;QACrD,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACrD,CAAC;AACJ,CAAC;AAEM,KAAK,UAAU,kCAAkC,CACtD,iBAAyB;IAEzB,MAAM,SAAS,GAAG,cAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,qBAAqB,CAAC,CAAC;IACtE,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,YAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QAC/D,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACzC,IAAI,WAAW,CAAC,0BAA0B,CAAC,EAAE,CAAC;YAC5C,gGAAgG;YAChG,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,0BAA0B,CAAC,CAAC,CAAC;YACtE,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IACV,OAAO,IAAI,CAAC;AACd,CAAC;AAMD;;GAEG;AACI,KAAK,UAAU,4BAA4B,CAChD,OAA8B,EAC9B,UAAkB,EAClB,eAA8B,EAC9B,MAAqC;IAErC,MAAM,SAAS,GAAG,cAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,cAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;IACtE,MAAM,YAAY,GAAG,MAAM,sBAAsB,CAAC,eAAe,CAAC,CAAC;IACnE,MAAM,oBAAoB,GAAG,MAAM,mCAAmC,CACpE,OAAO,EACP,SAAS,EACT,YAAY,EACZ,MAAM,CACP,CAAC;IACF,MAAM,UAAU,GAAG,cAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAE5C,6FAA6F;IAC7F,IAAI,CAAC;QACH,MAAM,eAAe,GAAG,MAAM,YAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QACvE,IAAI,eAAe,KAAK,oBAAoB,EAAE,CAAC;YAC7C,OAAO;QACT,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IAEV,MAAM,YAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,MAAM,YAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,UAAU,EAAE,oBAAoB,EAAE,MAAM,CAAC,CAAC;AACxE,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,mCAAmC,CAChD,OAA8B,EAC9B,SAAiB,EACjB,YAAuC,EACvC,MAAqC;IAErC,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAC/B,CAAC,MAAM,EAAE,EAAE,CACT,MAAM,CAAC,OAAO,CAAC,MAAM;QACrB,MAAM,CAAC,sBAAsB,CAAC,MAAM;QACpC,MAAM,CAAC,qBAAqB,CAAC,MAAM,CACtC,CAAC;IAEF,MAAM,eAAe,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACzE,MAAM,gBAAgB,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAEzE,MAAM,YAAY,GAAI,EAAe;SAClC,MAAM,CAAC,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;SACnE,MAAM,CAAC,OAAO,CAAC,CAAC;IAEnB,MAAM,qBAAqB,GAAI,EAAe;SAC3C,MAAM,CAAC,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;SACpE,MAAM,CAAC,OAAO,CAAC,CAAC;IAEnB,IAAI,iBAAiB,GAAI,EAAwB;SAC9C,MAAM,CAAC,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;SAC1D,MAAM,CAAC,OAAO,CAAC,CAAC;IAEnB,iBAAiB,GAAG,iBAAiB,CAAC,MAAM,CAC1C,MAAM,IAAA,gDAA6B,EAAC,MAAM,CAAC,kBAAkB,EAAE,MAAM,CAAC,OAAO,CAAC,CAC/E,CAAC;IAEF,MAAM,0BAA0B,GAAI,EAAwB;SACzD,MAAM,CAAC,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;SAC3D,MAAM,CAAC,OAAO,CAAC,CAAC;IAEnB,MAAM,sBAAsB,GAAI,EAAe,CAAC,MAAM,CACpD,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAClE,CAAC;IAEF,MAAM,+BAA+B,GAAI,EAAe,CAAC,MAAM,CAC7D,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,sBAAsB,CAAC,CACnE,CAAC;IAEF,MAAM,2BAA2B,GAAG,eAAe,CAAC,MAAM,CACxD,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,qBAAqB,CAAC,MAAM,CAClD,CAAC;IAEF,MAAM,oCAAoC,GAAG,gBAAgB,CAAC,MAAM,CAClE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,qBAAqB,CAAC,MAAM,CAClD,CAAC;IAEF,OAAO;;;;;;;;EAQP,wBAAwB,CAAC,YAAY,CAAC;EACtC,2BAA2B,CAAC,qBAAqB,CAAC;QAC5C,SAAS;iBACA,SAAS;;EAExB,qBAAqB,CAAC,iBAAiB,EAAE,0BAA0B,CAAC;;;;EAIpE,eAAe,CAAC,sBAAsB,EAAE,+BAA+B,CAAC;;;;EAIxE,6BAA6B,CAAC,2BAA2B,EAAE,oCAAoC,CAAC;;;;kDAIhD,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC;;;CAG7E,CAAC;AACF,CAAC;AAED,SAAS,wBAAwB,CAAC,YAAsB;IACtD,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,mBAAmB,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACtF,CAAC;AAED,SAAS,2BAA2B,CAAC,YAAsB;IACzD,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;QACzB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,CACL,6BAA6B,CAC3B,CAAC,EACD,YAAY,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,mBAAmB,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAC7E,GAAG,IAAI,CACT,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB,CAC5B,OAA0B,EAC1B,gBAAmC;IAEnC,MAAM,gBAAgB,GAAG,yBAAyB,CAAC,OAAO,CAAC,CAAC;IAC5D,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,OAAO,6BAA6B,CAClC,CAAC,EACD,UAAU,yBAAyB,CAAC,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,EAAE,EACvE,UAAU,gBAAgB,EAAE,CAC7B,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,gBAAgB,EAAE,CAAC;IACzD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,yBAAyB,CAAC,OAA0B;IAC3D,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,MAAM,CAAC,KAAK,gBAAgB,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;EACtJ,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;AACtB,CAAC;AAED,SAAS,eAAe,CAAC,UAAoB,EAAE,kBAA4B;IACzE,MAAM,gBAAgB,GAAG,uBAAuB,CAAC,UAAU,CAAC,CAAC;IAC7D,IAAI,kBAAkB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,OAAO,6BAA6B,CAClC,CAAC,EACD,UAAU,uBAAuB,CAAC,UAAU,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,EAAE,EAC1E,UAAU,gBAAgB,EAAE,CAC7B,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,gBAAgB,EAAE,CAAC;IACzD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,uBAAuB,CAAC,UAAoB;IACnD,OAAO,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,SAAS,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;EAC5F,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;AACtB,CAAC;AAED,SAAS,6BAA6B,CACpC,MAA6B,EAC7B,gBAAuC;IAEvC,MAAM,aAAa,GAAG,iCAAiC,CAAC,MAAM,CAAC,CAAC;IAChE,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,OAAO,6BAA6B,CAClC,CAAC,EACD,UAAU,iCAAiC,CAAC,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,EAAE,EAC9E,UAAU,aAAa,EAAE,CAC1B,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,aAAa,EAAE,CAAC;IACtD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAgB,iCAAiC,CAAC,OAA8B;IAC9E,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,qBAAqB,EAAE,CAAC;YACnD,MAAM,CAAC,IAAI,CAAC,kBAAkB,MAAM,CAAC,WAAW,eAAe,OAAO,QAAQ,CAAC,CAAC;QAClF,CAAC;IACH,CAAC;IACD,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;EAC3E,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;AACtB,CAAC;AAED,SAAS,6BAA6B,CACpC,gBAAwB,EACxB,UAAkB,EAClB,eAA8B,IAAI;IAElC,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,iCAAiC,MAAM,CAAC,MAAM,CACrF,gBAAgB,CACjB,GAAG,UAAU,KAAK,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,UAAU,MAAM,CAAC,MAAM,CACvE,gBAAgB,CACjB,GAAG,YAAY,KAAK,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,QAAQ,CAAC;IAC/D,CAAC;IAED,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,iCAAiC,MAAM,CAAC,MAAM,CACrF,gBAAgB,CACjB,GAAG,UAAU,KAAK,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,QAAQ,CAAC;AAC7D,CAAC;AAED,KAAK,UAAU,sBAAsB,CACnC,eAA8B;IAE9B,IAAI,CAAC,eAAe,IAAI,CAAC,CAAC,MAAM,IAAA,uBAAe,EAAC,eAAe,CAAC,CAAC,EAAE,CAAC;QAClE,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAA,qBAAU,EAAC,QAAQ,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,eAAe,CAAC,CAAC,CAAC;IAChG,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5C,OAAO;QACL,SAAS,EAAE,gBAAgB,CAAC,uCAAuC,CAAC,IAAI,SAAS;KAClF,CAAC;AACJ,CAAC"}
\ No newline at end of file
+{"version":3,"file":"apple.js","sourceRoot":"","sources":["../../../src/platforms/apple/apple.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/packages/expo-modules-autolinking/scripts/ios/precompiled_modules.rb b/packages/expo-modules-autolinking/scripts/ios/precompiled_modules.rb
index 524b7d00a82a52..55ee95b8761698 100644
--- a/packages/expo-modules-autolinking/scripts/ios/precompiled_modules.rb
+++ b/packages/expo-modules-autolinking/scripts/ios/precompiled_modules.rb
@@ -1823,7 +1823,7 @@ def react_native_version
end
end
- # Returns the Hermes version, accounting for Hermes v1 opt-in.
+ # Returns the Hermes version. Hermes v1 is the default; classic Hermes is opt-out.
# Mirrors the TypeScript resolution logic in tools/src/prebuilds/Utils.ts.
def hermes_version
@hermes_version ||= begin
diff --git a/packages/expo-modules-autolinking/src/__tests__/inlineModules.test.ts b/packages/expo-modules-autolinking/src/__tests__/inlineModules.test.ts
index 6ffc9cb43bbea7..6dc11bfcf0f5a7 100644
--- a/packages/expo-modules-autolinking/src/__tests__/inlineModules.test.ts
+++ b/packages/expo-modules-autolinking/src/__tests__/inlineModules.test.ts
@@ -13,6 +13,7 @@ import {
getKotlinFileNameWithItsPackage,
inlineModuleFileNameInformation,
} from '../inlineModules/inlineModules';
+import { isTargetInInlineModulesTargets } from '../inlineModules/iosInlineModules';
jest.mock('fs', () => require('memfs').fs);
jest.mock('fs/promises', () => require('memfs').fs.promises);
@@ -265,3 +266,62 @@ describe('androidInlineModules.ts', () => {
});
});
});
+
+describe('isTargetInInlineModulesTargets', () => {
+ it('should return true if mainTarget matches the extracted target from the path', () => {
+ const targetPath =
+ '/Users/user1/Projects/apps/ios/Pods/Target Support Files/Pods-AppTarget/ExpoModulesProvider.swift';
+ const inlineModulesTargets = { mainTarget: 'AppTarget', targets: [] };
+
+ const result = isTargetInInlineModulesTargets({ targetPath, inlineModulesTargets });
+ expect(result).toBe(true);
+ });
+
+ it('should return true if mainTarget is not provided and the extracted target is in the targets array', () => {
+ const targetPath =
+ '/Users/user1/Projects/apps/ios/Pods/Target Support Files/Pods-ExpoWidgetsTarget/ExpoModulesProvider.swift';
+ const inlineModulesTargets = {
+ targets: ['SomeOtherTarget', 'ExpoWidgetsTarget'],
+ };
+
+ const result = isTargetInInlineModulesTargets({ targetPath, inlineModulesTargets });
+ expect(result).toBe(true);
+ });
+
+ it('should return false if mainTarget is not provided and the extracted target is not in the targets array', () => {
+ const targetPath =
+ '/Users/user1/Projects/apps/ios/Pods/Target Support Files/Pods-ExpoWidgetsTarget/ExpoModulesProvider.swift';
+ const inlineModulesTargets = { targets: ['expo56c', 'SomeOtherTarget'] };
+
+ const result = isTargetInInlineModulesTargets({ targetPath, inlineModulesTargets });
+ expect(result).toBe(false);
+ });
+
+ it('should return false if mainTarget is not provided and the targets array is empty', () => {
+ const targetPath =
+ '/Users/user1/Projects/apps/ios/Pods/Target Support Files/Pods-expo56c/ExpoModulesProvider.swift';
+ const inlineModulesTargets = { targets: [] };
+
+ const result = isTargetInInlineModulesTargets({ targetPath, inlineModulesTargets });
+ expect(result).toBe(false);
+ });
+
+ it('should return false if the path format does not match the expected Pods layout', () => {
+ // Missing the "/Pods-" prefix before the target name
+ const targetPath =
+ '/Users/user1/Projects/apps/ios/Pods/Target Support Files/MyTarget/ExpoModulesProvider.swift';
+ const inlineModulesTargets = { targets: ['MyTarget'] };
+
+ const result = isTargetInInlineModulesTargets({ targetPath, inlineModulesTargets });
+ expect(result).toBe(false);
+ });
+
+ it('should return false if the target matches but has a different casing structure', () => {
+ const targetPath =
+ '/Users/user1/Projects/apps/ios/Pods/Target Support Files/Pods-ExpoWidgetsTarget/ExpoModulesProvider.swift';
+ const inlineModulesTargets = { targets: ['expowidgetstarget'] };
+
+ const result = isTargetInInlineModulesTargets({ targetPath, inlineModulesTargets });
+ expect(result).toBe(false);
+ });
+});
diff --git a/packages/expo-modules-autolinking/src/autolinking/generatePackageList.ts b/packages/expo-modules-autolinking/src/autolinking/generatePackageList.ts
index cf86bc1b472fa8..7227a453cd2329 100644
--- a/packages/expo-modules-autolinking/src/autolinking/generatePackageList.ts
+++ b/packages/expo-modules-autolinking/src/autolinking/generatePackageList.ts
@@ -6,6 +6,7 @@ interface GenerateModulesProviderParams {
targetPath: string;
entitlementPath: string | null;
watchedDirectories: string[];
+ inlineModulesTargets: { mainTarget?: string; targets: string[] };
appRoot: string;
}
diff --git a/packages/expo-modules-autolinking/src/commands/generateModulesProviderCommand.ts b/packages/expo-modules-autolinking/src/commands/generateModulesProviderCommand.ts
index 398d517a2e3fd9..1e905dadf8a837 100644
--- a/packages/expo-modules-autolinking/src/commands/generateModulesProviderCommand.ts
+++ b/packages/expo-modules-autolinking/src/commands/generateModulesProviderCommand.ts
@@ -17,6 +17,7 @@ interface GenerateModulesProviderArguments extends AutolinkingCommonArguments {
type PartialPodfileProperties = {
'expo.inlineModules.watchedDirectories'?: string;
+ 'expo.inlineModules.xcodeProjectTargets'?: string;
};
/** Generates a source file listing all packages to link in the runtime */
@@ -68,11 +69,16 @@ export function generateModulesProviderCommand(cli: commander.CommanderStatic) {
podfileProperties['expo.inlineModules.watchedDirectories'] ?? '[]'
);
+ const inlineModulesTargets = JSON.parse(
+ podfileProperties['expo.inlineModules.xcodeProjectTargets'] ?? '{"targets":[]}'
+ );
+
await generateModulesProviderAsync(filteredModules, {
platform,
targetPath: commandArguments.target,
entitlementPath: commandArguments.entitlement ?? null,
watchedDirectories,
+ inlineModulesTargets,
appRoot,
});
}
diff --git a/packages/expo-modules-autolinking/src/inlineModules/iosInlineModules.ts b/packages/expo-modules-autolinking/src/inlineModules/iosInlineModules.ts
index 13fbcb03e3f0bd..c29061c20fe814 100644
--- a/packages/expo-modules-autolinking/src/inlineModules/iosInlineModules.ts
+++ b/packages/expo-modules-autolinking/src/inlineModules/iosInlineModules.ts
@@ -14,3 +14,25 @@ export async function getIosInlineModulesClassNames(
}
);
}
+
+export function isTargetInInlineModulesTargets({
+ targetPath,
+ inlineModulesTargets,
+}: {
+ targetPath: string;
+ inlineModulesTargets: { mainTarget?: string; targets: string[] };
+}): boolean {
+ const targetRegex = /\/Pods-(.+?)\/ExpoModulesProvider\.swift$/;
+ const match = targetPath.match(targetRegex);
+ if (!match) {
+ return false;
+ }
+ const targetName = match[1];
+ if (targetName === undefined) {
+ return false;
+ }
+ if (inlineModulesTargets.mainTarget) {
+ return targetName === inlineModulesTargets.mainTarget;
+ }
+ return inlineModulesTargets.targets.includes(targetName);
+}
diff --git a/packages/expo-modules-autolinking/src/platforms/apple/apple.ts b/packages/expo-modules-autolinking/src/platforms/apple/apple.ts
index 24c6f83c0a6924..bfacd4cdbc7c45 100644
--- a/packages/expo-modules-autolinking/src/platforms/apple/apple.ts
+++ b/packages/expo-modules-autolinking/src/platforms/apple/apple.ts
@@ -3,7 +3,10 @@ import fs from 'fs';
import path from 'path';
import type { AutolinkingOptions } from '../../commands/autolinkingOptions';
-import { getIosInlineModulesClassNames } from '../../inlineModules/iosInlineModules';
+import {
+ getIosInlineModulesClassNames,
+ isTargetInInlineModulesTargets,
+} from '../../inlineModules/iosInlineModules';
import type {
AppleCodeSignEntitlements,
ExtraDependencies,
@@ -104,6 +107,8 @@ export async function resolveExtraBuildDependenciesAsync(
interface GenerateModulesProviderParams {
watchedDirectories: string[];
+ inlineModulesTargets: { mainTarget?: string; targets: string[] };
+ targetPath: string;
appRoot: string;
}
/**
@@ -168,9 +173,11 @@ async function generatePackageListFileContentAsync(
.concat(...modulesToImport.map((module) => module.modules))
.filter(Boolean);
- modulesClassNames = modulesClassNames.concat(
- await getIosInlineModulesClassNames(params.watchedDirectories, params.appRoot)
- );
+ if (isTargetInInlineModulesTargets(params)) {
+ modulesClassNames = modulesClassNames.concat(
+ await getIosInlineModulesClassNames(params.watchedDirectories, params.appRoot)
+ );
+ }
const debugOnlyModulesClassNames = ([] as ModuleIosConfig[])
.concat(...debugOnlyModules.map((module) => module.modules))
diff --git a/packages/expo-modules-core/CHANGELOG.md b/packages/expo-modules-core/CHANGELOG.md
index a9fadfa135ed11..f155219d7c0b71 100644
--- a/packages/expo-modules-core/CHANGELOG.md
+++ b/packages/expo-modules-core/CHANGELOG.md
@@ -8,6 +8,7 @@
- [iOS] Added the `@Record` macro that synthesizes a record from a type's stored properties, with no `@Field` wrappers needed. ([#46547](https://github.com/expo/expo/pull/46547) by [@tsapeta](https://github.com/tsapeta))
- [iOS] Added `Module.emit` that sends an event directly to the module's own JavaScript object, mirroring `SharedObject.emit`. Both now share an `EventEmitter` protocol. ([#46555](https://github.com/expo/expo/pull/46555) by [@tsapeta](https://github.com/tsapeta))
+- Add `useReleasingSharedObjectWithLifecycle` hook. ([#46494](https://github.com/expo/expo/pull/46494) by [@behenate](https://github.com/behenate))
### 🐛 Bug fixes
@@ -24,6 +25,7 @@
### 💡 Others
+- [Android] Make `expo-module-gradle-plugin` compatible with Android Gradle Plugin 9. ([#46769](https://github.com/expo/expo/pull/46769) by [@lukmccall](https://github.com/lukmccall))
- [iOS] `@ExpoModule` now synthesizes a `_decorateModule` that binds the module's `@JS` functions directly onto the JS object, letting the module holder skip the dynamic definition path for synthesized modules. ([#46612](https://github.com/expo/expo/pull/46612) by [@tsapeta](https://github.com/tsapeta))
- Update edge-to-edge package to call `updateEdgeToEdgeFeatureFlag` ([#46335](https://github.com/expo/expo/pull/46335) by [@zoontek](https://github.com/zoontek))
- `NativeArrayBuffer` arguments no longer copy the buffer when it's already native-backed. ([#46448](https://github.com/expo/expo/pull/46448) by [@barthap](https://github.com/barthap))
diff --git a/packages/expo-modules-core/build/hooks/useReleasingSharedObject.d.ts.map b/packages/expo-modules-core/build/hooks/useReleasingSharedObject.d.ts.map
index 1bb7b5f7fb7257..dd140b97b7aaa5 100644
--- a/packages/expo-modules-core/build/hooks/useReleasingSharedObject.d.ts.map
+++ b/packages/expo-modules-core/build/hooks/useReleasingSharedObject.d.ts.map
@@ -1 +1 @@
-{"version":3,"file":"useReleasingSharedObject.d.ts","sourceRoot":"","sources":["../../src/hooks/useReleasingSharedObject.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAG5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAEpE;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,aAAa,SAAS,YAAY,EACzE,OAAO,EAAE,MAAM,aAAa,EAC5B,YAAY,EAAE,cAAc,GAC3B,aAAa,CAoDf"}
\ No newline at end of file
+{"version":3,"file":"useReleasingSharedObject.d.ts","sourceRoot":"","sources":["../../src/hooks/useReleasingSharedObject.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAG5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAEpE;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,aAAa,SAAS,YAAY,EACzE,OAAO,EAAE,MAAM,aAAa,EAC5B,YAAY,EAAE,cAAc,GAC3B,aAAa,CAOf"}
\ No newline at end of file
diff --git a/packages/expo-modules-core/build/hooks/useReleasingSharedObjectWithLifecycle.d.ts b/packages/expo-modules-core/build/hooks/useReleasingSharedObjectWithLifecycle.d.ts
new file mode 100644
index 00000000000000..fb106a8a3f74f8
--- /dev/null
+++ b/packages/expo-modules-core/build/hooks/useReleasingSharedObjectWithLifecycle.d.ts
@@ -0,0 +1,49 @@
+import type { DependencyList } from 'react';
+import type { SharedObject } from '../ts-declarations/SharedObject';
+export type ReleasingSharedObjectLifecycleContext = {
+ /**
+ * The dependency values from the last committed object lifecycle decision.
+ */
+ previousDependencies: DependencyList;
+ /**
+ * The dependency values from the current render.
+ */
+ dependencies: DependencyList;
+};
+export type ReleasingSharedObjectLifecycle = {
+ /**
+ * Creates the shared object when the hook initializes or when `shouldRecreate` returns `true`.
+ */
+ factory: () => TSharedObject;
+ /**
+ * Called during render when dependencies change to decide whether to replace the object.
+ * Return `false` to keep the current object and handle the dependency change with the `update` function.
+ * When omitted or `true`, dependency changes recreate the object, matching `useReleasingSharedObject`.
+ *
+ * Must be a pure function with no side effects — it is called during the render phase and
+ * React may invoke it more than once with the same inputs.
+ */
+ shouldRecreate?: (object: TSharedObject, context: ReleasingSharedObjectLifecycleContext) => boolean;
+ /**
+ * Called after commit when dependencies changed and `shouldRecreate` returned `false`.
+ * Has no effect unless `shouldRecreate` is provided and returns `false` for the changed
+ * dependencies.
+ *
+ * If the returned `Promise` rejects, the error is logged with `console.error`. Handle errors
+ * inside `update` if specific error handling is needed.
+ *
+ * If a subsequent dependency change or unmount requires the object to be released while an
+ * async update is still in-flight, the release is deferred until the update settles.
+ */
+ update?: (object: TSharedObject, context: ReleasingSharedObjectLifecycleContext) => void | Promise;
+ /**
+ * Releases an object after it has been replaced or when the component unmounts.
+ * When omitted, the object's `release` method is called.
+ */
+ release?: (object: TSharedObject) => void;
+};
+/**
+ * Returns a shared object, delegating dependency changes to lifecycle callbacks.
+ */
+export declare function useReleasingSharedObjectWithLifecycle(lifecycle: ReleasingSharedObjectLifecycle, dependencies: DependencyList): TSharedObject;
+//# sourceMappingURL=useReleasingSharedObjectWithLifecycle.d.ts.map
\ No newline at end of file
diff --git a/packages/expo-modules-core/build/hooks/useReleasingSharedObjectWithLifecycle.d.ts.map b/packages/expo-modules-core/build/hooks/useReleasingSharedObjectWithLifecycle.d.ts.map
new file mode 100644
index 00000000000000..6b189f17a74f14
--- /dev/null
+++ b/packages/expo-modules-core/build/hooks/useReleasingSharedObjectWithLifecycle.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"useReleasingSharedObjectWithLifecycle.d.ts","sourceRoot":"","sources":["../../src/hooks/useReleasingSharedObjectWithLifecycle.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAG5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAEpE,MAAM,MAAM,qCAAqC,GAAG;IAClD;;OAEG;IACH,oBAAoB,EAAE,cAAc,CAAC;IAErC;;OAEG;IACH,YAAY,EAAE,cAAc,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,8BAA8B,CAAC,aAAa,SAAS,YAAY,IAAI;IAC/E;;OAEG;IACH,OAAO,EAAE,MAAM,aAAa,CAAC;IAE7B;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,CACf,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,qCAAqC,KAC3C,OAAO,CAAC;IAEb;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,CACP,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,qCAAqC,KAC3C,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1B;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;CAC3C,CAAC;AAcF;;GAEG;AACH,wBAAgB,qCAAqC,CAAC,aAAa,SAAS,YAAY,EACtF,SAAS,EAAE,8BAA8B,CAAC,aAAa,CAAC,EACxD,YAAY,EAAE,cAAc,GAC3B,aAAa,CAqGf"}
\ No newline at end of file
diff --git a/packages/expo-modules-core/build/index.d.ts b/packages/expo-modules-core/build/index.d.ts
index 7d0aea398c04a7..333f0f4bd1778b 100644
--- a/packages/expo-modules-core/build/index.d.ts
+++ b/packages/expo-modules-core/build/index.d.ts
@@ -17,6 +17,7 @@ export * from './PermissionsInterface';
export * from './PermissionsHook';
export * from './Refs';
export * from './hooks/useReleasingSharedObject';
+export * from './hooks/useReleasingSharedObjectWithLifecycle';
export * from './reload';
export { CodedError } from './errors/CodedError';
export { UnavailabilityError } from './errors/UnavailabilityError';
diff --git a/packages/expo-modules-core/build/index.d.ts.map b/packages/expo-modules-core/build/index.d.ts.map
index 65c6476cd1a9de..6692fb27ad16dc 100644
--- a/packages/expo-modules-core/build/index.d.ts.map
+++ b/packages/expo-modules-core/build/index.d.ts.map
@@ -1 +1 @@
-{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,0BAA0B,CAAC;AAClC,OAAO,0BAA0B,CAAC;AAClC,OAAO,YAAY,CAAC;AAEpB,mBAAmB,0BAA0B,CAAC;AAE9C,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEzC,YAAY,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAEtE,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AAEpC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAElC,cAAc,QAAQ,CAAC;AAEvB,cAAc,kCAAkC,CAAC;AACjD,cAAc,UAAU,CAAC;AAGzB,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAGnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAErE,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC"}
\ No newline at end of file
+{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,0BAA0B,CAAC;AAClC,OAAO,0BAA0B,CAAC;AAClC,OAAO,YAAY,CAAC;AAEpB,mBAAmB,0BAA0B,CAAC;AAE9C,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEzC,YAAY,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAEtE,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AAEpC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAElC,cAAc,QAAQ,CAAC;AAEvB,cAAc,kCAAkC,CAAC;AACjD,cAAc,+CAA+C,CAAC;AAC9D,cAAc,UAAU,CAAC;AAGzB,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAGnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAErE,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC"}
\ No newline at end of file
diff --git a/packages/expo-modules-core/expo-module-gradle-plugin/src/main/kotlin/expo/modules/plugin/ProjectConfiguration.kt b/packages/expo-modules-core/expo-module-gradle-plugin/src/main/kotlin/expo/modules/plugin/ProjectConfiguration.kt
index cfc300c21ed142..99bbd1ca714d0e 100644
--- a/packages/expo-modules-core/expo-module-gradle-plugin/src/main/kotlin/expo/modules/plugin/ProjectConfiguration.kt
+++ b/packages/expo-modules-core/expo-module-gradle-plugin/src/main/kotlin/expo/modules/plugin/ProjectConfiguration.kt
@@ -2,7 +2,8 @@
package expo.modules.plugin
-import com.android.build.gradle.LibraryExtension
+import com.android.build.api.dsl.LibraryExtension
+import com.android.build.api.variant.AndroidComponentsExtension
import expo.modules.plugin.android.PublicationInfo
import expo.modules.plugin.android.applyLinterOptions
import expo.modules.plugin.android.applyPublishingVariant
@@ -20,27 +21,31 @@ import org.gradle.internal.extensions.core.extra
import java.io.File
internal fun Project.applyDefaultPlugins() {
- if (!plugins.hasPlugin("com.android.library")) {
- plugins.apply("com.android.library")
- }
- if (!plugins.hasPlugin("kotlin-android")) {
- plugins.apply("kotlin-android")
- }
- if (!plugins.hasPlugin("maven-publish")) {
- plugins.apply("maven-publish")
+ applyPluginIfNeeded("com.android.library")
+
+ if (!hasBuiltInKotlinSupport()) {
+ // AGP 9 ships built-in Kotlin support (enabled by default), so applying `kotlin-android` on top
+ // of it fails with "Cannot add extension with name 'kotlin', …".
+ applyPluginIfNeeded("kotlin-android")
}
+
+ applyPluginIfNeeded("maven-publish")
}
internal fun Project.applyPikaPlugin() {
- if (!plugins.hasPlugin("io.github.lukmccall.pika")) {
- plugins.apply("io.github.lukmccall.pika")
- }
-
+ applyPluginIfNeeded("io.github.lukmccall.pika")
+
val pika = extensions.getByType(PikaGradleExtension::class.java)
pika.introspectableAnnotation("expo.modules.kotlin.types.OptimizedRecord")
pika.introspectableAnnotation("expo.modules.kotlin.views.OptimizedComposeProps")
}
+private fun Project.applyPluginIfNeeded(id: String) {
+ if (!plugins.hasPlugin(id)) {
+ plugins.apply(id)
+ }
+}
+
internal fun Project.configurePika(shouldBeEnabled: Boolean = true) {
val pika = extensions.getByType(PikaGradleExtension::class.java)
pika.enabled = shouldBeEnabled
@@ -72,9 +77,7 @@ internal fun Project.applyDefaultAndroidSdkVersions() {
compileSdk = rootProject.extra.safeGet("compileSdkVersion")
?: logger.warnIfNotDefined("compileSdkVersion", 36),
minSdk = rootProject.extra.safeGet("minSdkVersion")
- ?: logger.warnIfNotDefined("minSdkVersion", 24),
- targetSdk = rootProject.extra.safeGet("targetSdkVersion")
- ?: logger.warnIfNotDefined("targetSdkVersion", 36)
+ ?: logger.warnIfNotDefined("minSdkVersion", 24)
)
applyLinterOptions()
}
@@ -119,6 +122,21 @@ internal fun Project.applyPublishing(expoModulesExtension: ExpoModuleExtension)
}
}
+private const val AGP_BUILT_IN_KOTLIN_MAJOR = 9
+
+/**
+ * Whether AGP's built-in Kotlin support is active, meaning the `kotlin-android` plugin must not be
+ * applied. True on AGP 9+ unless the project explicitly opts out with `android.builtInKotlin=false`.
+ */
+internal fun Project.hasBuiltInKotlinSupport(): Boolean {
+ val androidComponents = extensions.findByType(AndroidComponentsExtension::class.java)
+ ?: return false
+ if (androidComponents.pluginVersion.major < AGP_BUILT_IN_KOTLIN_MAJOR) {
+ return false
+ }
+ return findProperty("android.builtInKotlin")?.toString()?.toBoolean() ?: true
+}
+
internal fun Project.androidLibraryExtension() = extensions.getByType(LibraryExtension::class.java)
internal fun Project.publishingExtension() = extensions.getByType(PublishingExtension::class.java)
diff --git a/packages/expo-modules-core/expo-module-gradle-plugin/src/main/kotlin/expo/modules/plugin/android/AndroidLibraryExtension.kt b/packages/expo-modules-core/expo-module-gradle-plugin/src/main/kotlin/expo/modules/plugin/android/AndroidLibraryExtension.kt
index 9bfae8d7961d6f..0de0f0ec998c3a 100644
--- a/packages/expo-modules-core/expo-module-gradle-plugin/src/main/kotlin/expo/modules/plugin/android/AndroidLibraryExtension.kt
+++ b/packages/expo-modules-core/expo-module-gradle-plugin/src/main/kotlin/expo/modules/plugin/android/AndroidLibraryExtension.kt
@@ -1,22 +1,21 @@
package expo.modules.plugin.android
-import com.android.build.gradle.LibraryExtension
+import com.android.build.api.dsl.LibraryExtension
-internal fun LibraryExtension.applySDKVersions(compileSdk: Int, minSdk: Int, targetSdk: Int) {
+internal fun LibraryExtension.applySDKVersions(compileSdk: Int, minSdk: Int) {
this.compileSdk = compileSdk
defaultConfig {
this@defaultConfig.minSdk = minSdk
- this@defaultConfig.targetSdk = targetSdk
}
}
internal fun LibraryExtension.applyLinterOptions() {
- lintOptions.isAbortOnError = false
+ lint.abortOnError = false
}
internal fun LibraryExtension.applyPublishingVariant() {
- publishing { publishing ->
- publishing.singleVariant("release") {
+ publishing {
+ singleVariant("release") {
withSourcesJar()
}
}
diff --git a/packages/expo-modules-core/expo-module-gradle-plugin/src/main/kotlin/expo/modules/plugin/android/MavenPublicationExtension.kt b/packages/expo-modules-core/expo-module-gradle-plugin/src/main/kotlin/expo/modules/plugin/android/MavenPublicationExtension.kt
index f0ce04eab97719..022886b8bebaea 100644
--- a/packages/expo-modules-core/expo-module-gradle-plugin/src/main/kotlin/expo/modules/plugin/android/MavenPublicationExtension.kt
+++ b/packages/expo-modules-core/expo-module-gradle-plugin/src/main/kotlin/expo/modules/plugin/android/MavenPublicationExtension.kt
@@ -23,9 +23,7 @@ import org.gradle.api.component.SoftwareComponent
import org.gradle.api.publish.PublicationContainer
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.tasks.TaskProvider
-import java.nio.file.Path
-import kotlin.io.path.exists
-import kotlin.io.path.toPath
+import java.io.File
internal data class PublicationInfo(
val components: SoftwareComponent,
@@ -41,17 +39,15 @@ internal data class PublicationInfo(
artifactId = requireNotNull(project.androidLibraryExtension().namespace) {
"'android.namespace' is not defined"
},
- version = requireNotNull(project.androidLibraryExtension().defaultConfig.versionName) {
- "'android.defaultConfig.versionName' is not defined"
+ version = requireNotNull(project.version.toString().takeUnless { it == "unspecified" }) {
+ "'project.version' is not defined. Set `version = \"\"` in the module's android/build.gradle."
},
)
- fun resolvePath(repositoryPath: Path): Path {
+ fun resolvePath(repositoryPath: File): File {
val groupPath = groupId.replace('.', '/')
val artifactPath = "$groupPath/$artifactId/$version"
- val publicationPath = repositoryPath.resolve(artifactPath)
-
- return publicationPath
+ return File(repositoryPath, artifactPath)
}
override fun toString(): String {
@@ -180,7 +176,7 @@ private fun Project.expoPublishBody(publicationInfo: PublicationInfo, expoModule
if (pathToRepository == null) {
val mavenLocal = publishingExtension().repositories.mavenLocal()
- val mavenLocalPath = mavenLocal.url.toPath()
+ val mavenLocalPath = File(mavenLocal.url)
val publicationPath = publicationInfo.resolvePath(mavenLocalPath)
if (!publicationPath.exists()) {
diff --git a/packages/expo-modules-core/src/hooks/useReleasingSharedObject.ts b/packages/expo-modules-core/src/hooks/useReleasingSharedObject.ts
index 9e9c13477132bd..20d5dc905576d5 100644
--- a/packages/expo-modules-core/src/hooks/useReleasingSharedObject.ts
+++ b/packages/expo-modules-core/src/hooks/useReleasingSharedObject.ts
@@ -1,8 +1,8 @@
'use client';
import type { DependencyList } from 'react';
-import { useEffect, useMemo, useRef } from 'react';
+import { useReleasingSharedObjectWithLifecycle } from './useReleasingSharedObjectWithLifecycle';
import type { SharedObject } from '../ts-declarations/SharedObject';
/**
@@ -12,55 +12,10 @@ export function useReleasingSharedObject(
factory: () => TSharedObject,
dependencies: DependencyList
): TSharedObject {
- const objectRef = useRef(null);
- const objectRefToRelease = useRef(null);
- const isFastRefresh = useRef(false);
- const previousDependencies = useRef(dependencies);
-
- if (objectRef.current == null) {
- objectRef.current = factory();
- }
-
- const object = useMemo(() => {
- let newObject = objectRef.current;
- const dependenciesAreEqual =
- previousDependencies.current?.length === dependencies.length &&
- dependencies.every((value, index) => value === previousDependencies.current[index]);
-
- // If the dependencies have changed, schedule the previous object for release and create a new one,
- // otherwise this has been called because of an unrelated fast refresh, and we don't want to release the object.
- if (!newObject || !dependenciesAreEqual) {
- objectRefToRelease.current = objectRef.current;
- newObject = factory();
- objectRef.current = newObject;
- previousDependencies.current = dependencies;
- }
- return newObject;
- }, dependencies);
-
- useEffect(() => {
- // When the object changes, release the previous one - it is important to do this in a useEffect, so that we don't release
- // the object during render.
- if (objectRefToRelease.current) {
- objectRefToRelease.current.release();
- objectRefToRelease.current = null;
- }
- }, [object]);
-
- useMemo(() => {
- isFastRefresh.current = true;
- }, []);
-
- useEffect(() => {
- isFastRefresh.current = false;
-
- return () => {
- // This will be called on every fast refresh and on unmount, but we only want to release the object on unmount.
- if (!isFastRefresh.current && objectRef.current) {
- objectRef.current.release();
- }
- };
- }, []);
-
- return object;
+ return useReleasingSharedObjectWithLifecycle(
+ {
+ factory,
+ },
+ dependencies
+ );
}
diff --git a/packages/expo-modules-core/src/hooks/useReleasingSharedObjectWithLifecycle.ts b/packages/expo-modules-core/src/hooks/useReleasingSharedObjectWithLifecycle.ts
new file mode 100644
index 00000000000000..4224433e910555
--- /dev/null
+++ b/packages/expo-modules-core/src/hooks/useReleasingSharedObjectWithLifecycle.ts
@@ -0,0 +1,181 @@
+'use client';
+
+import type { DependencyList } from 'react';
+import { useEffect, useMemo, useRef } from 'react';
+
+import type { SharedObject } from '../ts-declarations/SharedObject';
+
+export type ReleasingSharedObjectLifecycleContext = {
+ /**
+ * The dependency values from the last committed object lifecycle decision.
+ */
+ previousDependencies: DependencyList;
+
+ /**
+ * The dependency values from the current render.
+ */
+ dependencies: DependencyList;
+};
+
+export type ReleasingSharedObjectLifecycle = {
+ /**
+ * Creates the shared object when the hook initializes or when `shouldRecreate` returns `true`.
+ */
+ factory: () => TSharedObject;
+
+ /**
+ * Called during render when dependencies change to decide whether to replace the object.
+ * Return `false` to keep the current object and handle the dependency change with the `update` function.
+ * When omitted or `true`, dependency changes recreate the object, matching `useReleasingSharedObject`.
+ *
+ * Must be a pure function with no side effects — it is called during the render phase and
+ * React may invoke it more than once with the same inputs.
+ */
+ shouldRecreate?: (
+ object: TSharedObject,
+ context: ReleasingSharedObjectLifecycleContext
+ ) => boolean;
+
+ /**
+ * Called after commit when dependencies changed and `shouldRecreate` returned `false`.
+ * Has no effect unless `shouldRecreate` is provided and returns `false` for the changed
+ * dependencies.
+ *
+ * If the returned `Promise` rejects, the error is logged with `console.error`. Handle errors
+ * inside `update` if specific error handling is needed.
+ *
+ * If a subsequent dependency change or unmount requires the object to be released while an
+ * async update is still in-flight, the release is deferred until the update settles.
+ */
+ update?: (
+ object: TSharedObject,
+ context: ReleasingSharedObjectLifecycleContext
+ ) => void | Promise;
+
+ /**
+ * Releases an object after it has been replaced or when the component unmounts.
+ * When omitted, the object's `release` method is called.
+ */
+ release?: (object: TSharedObject) => void;
+};
+
+type PendingUpdate = {
+ object: TSharedObject;
+ context: ReleasingSharedObjectLifecycleContext;
+};
+
+function dependenciesAreEqual(previousDependencies: DependencyList, dependencies: DependencyList) {
+ return (
+ previousDependencies.length === dependencies.length &&
+ dependencies.every((value, index) => value === previousDependencies[index])
+ );
+}
+
+/**
+ * Returns a shared object, delegating dependency changes to lifecycle callbacks.
+ */
+export function useReleasingSharedObjectWithLifecycle(
+ lifecycle: ReleasingSharedObjectLifecycle,
+ dependencies: DependencyList
+): TSharedObject {
+ const objectRef = useRef(null);
+ const objectRefToRelease = useRef(null);
+ const pendingUpdateRef = useRef | null>(null);
+ const pendingUpdatePromiseRef = useRef | null>(null);
+ const isFastRefresh = useRef(false);
+ const previousDependencies = useRef(dependencies);
+ const lifecycleRef = useRef(lifecycle);
+
+ // Keep lifecycle callbacks fresh without making effects depend on the lifecycle object identity.
+ lifecycleRef.current = lifecycle;
+
+ if (objectRef.current == null) {
+ objectRef.current = lifecycleRef.current.factory();
+ }
+
+ const object = useMemo(() => {
+ let newObject = objectRef.current;
+ const context = {
+ previousDependencies: previousDependencies.current,
+ dependencies,
+ };
+
+ // If the dependencies have changed, let the caller decide whether the object should be
+ // replaced or updated in place. Otherwise this has been called because of an unrelated
+ // fast refresh, and we don't want to release the object.
+ if (!newObject || !dependenciesAreEqual(previousDependencies.current, dependencies)) {
+ if (!newObject || (lifecycleRef.current.shouldRecreate?.(newObject, context) ?? true)) {
+ objectRefToRelease.current = objectRef.current;
+ newObject = lifecycleRef.current.factory();
+ objectRef.current = newObject;
+ } else if (lifecycleRef.current.update) {
+ pendingUpdateRef.current = {
+ object: newObject,
+ context,
+ };
+ }
+ previousDependencies.current = dependencies;
+ }
+ return newObject;
+ }, dependencies);
+
+ function releaseObject(obj: TSharedObject) {
+ (lifecycleRef.current.release ?? ((o: TSharedObject) => o.release()))(obj);
+ }
+
+ useEffect(() => {
+ // When the object changes, release the previous one - it is important to do this in a useEffect, so that we don't release
+ // the object during render. If an async update is still in-flight, defer the release until it settles.
+ if (objectRefToRelease.current) {
+ const toRelease = objectRefToRelease.current;
+ objectRefToRelease.current = null;
+ const doRelease = () => releaseObject(toRelease);
+ if (pendingUpdatePromiseRef.current) {
+ pendingUpdatePromiseRef.current.then(doRelease, doRelease);
+ } else {
+ doRelease();
+ }
+ }
+
+ if (pendingUpdateRef.current) {
+ const pendingUpdate = pendingUpdateRef.current;
+ pendingUpdateRef.current = null;
+ const result = lifecycleRef.current.update?.(pendingUpdate.object, pendingUpdate.context);
+ if (result instanceof Promise) {
+ pendingUpdatePromiseRef.current = result;
+ result.then(
+ () => {
+ pendingUpdatePromiseRef.current = null;
+ },
+ (error) => {
+ pendingUpdatePromiseRef.current = null;
+ console.error(error);
+ }
+ );
+ }
+ }
+ }, dependencies);
+
+ useMemo(() => {
+ isFastRefresh.current = true;
+ }, []);
+
+ useEffect(() => {
+ isFastRefresh.current = false;
+
+ return () => {
+ // This will be called on every fast refresh and on unmount, but we only want to release the object on unmount.
+ if (!isFastRefresh.current && objectRef.current) {
+ const obj = objectRef.current;
+ const doRelease = () => releaseObject(obj);
+ if (pendingUpdatePromiseRef.current) {
+ pendingUpdatePromiseRef.current.then(doRelease, doRelease);
+ } else {
+ doRelease();
+ }
+ }
+ };
+ }, []);
+
+ return object;
+}
diff --git a/packages/expo-modules-core/src/index.ts b/packages/expo-modules-core/src/index.ts
index 345d5d6b6d5438..606f464cce0a8d 100644
--- a/packages/expo-modules-core/src/index.ts
+++ b/packages/expo-modules-core/src/index.ts
@@ -25,6 +25,7 @@ export * from './PermissionsHook';
export * from './Refs';
export * from './hooks/useReleasingSharedObject';
+export * from './hooks/useReleasingSharedObjectWithLifecycle';
export * from './reload';
// Errors
diff --git a/packages/expo-modules-jsi/CHANGELOG.md b/packages/expo-modules-jsi/CHANGELOG.md
index 25f8543e177026..6805efef2d34eb 100644
--- a/packages/expo-modules-jsi/CHANGELOG.md
+++ b/packages/expo-modules-jsi/CHANGELOG.md
@@ -23,6 +23,7 @@
### 💡 Others
+- [iOS] `JavaScriptUnownedValue` and `JavaScriptValuesBuffer` now cache the runtime as the immortal `facebook.jsi.IRuntime` instead of the ARC-managed `JavaScriptRuntime` wrapper, removing per-call retain/release on the argument-decode hot path (measured ~16% faster `addNumbers`, ~24% faster `addStrings`). ([#46678](https://github.com/expo/expo/pull/46678) by [@tsapeta](https://github.com/tsapeta))
- `NativeArrayBuffer` arguments no longer copy the buffer when it's already native-backed. ([#46448](https://github.com/expo/expo/pull/46448) by [@barthap](https://github.com/barthap))
- [iOS] `JavaScriptNativeState` can now back any `jsi::NativeState` subtype via a `void *` factory, so consumers without Swift/C++ interop (e.g. `expo-modules-core`) can supply their own pointee. `expo::NativeState` ships from the xcframework as a public C++ header. ([#46330](https://github.com/expo/expo/pull/46330) by [@tsapeta](https://github.com/tsapeta))
- [iOS] Ignore already-settled promises. ([#46765](https://github.com/expo/expo/pull/46765) by [@jakex7](https://github.com/jakex7))
diff --git a/packages/expo-modules-jsi/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptRuntime.swift b/packages/expo-modules-jsi/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptRuntime.swift
index 70232d7e67ccbe..bf28c74ba687ea 100644
--- a/packages/expo-modules-jsi/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptRuntime.swift
+++ b/packages/expo-modules-jsi/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptRuntime.swift
@@ -213,7 +213,8 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
let context = Unmanaged.passRetained(HostObjectContext(runtime: self, get, set, getPropertyNames, dealloc))
.toOpaque()
- let setterPointer: (@convention(c) (UnsafeMutableRawPointer, UnsafePointer, UnsafeMutableRawPointer) -> Void)? = setter
+ let setterPointer:
+ (@convention(c) (UnsafeMutableRawPointer, UnsafePointer, UnsafeMutableRawPointer) -> Void)? = setter
// Pass a null setter to C++ when the Swift setter is nil so that JS assignment
// raises a `jsi::JSError` directly, without crossing the Swift boundary.
let callbacks = expo.HostObjectCallbacks(
diff --git a/packages/expo-modules-jsi/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptValuesBuffer.swift b/packages/expo-modules-jsi/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptValuesBuffer.swift
index fcd23aa6d842ac..19b218f047a48d 100644
--- a/packages/expo-modules-jsi/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptValuesBuffer.swift
+++ b/packages/expo-modules-jsi/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptValuesBuffer.swift
@@ -8,6 +8,12 @@ public struct JavaScriptValuesBuffer: JavaScriptType, ~Copyable {
// so the runtime is always alive while the buffer exists.
internal unowned let runtime: JavaScriptRuntime
+ // The raw `facebook.jsi.IRuntime`, cached alongside the `JavaScriptRuntime` wrapper. `IRuntime` is
+ // an immortal reference (`jsi.apinotes`), so reading it costs no ARC, whereas reading `.pointee`
+ // off the `unowned` wrapper emits an unowned retain/release on every access. The hot decode path
+ // (`unownedValue(at:)`, `set`) reads this; `subscript`/`copy` still need the wrapper.
+ internal nonisolated(unsafe) let iRuntime: facebook.jsi.IRuntime
+
internal nonisolated(unsafe) let bufferPointer: UnsafeMutableBufferPointer
private let ownsMemory: Bool
@@ -34,6 +40,7 @@ public struct JavaScriptValuesBuffer: JavaScriptType, ~Copyable {
ownsMemory: Bool = false
) {
self.runtime = runtime
+ self.iRuntime = runtime.pointee
self.bufferPointer = buffer
self.ownsMemory = ownsMemory
}
@@ -69,7 +76,7 @@ public struct JavaScriptValuesBuffer: JavaScriptType, ~Copyable {
/// `baseAddress`, so passing any index into an empty buffer crashes, and an out-of-range index reads past
/// the buffer. The caller is responsible for the bounds check.
public func unownedValue(at index: Int) -> JavaScriptUnownedValue {
- return JavaScriptUnownedValue(runtime, bufferPointer.baseAddress! + index)
+ return JavaScriptUnownedValue(iRuntime, bufferPointer.baseAddress! + index)
}
@discardableResult
@@ -78,7 +85,7 @@ public struct JavaScriptValuesBuffer: JavaScriptType, ~Copyable {
guard (0.. class refs, there is no trap on use-after-free. The contract is "valid only within the synchronous
/// > decode call, while the owner is alive" — which the buffer-driven decode path honors because it
/// > reads the value inline on the JS thread before the buffer is torn down. Do not store, capture, or
-/// > escape it; call ``copied()`` to materialize an owning value when escape is needed.
+/// > escape it; call ``copied(in:)`` to materialize an owning value when escape is needed.
public struct JavaScriptUnownedValue: ~Copyable {
// Borrows the `jsi::Value` at this address; it does not own it and must not outlive the owner.
internal let pointer: UnsafePointer
- // Non-optional `unowned`, matching `JavaScriptValuesBuffer.runtime`: it is strictly call-scoped and
- // cannot outlive the runtime executing the call, so we skip both the ARC traffic and the optional unwrap
- // that the owning `JavaScriptValue` pays.
- internal unowned let runtime: JavaScriptRuntime
+ // The JSI runtime, stored as the raw `facebook.jsi.IRuntime` rather than the `JavaScriptRuntime`
+ // wrapper. `IRuntime` is imported as an immortal reference (see `jsi.apinotes`), so storing and
+ // copying it emits no ARC, unlike a `JavaScriptRuntime` field whose every per-call access pays an
+ // unowned retain/release. Only `getString` reads it; the type checks and numeric accessors touch
+ // only `pointer`.
+ internal let runtime: facebook.jsi.IRuntime
- internal init(_ runtime: JavaScriptRuntime, _ pointer: UnsafePointer) {
+ internal init(_ runtime: facebook.jsi.IRuntime, _ pointer: UnsafePointer) {
self.runtime = runtime
self.pointer = pointer
}
/// Materializes an owning ``JavaScriptValue`` by copying the borrowed `jsi::Value`. Use it when the
- /// value must outlive the decode call (stored, captured, handed to a `Promise`).
- public func copied() -> JavaScriptValue {
+ /// value must outlive the decode call (stored, captured, handed to a `Promise`). Takes the
+ /// `JavaScriptRuntime` wrapper since the owning value needs it; the caller has it in scope.
+ ///
+ /// `runtime` must be the runtime that owns the borrowed value. Copying a reference value (string,
+ /// object, function, array, bigint) clones its `PointerValue` against `runtime`, so passing a
+ /// different runtime would clone a handle from another heap and corrupt it; the assert guards that.
+ public func copied(in runtime: JavaScriptRuntime) -> JavaScriptValue {
+ assert(
+ Unmanaged.passUnretained(runtime.pointee).toOpaque() == Unmanaged.passUnretained(self.runtime).toOpaque(),
+ "`copied(in:)` must be passed the runtime that owns the borrowed value")
return JavaScriptValue(runtime, pointer.pointee)
}
@@ -98,7 +108,7 @@ public struct JavaScriptUnownedValue: ~Copyable {
/// Returns the value as a string, or asserts if not a string.
public func getString() -> String {
assert(isString(), "Value is not a string")
- return String(pointer.pointee.getString(runtime.pointee).utf8(runtime.pointee))
+ return String(pointer.pointee.getString(runtime).utf8(runtime))
}
// MARK: - Throwing conversions ("as functions")
diff --git a/packages/expo-modules-jsi/apple/Tests/JavaScriptUnownedValueTests.swift b/packages/expo-modules-jsi/apple/Tests/JavaScriptUnownedValueTests.swift
index f5c1924bdc60da..c9c85b7741ab82 100644
--- a/packages/expo-modules-jsi/apple/Tests/JavaScriptUnownedValueTests.swift
+++ b/packages/expo-modules-jsi/apple/Tests/JavaScriptUnownedValueTests.swift
@@ -61,7 +61,7 @@ struct JavaScriptUnownedValueTests {
@Test
func `copied materializes an owning value`() throws {
let buffer = JavaScriptValuesBuffer.allocate(in: runtime, with: "owned")
- let owning = buffer.unownedValue(at: 0).copied()
+ let owning = buffer.unownedValue(at: 0).copied(in: runtime)
#expect(try owning.asString() == "owned")
}
diff --git a/packages/expo-video/CHANGELOG.md b/packages/expo-video/CHANGELOG.md
index 30722010c47a6d..905fbfa1a4b992 100644
--- a/packages/expo-video/CHANGELOG.md
+++ b/packages/expo-video/CHANGELOG.md
@@ -10,6 +10,7 @@
### 🐛 Bug fixes
+- [iOS] Re-enable the shared remote command center commands so lock screen controls keep working after expo-audio playback. ([#46753](https://github.com/expo/expo/pull/46753) by [@zoontek](https://github.com/zoontek))
- Deduplicate `availableVideoTracks` for HLS sources with multiple audio renditions. ([#46691](https://github.com/expo/expo/pull/46691) by [@zoontek](https://github.com/zoontek))
- Recover failed players to fix broken playback placeholder ([#46681](https://github.com/expo/expo/pull/46681) by [@zoontek](https://github.com/zoontek))
- When caching take into account Authorization / auth-related request headers. ([#45995](https://github.com/expo/expo/pull/45995) by [@behenate](https://github.com/behenate))
diff --git a/packages/expo-video/ios/NowPlayingManager.swift b/packages/expo-video/ios/NowPlayingManager.swift
index 650e8b14b62d15..c276c5c918c8f8 100644
--- a/packages/expo-video/ios/NowPlayingManager.swift
+++ b/packages/expo-video/ios/NowPlayingManager.swift
@@ -226,6 +226,14 @@ class NowPlayingManager: VideoPlayerObserverDelegate {
}
return .commandFailed
}
+
+ // `MPRemoteCommandCenter` is a process-wide singleton that other modules (e.g. expo-audio) disable on
+ // teardown, so re-enable the commands we handle to keep the lock screen controls working. (issue #46711)
+ commandCenter.playCommand.isEnabled = true
+ commandCenter.pauseCommand.isEnabled = true
+ commandCenter.skipForwardCommand.isEnabled = true
+ commandCenter.skipBackwardCommand.isEnabled = true
+ commandCenter.changePlaybackPositionCommand.isEnabled = true
}
}
diff --git a/templates/expo-template-bare-minimum/ios/Podfile b/templates/expo-template-bare-minimum/ios/Podfile
index c3158e3fb9b16f..840081caab9143 100644
--- a/templates/expo-template-bare-minimum/ios/Podfile
+++ b/templates/expo-template-bare-minimum/ios/Podfile
@@ -15,7 +15,7 @@ end
ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] ||= podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR']
ENV['RCT_USE_RN_DEP'] ||= podfile_properties['ios.buildReactNativeFromSource'] == 'true' ? '0' : '1'
ENV['RCT_USE_PREBUILT_RNCORE'] ||= podfile_properties['ios.buildReactNativeFromSource'] == 'true' ? '0' : '1'
-ENV['RCT_HERMES_V1_ENABLED'] ||= '1' if podfile_properties['expo.useHermesV1'] == 'true'
+ENV['RCT_HERMES_V1_ENABLED'] ||= '0' if podfile_properties['expo.useHermesV1'] == 'false'
ENV['EXPO_USE_PRECOMPILED_MODULES'] ||= '1' if podfile_properties['EXPO_USE_PRECOMPILED_MODULES'] != 'false'
platform :ios, podfile_properties['ios.deploymentTarget'] || '16.4'