diff --git a/.github/workflows/brownfield.yml b/.github/workflows/brownfield.yml
index b773b508ad3106..f362dec2cac40d 100644
--- a/.github/workflows/brownfield.yml
+++ b/.github/workflows/brownfield.yml
@@ -39,8 +39,6 @@ jobs:
runs-on: ubuntu-24.04
outputs:
all_tests: ${{ steps.filter.outputs.all_tests }}
- cli_e2e: ${{ steps.filter.outputs.cli_e2e }}
- plugin_e2e: ${{ steps.filter.outputs.plugin_e2e }}
compilation_test_android: ${{ steps.filter.outputs.compilation_test_android }}
compilation_test_ios: ${{ steps.filter.outputs.compilation_test_ios }}
steps:
@@ -48,27 +46,13 @@ jobs:
uses: actions/checkout@v5
- uses: dorny/paths-filter@v3
id: filter
- # TODO(pmleczek): Update paths once we wrap up Maestro tests (remove expo-brownfield/**)
# TODO(pmleczek): Add "- 'packages/expo-updates/**'" to the compilation test filters
with:
filters: |
all_tests:
- '.github/workflows/brownfield.yml'
- 'yarn.lock'
- cli_e2e:
- - 'packages/expo-brownfield/bin/**'
- - 'packages/expo-brownfield/cli/**'
- - 'packages/expo-brownfield/e2e/cli/**'
- - 'packages/expo-brownfield/e2e/utils/**'
- - 'packages/expo-brownfield/package.json'
- plugin_e2e:
- - 'packages/expo-brownfield/plugin/**'
- - 'packages/expo-brownfield/e2e/plugin/**'
- - 'packages/expo-brownfield/e2e/utils/**'
- - 'packages/expo-brownfield/app.plugin.js'
- - 'packages/expo-brownfield/package.json'
compilation_test_android:
- - 'packages/expo-brownfield/**'
- 'packages/expo/android/src/main/jave/expo/modules/**'
- 'packages/expo/android/build.gradle'
- 'packages/expo-dev-menu/android/src/debug/java/expo/modules/devmenu/**'
@@ -76,10 +60,10 @@ jobs:
- 'packages/expo-manifests/android/src/main/java/expo/modules/manifests/**'
- 'packages/expo-manifests/android/build.gradle'
compilation_test_ios:
- - 'packages/expo-brownfield/**'
- 'packages/expo/ios/AppDelegates/**'
- 'packages/expo-dev-menu/ios/**'
- 'packages/expo-manifests/ios/EXManifests/**'
+ - 'packages/expo-modules-core/ios/**'
compilation-test-android:
runs-on: ubuntu-24.04
diff --git a/.github/workflows/test-suite-brownfield-isolated.yml b/.github/workflows/test-suite-brownfield-isolated.yml
index 9f61f006ac0bfb..b6026ebed87579 100644
--- a/.github/workflows/test-suite-brownfield-isolated.yml
+++ b/.github/workflows/test-suite-brownfield-isolated.yml
@@ -94,12 +94,21 @@ jobs:
npx expo prebuild --clean -p android
npx expo-brownfield build:android --repo MavenLocal --verbose
working-directory: apps/brownfield-tester/expo-app
- - name: ๐๏ธ Build APK
+ - name: ๐๏ธ Build Debug APK
+ run: |
+ ./gradlew clean assembleDebug --refresh-dependencies
+ working-directory: apps/brownfield-tester/android-integrated
+ - name: ๐พ Store Debug APK artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: expo-brownfield-android-debug
+ path: apps/brownfield-tester/android-integrated/app/build/outputs/apk/debug/app-debug.apk
+ - name: ๐๏ธ Build Release APK
run: |
./gradlew clean
./gradlew assembleRelease --refresh-dependencies
working-directory: apps/brownfield-tester/android-integrated
- - name: ๐พ Store APK artifact
+ - name: ๐พ Store Release APK artifact
uses: actions/upload-artifact@v4
with:
name: expo-brownfield-android-release
@@ -122,23 +131,43 @@ jobs:
# Version `1.x` fails due to https://github.com/oven-sh/setup-bun/issues/37
# TODO(cedric): swap `latest` back once the issue is resolved
bun-version: latest
- - name: ๐ Download builds
+ - name: ๐ Download build (Release)
uses: actions/download-artifact@v4
with:
name: expo-brownfield-android-release
path: apps/brownfield-tester/android-integrated/apk
+ - name: ๐ Download build (Debug)
+ uses: actions/download-artifact@v4
+ with:
+ name: expo-brownfield-android-debug
+ path: apps/brownfield-tester/android-integrated/apk
- name: ๐บ Install Maestro
run: |
curl -Ls "https://get.maestro.mobile.dev" | bash
echo "${HOME}/.maestro/bin" >> $GITHUB_PATH
- - name: ๐งช Run e2e tests (isolated brownfield)
+ - name: ๐งช Run e2e tests (Release)
+ uses: ./.github/actions/use-android-emulator
+ with:
+ avd-api: ${{ matrix.api-level }}
+ avd-name: avd-${{ matrix.api-level }}
+ script:
+ ./packages/expo-brownfield/e2e/scripts/run-e2e-android.sh
+ - name: ๐งถ Install node modules in root dir
+ run: yarn install --frozen-lockfile
+ - name: ๐ท Build Expo CLI
+ run: yarn workspace @expo/cli prepare
+ - name: ๐ Start Metro server
+ run: |
+ yarn start --clear &
+ npx wait-on http://localhost:8081 --timeout 60000
+ working-directory: apps/brownfield-tester/expo-app
+ - name: ๐งช Run e2e tests (Debug)
uses: ./.github/actions/use-android-emulator
with:
avd-api: ${{ matrix.api-level }}
avd-name: avd-${{ matrix.api-level }}
script: |
- adb install -r apps/brownfield-tester/android-integrated/apk/*.apk
- cd packages/expo-brownfield/e2e && maestro test maestro/__tests__/android
+ CONFIGURATION=Debug ./packages/expo-brownfield/e2e/scripts/run-e2e-android.sh
- name: ๐ Notify on Slack
uses: ./.github/actions/slack-notify
if: failure() && (github.event.ref == 'refs/heads/main' || startsWith(github.event.ref, 'refs/heads/sdk-'))
@@ -147,16 +176,10 @@ jobs:
channel: '#expo-android'
author_name: E2E Test Suite for Expo Brownfield
- ios-e2e:
+ ios-build-and-e2e:
runs-on: macos-15
needs: detect-platform-for-e2e
if: needs.detect-platform-for-e2e.outputs.should_run_ios == 'true'
- strategy:
- fail-fast: false
- matrix:
- build-type: [release]
- # TODO(pmleczek): Add dev menu tests for iOS and Android
- # build-type: [debug, release]
steps:
- name: ๐ Checkout
uses: actions/checkout@v5
@@ -203,25 +226,30 @@ jobs:
run: yarn install --frozen-lockfile
- name: ๐ท Build Expo CLI
run: yarn workspace @expo/cli prepare
- - name: ๐ Build iOS artifacts (apps/brownfield-tester/expo-app)
+ - name: ๐ Build iOS artifacts (Release)
run: |
npx expo prebuild --clean -p ios
- npx expo-brownfield build:ios --${{ matrix.build-type }} --verbose -a ../../../artifacts -p BrownfieldPackage
+ npx expo-brownfield build:ios -r --verbose -a ../../../artifacts -p BrownfieldPackage
working-directory: apps/brownfield-tester/expo-app
- - name: ๐พ Save ccache
- if: always()
- uses: actions/cache/save@v4
- with:
- path: ${{ runner.temp }}/.ccache
- key: ${{ steps.ccache-restore.outputs.cache-primary-key }}
- - name: ๐จ Add brownfield Swift Package to the app
+ - name: ๐จ Add XCFrameworks to SwiftUI project
run: ruby packages/expo-brownfield/e2e/scripts/add_xcframeworks.rb
- name: ๐บ Install Maestro
run: |
curl -Ls "https://get.maestro.mobile.dev" | bash
echo "${HOME}/.maestro/bin" >> $GITHUB_PATH
- - name: ๐งช Run e2e tests (isolated brownfield)
+ - name: ๐งช Run e2e tests (Release)
run: ./packages/expo-brownfield/e2e/scripts/run-e2e-ios.sh
+ - name: ๐ Build iOS artifacts (Debug)
+ run: |
+ npx expo-brownfield build:ios -d --verbose -a ../../../artifacts -p BrownfieldPackage
+ - name: ๐งช Run e2e tests (Debug)
+ run: CONFIGURATION=Debug ./packages/expo-brownfield/e2e/scripts/run-e2e-ios.sh
+ - name: ๐พ Save ccache
+ if: always()
+ uses: actions/cache/save@v4
+ with:
+ path: ${{ runner.temp }}/.ccache
+ key: ${{ steps.ccache-restore.outputs.cache-primary-key }}
- name: Show ccache stats
run: ccache -s -v
- name: ๐ Notify on Slack
diff --git a/apps/bare-expo/ios/Podfile.lock b/apps/bare-expo/ios/Podfile.lock
index a4f3ec64f6ff27..25512c99c031cc 100644
--- a/apps/bare-expo/ios/Podfile.lock
+++ b/apps/bare-expo/ios/Podfile.lock
@@ -2958,7 +2958,7 @@ PODS:
- ReactNativeDependencies
- RNWorklets
- Yoga
- - RNScreens (4.23.0):
+ - RNScreens (4.24.0):
- hermes-engine
- RCTRequired
- RCTTypeSafety
@@ -2980,9 +2980,9 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- ReactNativeDependencies
- - RNScreens/common (= 4.23.0)
+ - RNScreens/common (= 4.24.0)
- Yoga
- - RNScreens/common (4.23.0):
+ - RNScreens/common (4.24.0):
- hermes-engine
- RCTRequired
- RCTTypeSafety
@@ -3995,7 +3995,7 @@ SPEC CHECKSUMS:
RNDateTimePicker: 5e0666de98f1edfac67ee7dde6be8a5415e487a0
RNGestureHandler: 6d378fd1aa991c7ab62a4215ee6cc417895a6954
RNReanimated: 752b27ede7d3f8970d5adba71f10258cb7848150
- RNScreens: fb11b7412bcbdc0ffafcaf9174938d998d4e2bc4
+ RNScreens: 088d923c4327c63c9f8c942cae17a9d038f47d97
RNSVG: 13970bfde0ea9c9e10e01ab0d7b4a6cde11fca1b
RNWorklets: 460112a8b250bcecd1b6b68d39a82fcdb6f8eb24
SDWebImage: e9c98383c7572d713c1a0d7dd2783b10599b9838
diff --git a/apps/bare-expo/package.json b/apps/bare-expo/package.json
index d21b66cb5be811..2f45b221bc3ccb 100644
--- a/apps/bare-expo/package.json
+++ b/apps/bare-expo/package.json
@@ -76,7 +76,7 @@
"react-native-reanimated": "4.2.2",
"react-native-safe-area-context": "5.6.2",
"react-native-svg": "15.15.3",
- "react-native-screens": "4.23.0",
+ "react-native-screens": "4.24.0",
"react-native-view-shot": "4.0.3",
"react-native-webview": "13.16.0",
"react-native-worklets": "0.7.4",
diff --git a/apps/brownfield-tester/android-integrated/app/src/main/java/dev/expo/brownfieldintegratedtester/BrownfieldTestActivity.kt b/apps/brownfield-tester/android-integrated/app/src/main/java/dev/expo/brownfieldintegratedtester/BrownfieldTestActivity.kt
index 377e683e2a7a96..37602728c6c8a2 100644
--- a/apps/brownfield-tester/android-integrated/app/src/main/java/dev/expo/brownfieldintegratedtester/BrownfieldTestActivity.kt
+++ b/apps/brownfield-tester/android-integrated/app/src/main/java/dev/expo/brownfieldintegratedtester/BrownfieldTestActivity.kt
@@ -2,6 +2,7 @@ package dev.expo.brownfieldintegratedtester
import android.util.Log
import android.widget.Toast
+import androidx.appcompat.app.AlertDialog
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler
import expo.modules.brownfield.BrownfieldMessage
import expo.modules.brownfield.BrownfieldMessaging
@@ -26,7 +27,7 @@ open class BrownfieldTestActivity : BrownfieldActivity(), DefaultHardwareBackBtn
BrownfieldMessaging.addListener { message ->
Log.i("BrownfieldTestActivity", "Message from React Native received:")
Log.i("BrownfieldTestActivity", message.toString())
- showToast(message)
+ showDialog(message)
}
setupStateListeners()
@@ -97,12 +98,20 @@ open class BrownfieldTestActivity : BrownfieldActivity(), DefaultHardwareBackBtn
messageTimer = null
}
- private fun showToast(message: BrownfieldMessage) {
+ private fun showDialog(message: BrownfieldMessage) {
val sender = message["sender"] as? String
val nested = message["source"] as? Map<*, *>
val platform = nested?.get("platform") as? String
if (sender != null && platform != null) {
- Toast.makeText(this, "$platform($sender)", Toast.LENGTH_LONG).show()
+ runOnUiThread {
+ AlertDialog.Builder(this)
+ .setTitle("Message Received") // Optional: give it a title
+ .setMessage("$platform($sender)")
+ .setPositiveButton("OK") { dialog, _ ->
+ dialog.dismiss() // Closes the dialog when clicked
+ }
+ .show()
+ }
}
}
diff --git a/apps/brownfield-tester/expo-app/package.json b/apps/brownfield-tester/expo-app/package.json
index 12c7a2189e8147..3663043ac135ac 100644
--- a/apps/brownfield-tester/expo-app/package.json
+++ b/apps/brownfield-tester/expo-app/package.json
@@ -35,7 +35,7 @@
"react-native-worklets": "0.7.4",
"react-native-reanimated": "~4.2.2",
"react-native-safe-area-context": "~5.6.2",
- "react-native-screens": "~4.23.0",
+ "react-native-screens": "~4.24.0",
"react-native-web": "~0.21.0"
},
"devDependencies": {
diff --git a/apps/brownfield-tester/expo-app/src/app/apis/dev-menu.tsx b/apps/brownfield-tester/expo-app/src/app/apis/dev-menu.tsx
new file mode 100644
index 00000000000000..0d756d82b7baa0
--- /dev/null
+++ b/apps/brownfield-tester/expo-app/src/app/apis/dev-menu.tsx
@@ -0,0 +1,21 @@
+import * as ExpoDevMenu from 'expo-dev-menu';
+import { SafeAreaView } from 'react-native-safe-area-context';
+
+import { ActionButton, Header } from '@/components';
+
+const Navigation = () => {
+ return (
+
+
+ ExpoDevMenu.openMenu()}
+ testID="dev-menu-open"
+ />
+
+ );
+};
+
+export default Navigation;
diff --git a/apps/brownfield-tester/expo-app/src/app/apis/index.tsx b/apps/brownfield-tester/expo-app/src/app/apis/index.tsx
index 4ccf1ae7f730d2..64776f7e49b9d0 100644
--- a/apps/brownfield-tester/expo-app/src/app/apis/index.tsx
+++ b/apps/brownfield-tester/expo-app/src/app/apis/index.tsx
@@ -4,10 +4,12 @@ import { SafeAreaView } from 'react-native-safe-area-context';
import { ActionButton } from '@/components';
+type Screen = 'communication' | 'dev-menu' | 'navigation' | 'state';
+
const Index = () => {
const router = useRouter();
- const navigateToScreen = (screen: 'communication' | 'navigation' | 'state') => {
+ const navigateToScreen = (screen: Screen) => {
router.navigate(`/apis/${screen}`);
};
@@ -37,6 +39,14 @@ const Index = () => {
onPress={() => navigateToScreen('state')}
testID="apis-state"
/>
+ navigateToScreen('dev-menu')}
+ testID="apis-dev-menu"
+ />
);
};
diff --git a/apps/brownfield-tester/expo-app/src/components/header/Header.tsx b/apps/brownfield-tester/expo-app/src/components/header/Header.tsx
index 751752f5f56913..48470a81d1eaa0 100644
--- a/apps/brownfield-tester/expo-app/src/components/header/Header.tsx
+++ b/apps/brownfield-tester/expo-app/src/components/header/Header.tsx
@@ -4,7 +4,7 @@ import { View, Text, Pressable, StyleSheet } from 'react-native';
import type { HeaderProps } from './types';
-const Header = ({ title }: HeaderProps) => {
+const Header = ({ title, testID }: HeaderProps) => {
const router = useRouter();
return (
@@ -15,7 +15,7 @@ const Header = ({ title }: HeaderProps) => {
testID="header-back-button">
- {title}
+ {title}
);
};
diff --git a/apps/brownfield-tester/expo-app/src/components/header/types.ts b/apps/brownfield-tester/expo-app/src/components/header/types.ts
index 5def2174bf21c6..a70aa4a571e5f6 100644
--- a/apps/brownfield-tester/expo-app/src/components/header/types.ts
+++ b/apps/brownfield-tester/expo-app/src/components/header/types.ts
@@ -1,3 +1,4 @@
export interface HeaderProps {
title: string;
+ testID?: string;
}
diff --git a/apps/expo-go/ios/Podfile.lock b/apps/expo-go/ios/Podfile.lock
index ecc873614fced4..79f984880e5dfb 100644
--- a/apps/expo-go/ios/Podfile.lock
+++ b/apps/expo-go/ios/Podfile.lock
@@ -3739,7 +3739,7 @@ PODS:
- RNWorklets
- SocketRocket
- Yoga
- - RNScreens (4.23.0):
+ - RNScreens (4.24.0):
- boost
- DoubleConversion
- fast_float
@@ -3766,10 +3766,10 @@ PODS:
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- - RNScreens/common (= 4.23.0)
+ - RNScreens/common (= 4.24.0)
- SocketRocket
- Yoga
- - RNScreens/common (4.23.0):
+ - RNScreens/common (4.24.0):
- boost
- DoubleConversion
- fast_float
@@ -4868,7 +4868,7 @@ SPEC CHECKSUMS:
RNDateTimePicker: e9e210197c267461f70f3f47bec705401ff72077
RNGestureHandler: 0ac42879420bf5353c06174d14af11f6435f3294
RNReanimated: f60cb180f1540dde5e14d1fdc09d20a3552ee3ff
- RNScreens: ec8bdc9f024d5828e5adf4f5e8870d5260cff616
+ RNScreens: 7179cc1ba31b4e18ed29f10abf20c24a7961cf4c
RNSVG: 15c97a81fe80139227609070b1c11a86dce5c9b6
RNWorklets: 7f524b9625dc3d9f1014ae6529fdd25a0141c922
SDWebImage: f29024626962457f3470184232766516dee8dfea
diff --git a/apps/expo-go/package.json b/apps/expo-go/package.json
index edbb9c61d5cec5..abac5a731903d2 100644
--- a/apps/expo-go/package.json
+++ b/apps/expo-go/package.json
@@ -78,7 +78,7 @@
"react-native-reanimated": "4.2.2",
"react-native-safe-area-context": "5.6.2",
"react-native-svg": "15.15.3",
- "react-native-screens": "4.23.0",
+ "react-native-screens": "4.24.0",
"react-native-view-shot": "4.0.3",
"react-native-webview": "13.16.0",
"react-native-worklets": "0.7.4",
diff --git a/apps/native-component-list/package.json b/apps/native-component-list/package.json
index 1b96e3f4a7db11..e589d16623c964 100644
--- a/apps/native-component-list/package.json
+++ b/apps/native-component-list/package.json
@@ -153,7 +153,7 @@
"react-native-reanimated": "4.2.2",
"react-native-safe-area-context": "5.6.2",
"react-native-svg": "15.15.3",
- "react-native-screens": "4.23.0",
+ "react-native-screens": "4.24.0",
"react-native-view-shot": "4.0.3",
"react-native-web": "~0.21.0",
"react-native-webview": "13.16.0",
diff --git a/apps/notification-tester/package.json b/apps/notification-tester/package.json
index 41ecf691a187d3..120285a4e5aa2c 100644
--- a/apps/notification-tester/package.json
+++ b/apps/notification-tester/package.json
@@ -36,7 +36,7 @@
"react": "19.2.3",
"react-native": "0.84.1",
"react-native-safe-area-context": "5.6.2",
- "react-native-screens": "4.23.0"
+ "react-native-screens": "4.24.0"
},
"devDependencies": {
"@babel/core": "^7.20.0",
diff --git a/apps/router-e2e/package.json b/apps/router-e2e/package.json
index d9626822cfe500..d1de2b19ceb1ca 100644
--- a/apps/router-e2e/package.json
+++ b/apps/router-e2e/package.json
@@ -73,7 +73,7 @@
"react": "19.2.3",
"react-native": "0.84.1",
"react-native-safe-area-context": "5.6.2",
- "react-native-screens": "4.23.0",
+ "react-native-screens": "4.24.0",
"react-native-webview": "13.16.0"
},
"devDependencies": {
diff --git a/docs/pages/archive/classic-updates/offline-support.mdx b/docs/pages/archive/classic-updates/offline-support.mdx
index b08e37a97e0129..ec26a91958dc4e 100644
--- a/docs/pages/archive/classic-updates/offline-support.mdx
+++ b/docs/pages/archive/classic-updates/offline-support.mdx
@@ -14,7 +14,7 @@ To force JS updates to run in the background (rather than synchronously checking
## Cache your assets after downloading
-By default, all of your assets (images, fonts, and so on) are [uploaded to Expo's CDN](/guides/assets/) when you publish updates to your app. Once they're downloaded, you can [cache them](/archive/classic-updates/preloading-and-caching-assets) so you don't need to download them a second time. If you publish changes, the cache will be invalidated and the changed version will be downloaded.
+By default, all of your assets (images, fonts, and so on) are [uploaded to Expo's CDN](/develop/user-interface/assets/) when you publish updates to your app. Once they're downloaded, you can [cache them](/archive/classic-updates/preloading-and-caching-assets) so you don't need to download them a second time. If you publish changes, the cache will be invalidated and the changed version will be downloaded.
## Bundle your assets inside your standalone binary
diff --git a/docs/pages/archive/glossary.mdx b/docs/pages/archive/glossary.mdx
index c6a4d367ce2ace..c6a90a40191243 100644
--- a/docs/pages/archive/glossary.mdx
+++ b/docs/pages/archive/glossary.mdx
@@ -12,12 +12,12 @@ The term "detach" was previously used in Expo to mean [ejecting](#eject) your ap
The term "eject" was popularized by [create-react-app](https://github.com/facebook/create-react-app), and it is used in Expo to describe leaving the cozy comfort of the standard Expo development environment, where you do not have to deal with build configuration or native code. When you "eject" from Expo, you have two choices:
-- _Eject to bare workflow_, where you jump between [workflows](/archive/managed-vs-bare/) and move into the bare workflow, where you can continue to use Expo APIs but have access and full control over your native Android and iOS projects.
+- _Eject to bare workflow_, where you jump between [workflows](/workflow/overview/) and move into the bare workflow, where you can continue to use Expo APIs but have access and full control over your native Android and iOS projects.
- _Eject to ExpoKit_, where you get the native projects along with [ExpoKit](#expokit). This option is deprecated and support for ExpoKit was removed after SDK 38.
### ExpoKit
-ExpoKit is an Objective-C and Java library that allows you to use the [Expo SDK](/more/glossary-of-terms/#expo-sdk) and platform and your existing Expo project as part of a larger standard native project โ one that you would normally create using Xcode, Android Studio, or `react-native init`. For more information, see [Ejecting to ExpoKit](/archive/expokit/eject/).
+ExpoKit is an Objective-C and Java library that allows you to use the [Expo SDK](/more/glossary-of-terms/#expo-sdk) and platform and your existing Expo project as part of a larger standard native project โ one that you would normally create using Xcode, Android Studio, or `react-native init`. For more information, see [Ejecting to ExpoKit](#eject).
**Support for ExpoKit ended after SDK 38. Expo modules can implement support for custom native configuration, and projects that need even more custom native code can [expose their Android Studio and Xcode projects with `npx expo prebuild`](/workflow/customizing/).**
diff --git a/docs/pages/archive/push-notifications/sending-notifications-custom-fcm-legacy.mdx b/docs/pages/archive/push-notifications/sending-notifications-custom-fcm-legacy.mdx
index 587521340125aa..0c49f5ff42978b 100644
--- a/docs/pages/archive/push-notifications/sending-notifications-custom-fcm-legacy.mdx
+++ b/docs/pages/archive/push-notifications/sending-notifications-custom-fcm-legacy.mdx
@@ -8,7 +8,7 @@ description: Learn how to send notifications with FCM legacy server.
> **info** For documentation on communicating with the newer FCMv1 service, see [Send notifications with FCMv1 and APNs](/push-notifications/sending-notifications-custom/). This guide is based on [Google's documentation](https://firebase.google.com/docs/cloud-messaging/http-server-ref), and this section covers the basics to get you started.
>
-> Before sending a notification directly through FCM, you will need to [obtain a device token](/push-notifications/obtaining-a-device-token-for-fcm-or-apns).
+> Before sending a notification directly through FCM, you will need to [obtain a device token](/push-notifications/sending-notifications-custom/).
Communicating with FCM is done by sending a POST request. However, before sending or receiving any notifications, you'll need to follow the steps to [configure FCM](/push-notifications/push-notifications-setup/#android) to configure FCM and get your `FCM-SERVER-KEY`.
@@ -34,7 +34,7 @@ await fetch('https://fcm.googleapis.com/fcm/send', {
**The `experienceId` and `scopeKey` fields are required**. Otherwise, your notifications will not go through to your app. FCM has a list of supported fields in the [notification payload](https://firebase.google.com/docs/cloud-messaging/http-server-ref#notification-payload-support), and you can see which ones are supported by `expo-notifications` on Android by looking at the [FirebaseRemoteMessage](/versions/latest/sdk/notifications/#firebaseremotemessage).
-FCM also provides some [server-side libraries in a few different languages](https://firebase.google.com/docs/cloud-messaging/send-message#node.js) you can use instead of raw `fetch` requests.
+FCM also provides some [server-side libraries in a few different languages](https://firebase.google.com/docs/cloud-messaging/send/admin-sdk) you can use instead of raw `fetch` requests.
### How to find FCM server key
@@ -67,7 +67,7 @@ Your FCM server key can be found by making sure you've followed the [configurati
### Firebase notification types
-There are two types of Firebase Cloud Messaging messages: [notification and data messages](https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages).
+There are two types of Firebase Cloud Messaging messages: [notification and data messages](https://firebase.google.com/docs/cloud-messaging/customize-messages/set-message-type#notification-messages-with-optional-data-payload).
1. **Notification** messages are only handled (and displayed) by the Firebase library. They don't necessarily wake the app, and `expo-notifications` will not be made aware that your app has received any notification.
diff --git a/docs/pages/billing/plans.mdx b/docs/pages/billing/plans.mdx
index 2ad80bab399f8a..9bd485e469310c 100644
--- a/docs/pages/billing/plans.mdx
+++ b/docs/pages/billing/plans.mdx
@@ -92,6 +92,6 @@ The Enterprise Support add-on is only available for new Enterprise plan subscrib
diff --git a/docs/pages/build-reference/troubleshooting.mdx b/docs/pages/build-reference/troubleshooting.mdx
index df03bc8e569e91..00d9e46128a167 100644
--- a/docs/pages/build-reference/troubleshooting.mdx
+++ b/docs/pages/build-reference/troubleshooting.mdx
@@ -46,7 +46,7 @@ For example, you might see something like this on your Android builds:
]}
/>
-While you may or may not be interested in following up on that warning, it is not the cause of your failed build. So how do you know which logs are truly responsible? If you are building a bare project, you will already be good at this. If you are building a [managed project](/archive/managed-vs-bare/), it may be tricky because you don't directly interact with the native code, only write JavaScript.
+While you may or may not be interested in following up on that warning, it is not the cause of your failed build. So how do you know which logs are truly responsible? If you are building a bare project, you will already be good at this. If you are building a [managed project](/workflow/overview/), it may be tricky because you don't directly interact with the native code, only write JavaScript.
A good path forward is to **determine if the build failed due to a native or JavaScript error**. When your build fails due to a JavaScript build error, you will usually see something like this:
diff --git a/docs/pages/build/updates.mdx b/docs/pages/build/updates.mdx
index 9b8ebb540bc782..55cbbf96f2a989 100644
--- a/docs/pages/build/updates.mdx
+++ b/docs/pages/build/updates.mdx
@@ -31,7 +31,7 @@ The following example demonstrates how you might use the `"production"` channel
Your native runtime may change on each build, depending on whether you modify the code in a way that changes the API contract with JavaScript. If you publish a JavaScript bundle to a binary with an incompatible native runtime (for example, a function that the JavaScript bundle expects to exist does not exist) then your app may not work as expected, or it may crash.
-We recommend using a different [runtime version](/distribution/runtime-versions/) for each binary version of your app. Any time you change the native runtime (in managed apps, this happens when you add or remove a native library, or modify **app.json**), you should increment the runtime version.
+We recommend using a different [runtime version](/eas-update/runtime-versions/) for each binary version of your app. Any time you change the native runtime (in managed apps, this happens when you add or remove a native library, or modify **app.json**), you should increment the runtime version.
## Previewing updates in development builds
@@ -39,4 +39,4 @@ Updates published with the `runtimeVersion` field can't be loaded in Expo Go. In
## Environment variables and `eas update`
-Environment variables set on the `env` field in build profiles are not available when you run `eas update`. Learn more about using [environment variables with EAS Update](/eas-update/environment-variables).
+Environment variables set on the `env` field in build profiles are not available when you run `eas update`. Learn more about using [environment variables with EAS Update](/eas/environment-variables/usage/#using-environment-variables-with-eas-update).
diff --git a/docs/pages/develop/development-builds/share-with-your-team.mdx b/docs/pages/develop/development-builds/share-with-your-team.mdx
index 3cbc9aa046ea15..0786decf05b97d 100644
--- a/docs/pages/develop/development-builds/share-with-your-team.mdx
+++ b/docs/pages/develop/development-builds/share-with-your-team.mdx
@@ -66,6 +66,6 @@ You can use `eas build:resign` to codesign an existing **.ipa** for iOS to a new
diff --git a/docs/pages/eas-update/debug.mdx b/docs/pages/eas-update/debug.mdx
index 1563b7262c17b9..f92fe222de6234 100644
--- a/docs/pages/eas-update/debug.mdx
+++ b/docs/pages/eas-update/debug.mdx
@@ -19,7 +19,7 @@ This guide shows how to verify our configuration so that we can find the source
-> If we are not using EAS Build, our Deployments page will be empty. Follow the guide on [debugging configuration without EAS Build](/eas-update/debug-advanced/#configuration-without-eas-build) instead.
+> If we are not using EAS Build, our Deployments page will be empty. Follow the guide on [debugging configuration without EAS Build](/eas-update/debug/#configuration-without-eas-build) instead.
## Go to the Deployments page
@@ -89,7 +89,7 @@ The displayed deployment has the correct channel, but it is not linked to a bran
### Missing deployment
-If our deployment is not displayed, it means our build is not configured properly for EAS Update. To fix this, [configure our channel](/#configure-channel), [configure our runtime version](/#configure-runtime-version) and verify our [general configuration](/eas-update/debug-advanced/#verifying-app-configuration). We'll need to rebuild our app after making these changes.
+If our deployment is not displayed, it means our build is not configured properly for EAS Update. To fix this, [configure our channel](/#configure-channel), [configure our runtime version](/#configure-runtime-version) and verify our [general configuration](/eas-update/debug/#verifying-app-configuration). We'll need to rebuild our app after making these changes.
### Automatic roll back when an update crashes
@@ -247,7 +247,7 @@ If we aren't using EAS Build, this section will walk through debugging the state
#### Verify build configuration
-Follow the [Building Locally guide](/eas-update/standalone-service/) to configure our app's channel and runtime version. We'll also need to make sure our [general configuration](/eas-update/debug-advanced/#expo-updates-configuration) is correct.
+Follow the [Building Locally guide](/eas-update/standalone-service/) to configure our app's channel and runtime version. We'll also need to make sure our [general configuration](/eas-update/debug/#expo-updates-configuration) is correct.
#### Verify the channel
diff --git a/docs/pages/eas-update/deployment.mdx b/docs/pages/eas-update/deployment.mdx
index 8be27c8665db7a..2c99843458f242 100644
--- a/docs/pages/eas-update/deployment.mdx
+++ b/docs/pages/eas-update/deployment.mdx
@@ -26,7 +26,7 @@ In this guide, we'll describe a simple but powerful release process that uses **
The most simple way to use EAS Update is to ignore the concept of "branches" and focus on "channels". Branches will still exist, but you will not have to interact with them directly to manage deployments. You can keep your channels pointed at a branch with the same name as the channel and think of them as a singular concept.
-EAS Update branches were meant to map to Git branches and enable teams to publish changes from a Git branch directly to an EAS Update branch of the same name. This can be helpful for [previewing updates](/eas-update/develop-faster/), but for many apps, this level of integration with Git is not required. Often, developers are only interested in being able to release hotfixes to a staging or production version of their app manually, and can run `eas update --channel staging` or `eas update --channel production`, when needed rather than managing branches to accomplish the same result.
+EAS Update branches were meant to map to Git branches and enable teams to publish changes from a Git branch directly to an EAS Update branch of the same name. This can be helpful for [previewing updates](/eas-update/preview/), but for many apps, this level of integration with Git is not required. Often, developers are only interested in being able to release hotfixes to a staging or production version of their app manually, and can run `eas update --channel staging` or `eas update --channel production`, when needed rather than managing branches to accomplish the same result.
@@ -99,7 +99,7 @@ As explained above, preview builds will point to the "preview" channel. If you w
### Preview in development builds
-Development builds can load updates from any channel, provided the runtime version is compatible. Learn more about this in [Previewing updates](/eas-update/develop-faster/).
+Development builds can load updates from any channel, provided the runtime version is compatible. Learn more about this in [Previewing updates](/eas-update/preview/).
## Deploying to staging
@@ -144,4 +144,4 @@ Learn more in [Rollbacks](/eas-update/rollbacks/).
## Next steps
- [Learn more about the Persistent staging release process](/eas-update/deployment-patterns/#persistent-staging-flow), which is very similar to what is described here.
-- [Explore using preview updates in development builds](/eas-update/develop-faster/).
+- [Explore using preview updates in development builds](/eas-update/preview/).
diff --git a/docs/pages/eas-update/getting-started.mdx b/docs/pages/eas-update/getting-started.mdx
index 8707b177ed6305..3272fc18434f95 100644
--- a/docs/pages/eas-update/getting-started.mdx
+++ b/docs/pages/eas-update/getting-started.mdx
@@ -306,7 +306,7 @@ If your app is not updating as expected, see the [debugging guide](/eas-update/d
diff --git a/docs/pages/eas-update/integration-in-existing-native-apps.mdx b/docs/pages/eas-update/integration-in-existing-native-apps.mdx
index e90660ec809495..8b0c4fc01a6cc5 100644
--- a/docs/pages/eas-update/integration-in-existing-native-apps.mdx
+++ b/docs/pages/eas-update/integration-in-existing-native-apps.mdx
@@ -23,7 +23,7 @@ You should have a brownfield native project with React Native installed and conf
- Your app must be using the [latest Expo SDK version and its supported React Native version](/versions/latest/#each-expo-sdk-version-depends-on-a-react-native-version).
- Remove any other update library integration from your app, such as react-native-code-push, and ensure that your app compiles and runs successfully in both debug and release on your supported platforms.
-- Support for Expo modules (through the `expo` package) must be installed and configured in your project. [Learn more](/brownfield/installing-expo-modules/).
+- Support for Expo modules (through the `expo` package) must be installed and configured in your project. [Learn more](/brownfield/overview/).
- Your **metro.config.js** [must extend `expo/metro-config`](/guides/customizing-metro/#customizing) .
- Your **babel.config.js** [must extend `babel-preset-expo`](/versions/latest/config/babel/).
- The command `npx expo export -p android` must run successfully in your project if it supports Android, and `npx expo export -p ios` if it supports iOS.
diff --git a/docs/pages/eas-update/introduction.mdx b/docs/pages/eas-update/introduction.mdx
index a6b07bbf736e27..aa5f76f7679714 100644
--- a/docs/pages/eas-update/introduction.mdx
+++ b/docs/pages/eas-update/introduction.mdx
@@ -192,7 +192,7 @@ We recommend transitioning to EAS Update or using a [self-hosted update service]
diff --git a/docs/pages/eas/hosting/introduction.mdx b/docs/pages/eas/hosting/introduction.mdx
index d01627940e007c..1f50f55e754c50 100644
--- a/docs/pages/eas/hosting/introduction.mdx
+++ b/docs/pages/eas/hosting/introduction.mdx
@@ -158,7 +158,7 @@ For more information, see the [Web deployments with EAS Workflows](/eas/hosting/
diff --git a/docs/pages/faq.mdx b/docs/pages/faq.mdx
index c24618573bc314..14db9d749b6234 100644
--- a/docs/pages/faq.mdx
+++ b/docs/pages/faq.mdx
@@ -21,7 +21,7 @@ When Expo was first created, React Native had yet to be publicly released. This
The Expo SDK is well-tested, written in TypeScript, documented, and built for Android, iOS, and the web. Every module in the Expo SDK works together to ensure versioning always matches. This creates a nice upgrading experience.
-The Expo SDK is also written with the [Expo Modules API](/modules) to make contributing, maintaining, and understanding easier.
+The Expo SDK is also written with the [Expo Modules API](/modules/overview/) to make contributing, maintaining, and understanding easier.
## What is the difference between Expo and React Native?
@@ -43,7 +43,7 @@ Expo supports adding custom native code and customizing that native code (Androi
## Can I use Expo in the app that is created with React Native CLI?
-Yes! All Expo tools and services work great in any React Native app. For example, you can use any part of the [Expo SDK](/versions/latest), [`expo-dev-client`](/develop/development-builds/installation/) and EAS Build, Submit, and Update — they work great! Learn more about [installing `expo` in your project](/bare/installing-expo-modules), [adopting prebuild](/guides/adopting-prebuild), and [setting up EAS Build](/build/introduction).
+Yes! All Expo tools and services work great in any React Native app. For example, you can use any part of the [Expo SDK](/versions/latest), [`expo-dev-client`](/develop/development-builds/create-a-build/) and EAS Build, Submit, and Update — they work great! Learn more about [installing `expo` in your project](/bare/installing-expo-modules), [adopting prebuild](/guides/adopting-prebuild), and [setting up EAS Build](/build/introduction).
## How do I share my Expo project? Can I submit it to the app stores?
@@ -69,7 +69,7 @@ If the `expo` package is included in your app, it only adds 1 MB one time to the
## Can I use Expo with my native library?
-You can use native Android and iOS libraries with Expo by creating a [custom native module](/modules) with Swift and Kotlin. Many popular libraries already have custom native modules. Check out our [React Native directory](https://reactnative.directory) to find popular libraries for your use case.
+You can use native Android and iOS libraries with Expo by creating a [custom native module](/modules/overview/) with Swift and Kotlin. Many popular libraries already have custom native modules. Check out our [React Native directory](https://reactnative.directory) to find popular libraries for your use case.
## Can I use Expo with this web library?
diff --git a/docs/pages/guides/using-firebase.mdx b/docs/pages/guides/using-firebase.mdx
index 2aafeb1cd3d95c..d0d2824c80d0ae 100644
--- a/docs/pages/guides/using-firebase.mdx
+++ b/docs/pages/guides/using-firebase.mdx
@@ -157,7 +157,7 @@ Each Firebase service is available as a module that can be added as a dependency
You can consider using React Native Firebase when:
-- Your app requires access to Firebase services not supported by the Firebase JS SDK, such as [Dynamic Links](https://rnfirebase.io/dynamic-links/usage), [Crashlytics](https://rnfirebase.io/crashlytics/usage), and so on.
+- Your app requires access to Firebase services not supported by the Firebase JS SDK, such as [Dynamic Links](https://rnfirebase.io/screencasts/dynamic-links-overview), [Crashlytics](https://rnfirebase.io/crashlytics/usage), and so on.
For more information on the additional capabilities offered by the native SDK's, see [React Native Firebase documentation](https://rnfirebase.io/faqs-and-tips#why-react-native-firebase-over-firebase-js-sdk).
- You want to use native SDKs in your app.
- You have a bare React Native app with React Native Firebase already configured but are migrating to use Expo SDK.
@@ -181,7 +181,7 @@ React Native Firebase requires [custom native code and cannot be used with Expo
Since React Native Firebase requires custom native code, you need to install the `expo-dev-client` library in your project.
It allows configuring any native code required by React Native Firebase using [Config plugins](/config-plugins/introduction/) without writing native code yourself.
-To install [`expo-dev-client`](/development/getting-started/#installing--expo-dev-client--in-your-project), run the following command in your project:
+To install [`expo-dev-client`](/develop/development-builds/create-a-build/), run the following command in your project:
diff --git a/docs/pages/guides/using-push-notifications-services.mdx b/docs/pages/guides/using-push-notifications-services.mdx
index b3631f01426b1f..a243f726093af0 100644
--- a/docs/pages/guides/using-push-notifications-services.mdx
+++ b/docs/pages/guides/using-push-notifications-services.mdx
@@ -61,7 +61,7 @@ For implementation details, see the following guides:
diff --git a/docs/pages/guides/using-vexo.mdx b/docs/pages/guides/using-vexo.mdx
index 2fb0c415476b4f..f9b46d5843155a 100644
--- a/docs/pages/guides/using-vexo.mdx
+++ b/docs/pages/guides/using-vexo.mdx
@@ -59,7 +59,7 @@ With a two-line integration, Vexo starts collecting data automatically, giving y
## Compatibility
-- Expo: Vexo is compatible with [Development builds](/development/introduction/) and does not require additional configuration plugins.
+- Expo: Vexo is compatible with [Development builds](/develop/development-builds/introduction/) and does not require additional configuration plugins.
- Expo Go: Not supported, as Vexo requires custom native code.
## Learn more about Vexo
diff --git a/docs/pages/guides/why-metro.mdx b/docs/pages/guides/why-metro.mdx
index 34084b7dd6a424..3d873ea5c6eb80 100644
--- a/docs/pages/guides/why-metro.mdx
+++ b/docs/pages/guides/why-metro.mdx
@@ -23,7 +23,7 @@ New and upcoming features that are planned to come to Metro include:
- Compiling Flow code to native machine code with Static Hermes. Learn more in the [Static Hermes](https://www.youtube.com/watch?v=GUM64b-gAGg) talk by Tzvetan Mikov.
- Data fetching, streaming, React Suspense, server rendering, and build-time static rendering with universal React Server Components for all platforms. Learn more in the [Universal React Server Components](https://www.youtube.com/watch?v=djhEgxQf3Kw) talk at React Conf 2024.
-The Expo team collaborates with Meta to develop Metro for Expo Router, adding features like [file-based routing](/develop/file-based-routing/), [web support](/guides/customizing-metro/#web-support), [bundle splitting](/guides/customizing-metro/#bundle-splitting), [tree shaking](/guides/tree-shaking/), [CSS](/versions/latest/config/metro/#css), [DOM components](/guides/dom-components/), server components, and [API routes](/router/web/api-routes/).
+The Expo team collaborates with Meta to develop Metro for Expo Router, adding features like [file-based routing](/develop/app-navigation/), [web support](/guides/customizing-metro/#web-support), [bundle splitting](/guides/customizing-metro/#bundle-splitting), [tree shaking](/guides/tree-shaking/), [CSS](/versions/latest/config/metro/#css), [DOM components](/guides/dom-components/), server components, and [API routes](/router/web/api-routes/).
## Battle-tested at scale
diff --git a/docs/pages/linking/into-other-apps.mdx b/docs/pages/linking/into-other-apps.mdx
index af7af9e5a38ad7..6d46837712643f 100644
--- a/docs/pages/linking/into-other-apps.mdx
+++ b/docs/pages/linking/into-other-apps.mdx
@@ -10,7 +10,7 @@ import { SnackInline } from '~/ui/components/Snippet';
Handling linking into other apps from your app is achieved by using the target app's URL. There are two methods you can use to open such URLs from your app:
- Using the [`expo-linking`](/versions/latest/sdk/linking) API
-- Using Expo Router's [`Link` component](/develop/file-based-routing/#how-does-link-work)
+- Using Expo Router's [`Link` component](/develop/app-navigation/)
## Using expo-linking API
diff --git a/docs/pages/modules/additional-platform-support.mdx b/docs/pages/modules/additional-platform-support.mdx
index 873d41cd24da6f..fb46a78170d1be 100644
--- a/docs/pages/modules/additional-platform-support.mdx
+++ b/docs/pages/modules/additional-platform-support.mdx
@@ -65,7 +65,7 @@ Any changes in the podspec require running `pod install` to have an effect.
If you are writing a local module and your app is already set up, you can skip this step. Otherwise, you will need to set up your app or the example app if you are writing a standalone (non-local) module.
-- **For macOS**: follow the official [Install React Native for macOS](https://microsoft.github.io/react-native-windows/docs/rnm-getting-started#install-the-macos-extension) guide from `react-native-macos` documentation.
+- **For macOS**: follow the official [Install React Native for macOS](https://microsoft.github.io/react-native-macos/docs/getting-started) guide from `react-native-macos` documentation.
- **For tvOS**: follow the instructions in the [`react-native-tvos`](https://github.com/react-native-tvos/react-native-tvos) repository. If you are building an Expo app, you should also follow the instructions in the [Build Expo apps for TV guide](/guides/building-for-tv/).
diff --git a/docs/pages/push-notifications/sending-notifications-custom.mdx b/docs/pages/push-notifications/sending-notifications-custom.mdx
index ad89b1a6ffbb4d..7fe9fbc7ae4830 100644
--- a/docs/pages/push-notifications/sending-notifications-custom.mdx
+++ b/docs/pages/push-notifications/sending-notifications-custom.mdx
@@ -37,7 +37,7 @@ Communicating with FCM is done by sending a POST request. However, before sendin
### Getting an authentication token
-FCM requires an Oauth 2.0 access token, which must be obtained via one of the methods described in ["Update authorization of send requests"](https://firebase.google.com/docs/cloud-messaging/migrate-v1#update-authorization-of-send-requests).
+FCM requires an Oauth 2.0 access token, which must be obtained via one of the methods described in ["Update authorization of send requests"](https://firebase.google.com/docs/cloud-messaging/send/v1-api#authorize-http-v1-send-requests).
For testing purposes, you can use the Google Auth Library and your private key file obtained above, to obtain a short lived token for a single notification, as in this Node example adapted from Firebase documentation:
@@ -117,7 +117,7 @@ async function sendFCMv1Notification() {
The `experienceId` and `scopeKey` fields are only applicable when using Expo Go (from SDK 53, push notifications support is removed from Expo Go). Otherwise, your notifications will not go through to your app. FCM has a list of supported fields in the [notification payload](https://firebase.google.com/docs/cloud-messaging/http-server-ref#notification-payload-support), and you can see which ones are supported by `expo-notifications` on Android by looking at the [FirebaseRemoteMessage](/versions/latest/sdk/notifications/#firebaseremotemessage).
-FCM also provides some [server-side libraries in a few different languages](https://firebase.google.com/docs/cloud-messaging/send-message#node.js) you can use instead of raw `fetch` requests.
+FCM also provides some [server-side libraries in a few different languages](https://firebase.google.com/docs/cloud-messaging/send/admin-sdk) you can use instead of raw `fetch` requests.
### How to find FCM server key
diff --git a/docs/pages/push-notifications/what-you-need-to-know.mdx b/docs/pages/push-notifications/what-you-need-to-know.mdx
index 5bfea16d70e342..bc8ec7bb1beee6 100644
--- a/docs/pages/push-notifications/what-you-need-to-know.mdx
+++ b/docs/pages/push-notifications/what-you-need-to-know.mdx
@@ -69,7 +69,7 @@ The typical use case for a Notification Message is to have it presented to the u
### Notification Message with data payload
-This is an Android-only term ([see the official docs](https://firebase.google.com/docs/cloud-messaging/concept-options#data_messages)) where a push notification request contains both `data` field and a `notification` field.
+This is an Android-only term ([see the official docs](https://firebase.google.com/docs/cloud-messaging/customize-messages/set-message-type#data-messages)) where a push notification request contains both `data` field and a `notification` field.
On iOS, extra data may be part of a regular Notification Message request. Apple doesn't distinguish between Notification Message which does and does not carry data.
@@ -77,7 +77,7 @@ On iOS, extra data may be part of a regular Notification Message request. Apple
Headless Notification is a remote notification that doesn't directly specify presentational information such as the title or body text. With the exception below\*, headless notifications are not presented to users. Instead, they carry data (JSON) which is processed by a JavaScript task defined in your app via [`registerTaskAsync`](/versions/latest/sdk/notifications/#registertaskasynctaskname). The task may perform arbitrary logic. For example, write to `AsyncStorage`, make an api request, or present a local notification whose content is taken from the push notification's data.
-> **info** We use the term "Headless Background Notification" to refer to the [Data Message](https://firebase.google.com/docs/cloud-messaging/concept-options#data_messages) on Android and the [background notification](https://developer.apple.com/documentation/usernotifications/pushing-background-updates-to-your-app#Create-a-background-notification) on iOS. Their key similarities are that both of these notification types allow sending only JSON data, and background processing by the app.
+> **info** We use the term "Headless Background Notification" to refer to the [Data Message](https://firebase.google.com/docs/cloud-messaging/customize-messages/set-message-type#data-messages) on Android and the [background notification](https://developer.apple.com/documentation/usernotifications/pushing-background-updates-to-your-app#Create-a-background-notification) on iOS. Their key similarities are that both of these notification types allow sending only JSON data, and background processing by the app.
Headless Background Notifications have the ability to run custom JavaScript in response to a notification _even when the app is terminated_. This is powerful but comes with a limitation: even when the notification is delivered to the device, the OS does not guarantee its delivery to your app. This may happen due to a variety of reasons, such as when [Doze mode](https://developer.android.com/training/monitoring-device-state/doze-standby) is enabled on Android, or when you send too many background notifications — Apple recommends not to [send more than two or three per hour](https://developer.apple.com/documentation/usernotifications/pushing-background-updates-to-your-app#overview).
@@ -93,7 +93,7 @@ The rule of thumb is to prefer a regular Notification Message if you don't requi
### Data-only notifications
-Android has a concept of [Data Messages](https://firebase.google.com/docs/cloud-messaging/concept-options#data_messages). iOS does not have exactly the same concept, but a close equivalent is [Headless Background Notifications](#headless-background-notifications).
+Android has a concept of [Data Messages](https://firebase.google.com/docs/cloud-messaging/customize-messages/set-message-type#data-messages). iOS does not have exactly the same concept, but a close equivalent is [Headless Background Notifications](#headless-background-notifications).
You may also come across the term "silent notification", which is yet another name for notifications that don't present anything to the user — we describe these as [Headless Background Notifications](#headless-background-notifications).
diff --git a/docs/pages/router/advanced/modals.mdx b/docs/pages/router/advanced/modals.mdx
index 15e51292f0ea80..6e497cd9f25028 100644
--- a/docs/pages/router/advanced/modals.mdx
+++ b/docs/pages/router/advanced/modals.mdx
@@ -132,7 +132,7 @@ A modal loses its previous context when it is the current screen in the navigato
- On Android, the modal slides on top of the current screen. To dismiss it, use the back button to navigate back to the previous screen.
- On iOS, the modal slides from the bottom of the current screen. To dismiss it, swipe it down from the top.
-- On web, the modal is presented as a separate route, and the dismiss behavior has to be provided manually using [`router.canGoBack()`](/router/navigating-pages/#imperative-navigation). Here's an example of how to dismiss the modal:
+- On web, the modal is presented as a separate route, and the dismiss behavior has to be provided manually using [`router.canGoBack()`](/router/basics/navigation/). Here's an example of how to dismiss the modal:
{/* prettier-ignore */}
```tsx src/app/modal.tsx
diff --git a/docs/pages/router/advanced/redirects.mdx b/docs/pages/router/advanced/redirects.mdx
index b129b5e8fd3cf4..3da452e9b553c8 100644
--- a/docs/pages/router/advanced/redirects.mdx
+++ b/docs/pages/router/advanced/redirects.mdx
@@ -82,7 +82,7 @@ Unlike routes within the **app** directory, you do not need to add the `/index`
### Dynamic routes
-The `source` and `destination` routes can use the [dynamic route syntax](/develop/dynamic-routes/) to create redirects for dynamic routes. You can define them in **app.json** using the `expo-router` config plugin.
+The `source` and `destination` routes can use the [dynamic route syntax](/develop/app-navigation/) to create redirects for dynamic routes. You can define them in **app.json** using the `expo-router` config plugin.
```json app.json
{
diff --git a/docs/pages/submit/android.mdx b/docs/pages/submit/android.mdx
index 0ff79dd1dbb863..d2516a6126373a 100644
--- a/docs/pages/submit/android.mdx
+++ b/docs/pages/submit/android.mdx
@@ -151,7 +151,7 @@ Once you have completed all the prerequisites, you can set up a CI/CD pipeline t
### Use EAS Workflows CI/CD
-You can use [EAS Workflows](/eas-workflows/get-started/) to build and submit your app automatically.
+You can use [EAS Workflows](/eas/workflows/get-started/) to build and submit your app automatically.
1. Create a workflow file named **.eas/workflows/submit-android.yml** at the root of your project.
2. Inside **submit-android.yml**, you can use the following workflow to kick off a job that submits an Android app:
diff --git a/docs/pages/submit/ios.mdx b/docs/pages/submit/ios.mdx
index 27040e8b9a81ca..60f4d7b99590c1 100644
--- a/docs/pages/submit/ios.mdx
+++ b/docs/pages/submit/ios.mdx
@@ -172,7 +172,7 @@ Once you have completed all the prerequisites, you can set up a CI/CD pipeline t
### Use EAS Workflows CI/CD
-You can use [EAS Workflows](/eas-workflows/get-started/) to build and submit your app automatically.
+You can use [EAS Workflows](/eas/workflows/get-started/) to build and submit your app automatically.
1. Create a workflow file named **.eas/workflows/submit-ios.yml** at the root of your project.
2. Inside **submit-ios.yml**, you can use the following workflow to kick off a job that submits an iOS app:
diff --git a/docs/pages/troubleshooting/overview.mdx b/docs/pages/troubleshooting/overview.mdx
index 101c35d7d72166..b6cbd125166f34 100644
--- a/docs/pages/troubleshooting/overview.mdx
+++ b/docs/pages/troubleshooting/overview.mdx
@@ -108,7 +108,7 @@ This page lists a collection of various troubleshooting guides for Expo and EAS.
@@ -140,7 +140,7 @@ This page lists a collection of various troubleshooting guides for Expo and EAS.
diff --git a/docs/pages/tutorial/eas/configure-development-build.mdx b/docs/pages/tutorial/eas/configure-development-build.mdx
index f815772d08fb37..fe4b5c7e123835 100644
--- a/docs/pages/tutorial/eas/configure-development-build.mdx
+++ b/docs/pages/tutorial/eas/configure-development-build.mdx
@@ -27,7 +27,7 @@ A [development build](/develop/development-builds/introduction/) is a debug vers
### Key highlights
-> **Note:** If you are familiar with [Expo Go](/get-started/expo-go/), think of a development build as a customizable version of Expo Go that is unique to the requirements of a project.
+> **Note:** If you are familiar with [Expo Go](/get-started/set-up-your-environment/), think of a development build as a customizable version of Expo Go that is unique to the requirements of a project.
| Feature | Development Builds | Expo Go |
| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
diff --git a/docs/pages/versions/unversioned/sdk/print.mdx b/docs/pages/versions/unversioned/sdk/print.mdx
index aaa4fbdb486db2..4e698bd2d9db53 100644
--- a/docs/pages/versions/unversioned/sdk/print.mdx
+++ b/docs/pages/versions/unversioned/sdk/print.mdx
@@ -37,7 +37,7 @@ const html = `
Hello Expo!