diff --git a/.github/resources/expo.svg b/.github/resources/expo.svg new file mode 100644 index 00000000000000..7cc5b408078380 --- /dev/null +++ b/.github/resources/expo.svg @@ -0,0 +1,8 @@ + + + +
+ + + +
diff --git a/apps/bare-expo/App.tsx b/apps/bare-expo/App.tsx index 62e271601ee9b9..8807fd85960173 100644 --- a/apps/bare-expo/App.tsx +++ b/apps/bare-expo/App.tsx @@ -69,6 +69,9 @@ function useLoaded() { ExpoObserve.configure({ dispatchingEnabled: true, sampleRate: 0.9, + integrations: { + 'react-navigation': true, + }, }); export default function Main() { diff --git a/apps/bare-expo/MainNavigator.tsx b/apps/bare-expo/MainNavigator.tsx index b220ac8dac2cd9..6671dcfc38dd55 100644 --- a/apps/bare-expo/MainNavigator.tsx +++ b/apps/bare-expo/MainNavigator.tsx @@ -1,6 +1,6 @@ import AsyncStorage from '@react-native-async-storage/async-storage'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; -import { LinkingOptions, NavigationContainer } from '@react-navigation/native'; +import { LinkingOptions } from '@react-navigation/native'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; import { useTheme } from 'ThemeProvider'; import * as Linking from 'expo-linking'; @@ -10,6 +10,7 @@ import { Platform } from 'react-native'; import { TestStackNavigator } from 'test-suite/TestStackNavigator'; import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { AppMetrics } from 'expo-observe'; +import { ObserveNavigationContainer } from 'expo-observe/integrations/react-navigation'; type NavigationRouteConfigMap = React.ComponentType; @@ -164,7 +165,7 @@ export default function MainNavigator() { } return ( - { @@ -179,7 +180,7 @@ export default function MainNavigator() { - + ); } diff --git a/apps/bare-expo/ios/Podfile.lock b/apps/bare-expo/ios/Podfile.lock index de2cfa99c12052..b06fb4162e2602 100644 --- a/apps/bare-expo/ios/Podfile.lock +++ b/apps/bare-expo/ios/Podfile.lock @@ -384,12 +384,12 @@ PODS: - ExpoModulesCore - ExpoAudio (56.0.9): - ExpoModulesCore - - ExpoBackgroundFetch (56.0.12): + - ExpoBackgroundFetch (56.0.13): - ExpoModulesCore - - ExpoBackgroundTask (56.0.12): + - ExpoBackgroundTask (56.0.13): - ExpoModulesCore - ExpoTaskManager - - ExpoBackgroundTask/Tests (56.0.12): + - ExpoBackgroundTask/Tests (56.0.13): - ExpoModulesCore - ExpoModulesTestCore - ExpoTaskManager @@ -685,16 +685,16 @@ PODS: - ExpoModulesCore - ExpoSystemUI (56.0.5): - ExpoModulesCore - - ExpoTaskManager (56.0.12): + - ExpoTaskManager (56.0.13): - ExpoModulesCore - UMAppLoader - - ExpoTaskManager/Tests (56.0.12): + - ExpoTaskManager/Tests (56.0.13): - ExpoModulesCore - ExpoModulesTestCore - UMAppLoader - ExpoTrackingTransparency (56.0.5): - ExpoModulesCore - - ExpoUI (56.0.11): + - ExpoUI (56.0.12): - ExpoModulesCore - ExpoModulesWorklets - React-RCTFabric @@ -3978,8 +3978,8 @@ SPEC CHECKSUMS: ExpoAppMetrics: dcae0e266d9a801e9b4daa2d7695f24ca2b13b0d ExpoAsset: 873ff4f99d9855e222b832c8acedb6b16e83cb2c ExpoAudio: 80f5e1e70e74ba19c2be2ed7c672bcbc12ca1216 - ExpoBackgroundFetch: 05d655a638fcea0e443c57e8b83993380c22d80d - ExpoBackgroundTask: a026157fe6766c164b5e64fc6f87d49ab9089f95 + ExpoBackgroundFetch: f9d5d47e4729ce771a439f65ce8d00026df272e9 + ExpoBackgroundTask: 5c8f9f7693f645a98aa59bddfee8ccb4ea5d93eb ExpoBattery: a42e918404ceee07a957db4312918ec0c52bc0d6 ExpoBlob: 3e896c97726abf49bdecf63151e09fb4f7e21195 ExpoBlur: caddd80171e5f8f3581ff3d865e99c6465047240 @@ -4037,9 +4037,9 @@ SPEC CHECKSUMS: ExpoStoreReview: f785057aececd9c63a113c69a82b491e5f90694e ExpoSymbols: f83c91f2897d37102b98b9224c603095630be9d0 ExpoSystemUI: 8f4fb641c6a6ebe2a01dda0fbd3fdd952ab5823a - ExpoTaskManager: b0dfa41a1b93e01005c0672a055f7e8373939a38 + ExpoTaskManager: 23971cc0a92b61ce06c4dfa521c10627013da497 ExpoTrackingTransparency: a5117d608c3abd938cd40ebcaa2f00049b886a8c - ExpoUI: 85a30909c38771a26bc1c4ab7510fe07a5666c22 + ExpoUI: 556eeaf2686e78f690c8a6779e85412171f3bb76 ExpoVideo: 8ebbbf65778c5f986d65fc17bb60b79e9d7624e6 ExpoVideoDashSupportModule: a8197584e7b7e533a67e75d3349c5fa827358ad6 ExpoVideoThumbnails: 116c2563d2bd3a1e98326a267020e25fea8af79e diff --git a/apps/expo-go/ios/Podfile.lock b/apps/expo-go/ios/Podfile.lock index 2f327378547d40..b2ad4c3ac6d964 100644 --- a/apps/expo-go/ios/Podfile.lock +++ b/apps/expo-go/ios/Podfile.lock @@ -89,12 +89,12 @@ PODS: - ExpoModulesCore - ExpoAudio (56.0.9): - ExpoModulesCore - - ExpoBackgroundFetch (56.0.12): + - ExpoBackgroundFetch (56.0.13): - ExpoModulesCore - - ExpoBackgroundTask (56.0.12): + - ExpoBackgroundTask (56.0.13): - ExpoModulesCore - ExpoTaskManager - - ExpoBackgroundTask/Tests (56.0.12): + - ExpoBackgroundTask/Tests (56.0.13): - ExpoModulesCore - ExpoModulesTestCore - ExpoTaskManager @@ -331,16 +331,16 @@ PODS: - ExpoModulesCore - ExpoSystemUI (56.0.5): - ExpoModulesCore - - ExpoTaskManager (56.0.12): + - ExpoTaskManager (56.0.13): - ExpoModulesCore - UMAppLoader - - ExpoTaskManager/Tests (56.0.12): + - ExpoTaskManager/Tests (56.0.13): - ExpoModulesCore - ExpoModulesTestCore - UMAppLoader - ExpoTrackingTransparency (56.0.5): - ExpoModulesCore - - ExpoUI (56.0.11): + - ExpoUI (56.0.12): - ExpoModulesCore - ExpoModulesWorklets - React-RCTFabric @@ -4646,8 +4646,8 @@ SPEC CHECKSUMS: Expo: cc00f5cb7006c4f13554ff795d3ef0b8ebbe7307 ExpoAsset: 873ff4f99d9855e222b832c8acedb6b16e83cb2c ExpoAudio: 80f5e1e70e74ba19c2be2ed7c672bcbc12ca1216 - ExpoBackgroundFetch: 05d655a638fcea0e443c57e8b83993380c22d80d - ExpoBackgroundTask: a026157fe6766c164b5e64fc6f87d49ab9089f95 + ExpoBackgroundFetch: f9d5d47e4729ce771a439f65ce8d00026df272e9 + ExpoBackgroundTask: 5c8f9f7693f645a98aa59bddfee8ccb4ea5d93eb ExpoBattery: a42e918404ceee07a957db4312918ec0c52bc0d6 ExpoBlob: 3e896c97726abf49bdecf63151e09fb4f7e21195 ExpoBlur: caddd80171e5f8f3581ff3d865e99c6465047240 @@ -4699,9 +4699,9 @@ SPEC CHECKSUMS: ExpoStoreReview: f785057aececd9c63a113c69a82b491e5f90694e ExpoSymbols: f83c91f2897d37102b98b9224c603095630be9d0 ExpoSystemUI: 8f4fb641c6a6ebe2a01dda0fbd3fdd952ab5823a - ExpoTaskManager: b0dfa41a1b93e01005c0672a055f7e8373939a38 + ExpoTaskManager: 23971cc0a92b61ce06c4dfa521c10627013da497 ExpoTrackingTransparency: a5117d608c3abd938cd40ebcaa2f00049b886a8c - ExpoUI: 85a30909c38771a26bc1c4ab7510fe07a5666c22 + ExpoUI: 556eeaf2686e78f690c8a6779e85412171f3bb76 ExpoVideo: 8ebbbf65778c5f986d65fc17bb60b79e9d7624e6 ExpoVideoThumbnails: 116c2563d2bd3a1e98326a267020e25fea8af79e ExpoWebBrowser: 6e3d90e3fe1952d21a8494872b1e1a485cd50e2f diff --git a/docs/.oxlintrc.json b/docs/.oxlintrc.json index 8cd0cb542cc320..70c21cb6ff113f 100644 --- a/docs/.oxlintrc.json +++ b/docs/.oxlintrc.json @@ -29,7 +29,7 @@ "**/*.{md,mdx}" ], "rules": { - "curly": "warn", + "curly": "error", "eqeqeq": [ "error", "always", @@ -38,94 +38,71 @@ } ], "no-void": [ - "warn", + "error", { "allowAsStatement": true } ], - "constructor-super": "warn", - "no-array-constructor": "warn", - "no-caller": "warn", - "no-case-declarations": "warn", - "no-compare-neg-zero": "warn", - "no-cond-assign": "warn", - "no-const-assign": "warn", - "no-constant-condition": "warn", - "no-debugger": "warn", - "no-delete-var": "warn", - "no-dupe-class-members": "warn", - "no-dupe-keys": "warn", - "no-duplicate-case": "warn", - "no-empty-character-class": "warn", - "no-empty-pattern": "warn", - "no-eval": "warn", - "no-ex-assign": "warn", - "no-extend-native": "warn", - "no-extra-bind": "warn", - "no-extra-boolean-cast": "warn", - "no-fallthrough": "warn", - "no-func-assign": "warn", - "no-global-assign": "warn", - "no-inner-declarations": "warn", - "no-invalid-regexp": "warn", - "no-irregular-whitespace": "warn", - "no-iterator": "warn", - "no-label-var": "warn", - "no-labels": "warn", - "no-lone-blocks": "warn", - "no-multi-assign": "warn", - "no-new": "warn", - "no-new-func": "warn", - "no-object-constructor": "warn", - "no-new-native-nonconstructor": "warn", - "no-obj-calls": "warn", - "no-proto": "warn", - "no-redeclare": "warn", - "no-return-assign": "warn", - "no-script-url": "warn", - "no-self-assign": "warn", - "no-self-compare": "warn", - "no-sequences": "warn", - "no-shadow-restricted-names": "warn", - "no-sparse-arrays": "warn", - "no-this-before-super": "warn", - "no-throw-literal": "warn", - "no-unneeded-ternary": "warn", - "no-unsafe-negation": "warn", - "no-unused-expressions": "warn", - "no-unused-labels": "warn", - "no-unused-vars": "warn", - "no-useless-computed-key": "warn", - "no-useless-concat": "warn", - "no-useless-constructor": "warn", - "no-useless-escape": "warn", - "no-useless-rename": "warn", - "no-useless-return": "warn", - "no-var": "warn", - "no-with": "warn", - "prefer-const": "warn", - "prefer-promise-reject-errors": "warn", - "prefer-rest-params": "warn", - "prefer-spread": "warn", - "radix": "warn", - "unicode-bom": "warn", - "use-isnan": "warn", - "valid-typeof": "warn", - "yoda": "warn", - "unicorn/consistent-date-clone": "warn", - "unicorn/explicit-length-check": "warn", - "unicorn/new-for-builtins": "warn", - "unicorn/no-useless-spread": "warn", - "unicorn/no-unnecessary-array-splice-count": "warn", - "unicorn/prefer-array-some": "warn", - "unicorn/prefer-at": "warn", - "unicorn/prefer-date-now": "warn", - "unicorn/prefer-set-has": "warn", - "unicorn/prefer-includes": "warn", - "unicorn/prefer-regexp-test": "warn", - "unicorn/prefer-node-protocol": "warn", - "unicorn/prefer-string-slice": "warn", - "unicorn/throw-new-error": "warn", + "constructor-super": "error", + "no-array-constructor": "error", + "no-caller": "error", + "no-case-declarations": "error", + "no-compare-neg-zero": "error", + "no-cond-assign": "error", + "no-const-assign": "error", + "no-constant-condition": "error", + "no-debugger": "error", + "no-delete-var": "error", + "no-dupe-class-members": "error", + "no-dupe-keys": "error", + "no-duplicate-case": "error", + "no-empty-character-class": "error", + "no-empty-pattern": "error", + "no-eval": "error", + "no-ex-assign": "error", + "no-extend-native": "error", + "no-extra-boolean-cast": "error", + "no-fallthrough": "error", + "no-func-assign": "error", + "no-global-assign": "error", + "no-inner-declarations": "error", + "no-invalid-regexp": "error", + "no-irregular-whitespace": "error", + "no-new": "error", + "no-new-func": "error", + "no-new-native-nonconstructor": "error", + "no-obj-calls": "error", + "no-redeclare": "error", + "no-return-assign": "error", + "no-script-url": "error", + "no-self-assign": "error", + "no-self-compare": "error", + "no-shadow-restricted-names": "error", + "no-sparse-arrays": "error", + "no-this-before-super": "error", + "no-throw-literal": "error", + "no-unsafe-negation": "error", + "no-unused-expressions": "error", + "no-unused-labels": "error", + "no-unused-vars": "error", + "no-useless-escape": "error", + "no-useless-rename": "error", + "no-var": "error", + "no-with": "error", + "prefer-const": "error", + "prefer-promise-reject-errors": "error", + "radix": "error", + "use-isnan": "error", + "valid-typeof": "error", + "unicorn/new-for-builtins": "error", + "unicorn/no-useless-spread": "error", + "unicorn/prefer-array-some": "error", + "unicorn/prefer-at": "error", + "unicorn/prefer-date-now": "error", + "unicorn/prefer-includes": "error", + "unicorn/prefer-regexp-test": "error", + "unicorn/prefer-node-protocol": "error", + "unicorn/throw-new-error": "error", "react/jsx-key": [ "error", { @@ -142,30 +119,22 @@ ], "react/jsx-no-duplicate-props": "error", "react/jsx-no-undef": "error", - "react/no-direct-mutation-state": "warn", - "react/jsx-boolean-value": "warn", - "react/jsx-curly-brace-presence": "warn", - "react/jsx-fragments": "warn", - "react/no-did-mount-set-state": "warn", - "react/no-redundant-should-component-update": "warn", - "react/no-will-update-set-state": "warn", - "react/self-closing-comp": "warn", + "react/no-direct-mutation-state": "error", "react-hooks/rules-of-hooks": "error", - "@next/next/google-font-display": "warn", - "@next/next/google-font-preconnect": "warn", - "@next/next/next-script-for-ga": "warn", - "@next/next/no-async-client-component": "warn", - "@next/next/no-before-interactive-script-outside-document": "warn", - "@next/next/no-css-tags": "warn", - "@next/next/no-head-element": "warn", + "@next/next/google-font-display": "error", + "@next/next/google-font-preconnect": "error", + "@next/next/no-async-client-component": "error", + "@next/next/no-before-interactive-script-outside-document": "error", + "@next/next/no-css-tags": "error", + "@next/next/no-head-element": "error", "@next/next/no-html-link-for-pages": "error", "@next/next/no-img-element": "off", - "@next/next/no-page-custom-font": "warn", - "@next/next/no-styled-jsx-in-document": "warn", + "@next/next/no-page-custom-font": "error", + "@next/next/no-styled-jsx-in-document": "error", "@next/next/no-sync-scripts": "error", - "@next/next/no-title-in-document-head": "warn", - "@next/next/no-typos": "warn", - "@next/next/no-unwanted-polyfillio": "warn", + "@next/next/no-title-in-document-head": "error", + "@next/next/no-typos": "error", + "@next/next/no-unwanted-polyfillio": "error", "@next/next/inline-script-id": "error", "@next/next/no-assign-module-variable": "error", "@next/next/no-document-import-in-page": "error", @@ -180,34 +149,24 @@ "allowComputed": true } ], - "import/first": "warn", "import/no-cycle": "error", - "import/no-named-as-default": "warn", - "import/no-named-as-default-member": "warn", - "node/handle-callback-err": "warn", - "node/no-new-require": "warn", - "node/no-path-concat": "warn", - "oxc/bad-array-method-on-arguments": "warn", - "oxc/bad-char-at-comparison": "warn", - "oxc/bad-comparison-sequence": "warn", - "oxc/bad-min-max-func": "warn", - "oxc/bad-object-literal-comparison": "warn", - "oxc/bad-replace-all-arg": "warn", - "oxc/const-comparisons": "warn", - "oxc/double-comparisons": "warn", - "oxc/erasing-op": "warn", - "oxc/missing-throw": "warn", - "oxc/number-arg-out-of-range": "warn", - "oxc/only-used-in-recursion": "warn", - "oxc/uninvoked-array-callback": "warn", - "@typescript-eslint/array-type": [ - "warn", - { - "default": "array" - } - ], + "node/no-new-require": "error", + "node/no-path-concat": "error", + "oxc/bad-array-method-on-arguments": "error", + "oxc/bad-char-at-comparison": "error", + "oxc/bad-comparison-sequence": "error", + "oxc/bad-min-max-func": "error", + "oxc/bad-object-literal-comparison": "error", + "oxc/bad-replace-all-arg": "error", + "oxc/const-comparisons": "error", + "oxc/double-comparisons": "error", + "oxc/erasing-op": "error", + "oxc/missing-throw": "error", + "oxc/number-arg-out-of-range": "error", + "oxc/only-used-in-recursion": "error", + "oxc/uninvoked-array-callback": "error", "@typescript-eslint/ban-ts-comment": [ - "warn", + "error", { "minimumDescriptionLength": 3, "ts-check": false, @@ -216,24 +175,17 @@ "ts-nocheck": true } ], - "@typescript-eslint/consistent-type-assertions": [ - "warn", - { - "assertionStyle": "as", - "objectLiteralTypeAssertions": "allow" - } - ], - "@typescript-eslint/no-confusing-non-null-assertion": "warn", + "@typescript-eslint/no-confusing-non-null-assertion": "error", "@typescript-eslint/no-empty-object-type": [ - "warn", + "error", { "allowInterfaces": "with-single-extends" } ], - "@typescript-eslint/no-extra-non-null-assertion": "warn", - "@typescript-eslint/no-restricted-types": "warn", - "@typescript-eslint/no-wrapper-object-types": "warn", - "@typescript-eslint/prefer-as-const": "warn", + "@typescript-eslint/no-extra-non-null-assertion": "error", + "@typescript-eslint/no-restricted-types": "error", + "@typescript-eslint/no-wrapper-object-types": "error", + "@typescript-eslint/prefer-as-const": "error", "@typescript-eslint/await-thenable": "error", "@typescript-eslint/no-floating-promises": "error", "@typescript-eslint/no-misused-promises": [ @@ -243,19 +195,19 @@ } ], "@typescript-eslint/return-await": ["error", "always"], - "@typescript-eslint/no-unnecessary-type-assertion": "warn", - "@typescript-eslint/prefer-includes": "warn", + "@typescript-eslint/no-unnecessary-type-assertion": "error", + "@typescript-eslint/prefer-includes": "error", "@typescript-eslint/prefer-nullish-coalescing": [ - "warn", + "error", { "ignoreConditionalTests": true, "ignoreMixedLogicalExpressions": true } ], - "@typescript-eslint/no-dupe-class-members": "warn", - "@typescript-eslint/no-unused-expressions": "warn", + "@typescript-eslint/no-dupe-class-members": "error", + "@typescript-eslint/no-unused-expressions": "error", "@typescript-eslint/no-unused-vars": [ - "warn", + "error", { "vars": "all", "args": "none", @@ -263,11 +215,11 @@ "caughtErrors": "all" } ], - "@typescript-eslint/no-useless-constructor": "warn", - "@typescript-eslint/no-confusing-void-expression": "warn", - "@typescript-eslint/no-for-in-array": "warn", - "@typescript-eslint/only-throw-error": "warn", - "@typescript-eslint/no-redeclare": "warn", + "@typescript-eslint/no-useless-constructor": "error", + "@typescript-eslint/no-confusing-void-expression": "error", + "@typescript-eslint/no-for-in-array": "error", + "@typescript-eslint/only-throw-error": "error", + "@typescript-eslint/no-redeclare": "error", "testing-library/await-async-events": [ "error", { @@ -284,7 +236,6 @@ ], "testing-library/no-await-sync-queries": "error", "testing-library/no-container": "error", - "testing-library/no-debugging-utils": "warn", "testing-library/no-dom-import": ["error", "react"], "testing-library/no-global-regexp-flag-in-query": "error", "testing-library/no-manual-cleanup": "error", @@ -301,7 +252,7 @@ "testing-library/prefer-screen-queries": "error", "testing-library/render-result-naming-convention": "error", "tailwindcss/no-unknown-classes": [ - "warn", + "error", { "allowlist": [ "dark-theme", @@ -313,18 +264,18 @@ "ignorePrefixes": ["diff-", "dialog-", "max-medium:", "[table_&]"] } ], - "tailwindcss/no-duplicate-classes": "warn", + "tailwindcss/no-duplicate-classes": "error", "tailwindcss/no-conflicting-classes": "allow", - "tailwindcss/no-deprecated-classes": "warn", - "tailwindcss/no-unnecessary-whitespace": "warn", + "tailwindcss/no-deprecated-classes": "error", + "tailwindcss/no-unnecessary-whitespace": "error", "tailwindcss/enforce-sort-order": [ - "warn", + "error", { "mode": "strict" } ], - "tailwindcss/enforce-shorthand": "warn", - "tailwindcss/enforce-canonical": "warn" + "tailwindcss/enforce-shorthand": "error", + "tailwindcss/enforce-canonical": "error" }, "settings": { "tailwindcss": { diff --git a/docs/common/client-redirects.ts b/docs/common/client-redirects.ts index 418ddb85ecb3a9..c079947f8276d1 100644 --- a/docs/common/client-redirects.ts +++ b/docs/common/client-redirects.ts @@ -546,12 +546,8 @@ const RENAMED_PAGES: Record = { '/config-plugins/plugins-and-mods/': '/config-plugins/plugins/', // After merging registerRootComponent info in `expo` API reference - '/versions/v53.0.0/sdk/register-root-component/': - '/versions/v53.0.0/sdk/expo/#registerrootcomponentcomponent', '/versions/latest/sdk/register-root-component/': '/versions/latest/sdk/expo/#registerrootcomponentcomponent', - '/versions/v53.0.0/sdk/url/': '/versions/v53.0.0/sdk/expo/#url-api', - '/versions/v53.0.0/sdk/encoding/': '/versions/v53.0.0/sdk/expo/#encoding-api', // Temporary redirects '/router/advanced/singular/': '/preview/singular/', diff --git a/docs/components/plugins/__snapshots__/APISection.test.tsx.snap b/docs/components/plugins/__snapshots__/APISection.test.tsx.snap index 1131cad5f22b58..d9ced3fc15f8a9 100644 --- a/docs/components/plugins/__snapshots__/APISection.test.tsx.snap +++ b/docs/components/plugins/__snapshots__/APISection.test.tsx.snap @@ -5672,7 +5672,7 @@ OAuth 2.0 protocol
= { }; export const sdkVersionHardcodedTypeLinks: Record> = { - 'v53.0.0': { - CameraPosition: '/versions/v53.0.0/sdk/maps/#cameraposition-2', - EventEmitter: '/versions/v53.0.0/sdk/expo/#eventemitter', - NativeModule: '/versions/v53.0.0/sdk/expo/#nativemodule', - SharedObject: '/versions/v53.0.0/sdk/expo/#sharedobject', - SharedRef: '/versions/v53.0.0/sdk/expo/#sharedref', - }, 'v54.0.0': { BufferOptions: '/versions/v54.0.0/sdk/video/#bufferoptions-1', CameraPosition: '/versions/v54.0.0/sdk/maps/#cameraposition-2', @@ -354,6 +347,36 @@ export const sdkVersionHardcodedTypeLinks: Record + className={mergeClasses('mb-3 flex flex-row items-start in-[table]:mb-2.5', className)}> {experimentalData.length > 0 && (
diff --git a/docs/components/plugins/api/components/__snapshots__/APICommentTextBlock.test.tsx.snap b/docs/components/plugins/api/components/__snapshots__/APICommentTextBlock.test.tsx.snap index 4148d7a8b6f6b3..49c87f182b67f6 100644 --- a/docs/components/plugins/api/components/__snapshots__/APICommentTextBlock.test.tsx.snap +++ b/docs/components/plugins/api/components/__snapshots__/APICommentTextBlock.test.tsx.snap @@ -21,7 +21,7 @@ exports[`APICommentTextBlock comment with example 1`] = ` class="px-4 [table_&]:mb-0! [table_&]:px-0" >
+ This command creates a new directory named **my-project** that contains your new Expo project. While you can name the project anything, this guide uses **my-project** for consistency. The new project includes an example TypeScript application to help you get started. diff --git a/docs/pages/brownfield/isolated-approach.mdx b/docs/pages/brownfield/isolated-approach.mdx index 1c48356bfdd8c6..2490046a786330 100644 --- a/docs/pages/brownfield/isolated-approach.mdx +++ b/docs/pages/brownfield/isolated-approach.mdx @@ -39,7 +39,7 @@ Learn more from the [Set up environment guide](/get-started/set-up-your-environm Run the following command to create a new directory named **my-project** that contains your new Expo project. While you can name the project anything, this guide uses **my-project** for consistency. - + The **my-project** does not need to live inside your existing native app and can be created in a separate repository or a monorepo. The new project includes an example TypeScript application to help you get started. diff --git a/docs/pages/build/setup.mdx b/docs/pages/build/setup.mdx index 13709df5fc6286..768baf839e09d9 100644 --- a/docs/pages/build/setup.mdx +++ b/docs/pages/build/setup.mdx @@ -22,7 +22,7 @@ For a small app, builds for Android and iOS platforms trigger within a few minut Don't have a project yet? It's quick and easy to create a "Hello world" app you can use with this guide: - + EAS Build also works well with projects created by `npx create-react-native-app`, `npx react-native`, `ignite-cli`, and other project bootstrapping tools. diff --git a/docs/pages/develop/app-navigation.mdx b/docs/pages/develop/app-navigation.mdx index 6d33cd373a42c5..5fa685cfb2d5ce 100644 --- a/docs/pages/develop/app-navigation.mdx +++ b/docs/pages/develop/app-navigation.mdx @@ -31,7 +31,7 @@ The library offers platform-specific look-and-feel with smooth animations and ge Expo Router is a file-based routing library for Expo and React Native projects. By following the **app** directory convention, it turns files into routes and is integrated with Expo for [Expo CLI](/more/expo-cli/) and bundling without additional setup. The library also adds features such as typed routes, dynamic routes, lazy bundling in development, static rendering for the web, and automatic deep linking. -New Expo projects created with `npx create-expo-app@latest --template default@sdk-55` include Expo Router by default. +New Expo projects created with `npx create-expo-app@latest --template default@sdk-56` include Expo Router by default. Don't have a project yet? It's quick and easy to create a "Hello world" app you can use with this guide. Run the following command to create a new project: - + EAS Update also works well with projects created by `npx create-react-native-app`, `npx react-native`, `ignite-cli`, and other project bootstrapping tools. diff --git a/docs/pages/eas/ai/mcp.mdx b/docs/pages/eas/ai/mcp.mdx index ecc3b7428b7699..c39f99a2891d8f 100644 --- a/docs/pages/eas/ai/mcp.mdx +++ b/docs/pages/eas/ai/mcp.mdx @@ -66,7 +66,7 @@ The complete table of [MCP capabilities](#available-mcp-capabilities) documents An [EAS paid plan](https://expo.dev/pricing) is required to use Expo MCP Server. - Create a project with `npx create-expo-app@latest --template default@sdk-55`, or ensure your + Create a project with `npx create-expo-app@latest --template default@sdk-56`, or ensure your existing project has the latest `expo` package installed. diff --git a/docs/pages/eas/hosting/get-started.mdx b/docs/pages/eas/hosting/get-started.mdx index ef2293e02a6e19..7d1376f25380de 100644 --- a/docs/pages/eas/hosting/get-started.mdx +++ b/docs/pages/eas/hosting/get-started.mdx @@ -33,7 +33,7 @@ This guide will walk you through the process of creating your first web deployme Don't have a project yet? It's quick and easy to create a "Hello world" app you can use with this guide. Run the following command to create a new project: - + diff --git a/docs/pages/eas/index.mdx b/docs/pages/eas/index.mdx index 6763b9576048fe..24c402dd99155c 100644 --- a/docs/pages/eas/index.mdx +++ b/docs/pages/eas/index.mdx @@ -70,7 +70,7 @@ Read the full pitch at [expo.dev/eas](https://expo.dev/eas), or follow the links /> **warning** Enable this only when testing your Expo Observe integration. Development/debug performance differs significantly from production, so collecting development/debug metrics may distort the results shown in your dashboard. +> **warning** Enable this only when testing your EAS Observe integration. Development/debug performance differs significantly from production, so collecting development/debug metrics may distort the results shown in your dashboard. ## Custom endpoint diff --git a/docs/pages/eas/observe/dashboard.mdx b/docs/pages/eas/observe/dashboard.mdx index eb135c79b9dd3e..a8423d40714719 100644 --- a/docs/pages/eas/observe/dashboard.mdx +++ b/docs/pages/eas/observe/dashboard.mdx @@ -1,15 +1,15 @@ --- -title: Expo Observe dashboard +title: EAS Observe dashboard sidebar_title: Dashboard -description: View performance metrics, filter by platform or version, and investigate individual sessions in the Expo Observe dashboard. +description: View performance metrics, filter by platform or version, and investigate individual sessions in the EAS Observe dashboard. --- import { ContentSpotlight } from '~/ui/components/ContentSpotlight'; -The Observe dashboard provides a visual overview of your app's performance metrics. Open your project and in EAS dashboard, select [**Observe**](https://expo.dev/accounts/[account]/projects/[project]/observe) from the navigation menu. +The EAS Observe dashboard provides a visual overview of your app's performance metrics. Open your project and in EAS dashboard, select [**Observe**](https://expo.dev/accounts/[account]/projects/[project]/observe) from the navigation menu. diff --git a/docs/pages/eas/observe/get-started.mdx b/docs/pages/eas/observe/get-started.mdx index f758342e7f1246..e0bb5e14e22987 100644 --- a/docs/pages/eas/observe/get-started.mdx +++ b/docs/pages/eas/observe/get-started.mdx @@ -1,7 +1,7 @@ --- -title: Set up Expo Observe +title: Set up EAS Observe sidebar_title: Get started -description: Learn how to install Expo Observe and start collecting performance metrics from your production app. +description: Learn how to install EAS Observe and start collecting performance metrics from your production app. searchRank: 9 --- @@ -10,21 +10,21 @@ import { Tabs, Tab } from '~/ui/components/Tabs'; import { Terminal } from '~/ui/components/Snippet'; import { Step } from '~/ui/components/Step'; -Expo Observe tracks your app's startup performance in production. This guide walks you through installing the library, setting up your app, and viewing your first metrics. +EAS Observe tracks your app's startup performance in production. This guide walks you through installing the library, setting up your app, and viewing your first metrics. ## Prerequisites - - Expo Observe is in Private Preview and access is granted on request. [Request access + + EAS Observe is in Private Preview and access is granted on request. [Request access here](https://expo.dev/changelog/introducing-expo-observe). - Expo Observe is available to anyone with an Expo account. You can sign up at + EAS Observe is available to anyone with an Expo account. You can sign up at [expo.dev/signup](https://expo.dev/signup). - Expo Observe requires SDK 55 or later. Run `npx expo-doctor` to check your SDK version and `npx + EAS Observe requires SDK 55 or later. Run `npx expo-doctor` to check your SDK version and `npx expo install --fix` to update dependencies. diff --git a/docs/pages/eas/observe/index.mdx b/docs/pages/eas/observe/index.mdx index 6147beef9b06df..11b73e8c9f82cc 100644 --- a/docs/pages/eas/observe/index.mdx +++ b/docs/pages/eas/observe/index.mdx @@ -1,5 +1,5 @@ --- -title: Expo Observe +title: EAS Observe --- import Redirect from '~/components/plugins/Redirect'; diff --git a/docs/pages/eas/observe/integrations/expo-router.mdx b/docs/pages/eas/observe/integrations/expo-router.mdx new file mode 100644 index 00000000000000..103c9b24bb3623 --- /dev/null +++ b/docs/pages/eas/observe/integrations/expo-router.mdx @@ -0,0 +1,121 @@ +--- +title: Expo Router integration +sidebar_title: Expo Router +description: Track per-route render and interactive timings by enabling the Expo Router integration for EAS Observe. +--- + +import { Prerequisites, Requirement } from '~/ui/components/Prerequisites'; +import { Step } from '~/ui/components/Step'; + +EAS Observe ships an opt-in integration for [Expo Router](/router/introduction/) that collects per-route metrics tagged with the route pattern (for example, `/(tabs)/sessions/[sessionId]`). This lets you compare navigation performance by route in the dashboard instead of looking only at app-wide aggregates. + +## Prerequisites + + + + The Expo Router integration is available on SDK 56 and later. On earlier SDKs, `expo-observe` + still tracks app-wide metrics, but per-route navigation events are not emitted. + + + Follow [Get started](/eas/observe/get-started/) to install `expo-observe` and create your first + build. + + + The integration depends on `expo-router` at runtime. If the package is not installed, the + integration becomes a silent no-op. + + + + + +## Enable the integration + +> **warning** The integration must be enabled before mount and cannot be toggled at runtime. Calling `configure()` after the app has mounted, or toggling the flag mid-session, throws an error. + +Call `ExpoObserve.configure()` with the `expo-router` integration flag at module scope, before any screen mounts: + +```tsx src/app/_layout.tsx +import ExpoObserve from 'expo-observe'; + +ExpoObserve.configure({ + integrations: { 'expo-router': true }, +}); +``` + + + + + +## Call `useObserve()` in your screens + +Use the `useObserve()` hook to get a `markInteractive` that is automatically scoped to the current route. The emitted event is tagged with the screen's route pattern. + +```tsx src/app/(tabs)/index.tsx +import { useObserve } from 'expo-observe'; +import { useEffect } from 'react'; + +export default function Home() { + const { markInteractive } = useObserve(); + + useEffect(() => { + markInteractive(); + }, [markInteractive]); + + return (/* your screen content */); +} +``` + +> **info** If the integration is disabled or `expo-router` is not installed, `useObserve()` falls back to the global `AppMetrics.markInteractive`. You can leave the hook in place regardless of integration state. + + + +## Metrics + +### Per-route first render (`cold_ttr`) + +**What it measures:** Time from when a navigation action is dispatched (for example, a link click) to when the destination screen first becomes focused. For the very first focus after app launch, the measurement is taken from when the JS bundle is loaded, and the event includes `isAppLaunch: true`. + +Emitted at most once per screen instance within a session. + +**Event params:** + +| Param | Type | Description | +| ------------- | --------- | ------------------------------------------------------------------------------ | +| `routeName` | `string` | Route pattern, for example `/(tabs)/sessions/[sessionId]`. | +| `url` | `string` | Resolved pathname for the navigation. | +| `routeParams` | `object` | Resolved route params (for example, `{ sessionId: 'abc' }`). | +| `isAppLaunch` | `boolean` | `true` when measured against process start, `false` for subsequent navigation. | + +### Per-route warm render (`warm_ttr`) + +**What it measures:** Same as `cold_ttr`, but for screens that were already rendered before focus, typically because they were preloaded via [``](/router/basics/navigation/#prefetching) or the user navigated back to them. + +**Event params:** + +| Param | Type | Description | +| ------------- | -------- | ------------------------------------------------------------ | +| `routeName` | `string` | Route pattern, for example `/(tabs)/sessions/[sessionId]`. | +| `url` | `string` | Resolved pathname for the navigation. | +| `routeParams` | `object` | Resolved route params (for example, `{ sessionId: 'abc' }`). | + +### Per-route time to interactive (`tti`) + +**What it measures:** Time from when a navigation action is dispatched to when `markInteractive()` is called on the destination screen. Only the first call per navigation is recorded, so it is safe to call `markInteractive()` multiple times. + +**Event params:** + +| Param | Type | Description | +| ------------- | -------- | -------------------------------------------------------------------- | +| `routeName` | `string` | Route pattern, for example `/(tabs)/sessions/[sessionId]`. | +| `url` | `string` | Resolved pathname. | +| `routeParams` | `object` | Resolved route params. | +| `...` | `any` | Any custom params passed via `markInteractive({ params: { ... } })`. | + +## Notes and troubleshooting + +- `routeName` is a pattern (`/(tabs)/sessions/[sessionId]`), not a resolved URL (`/sessions/abc`). This keeps metrics stable across distinct param values so the dashboard buckets them together. Resolved values are still available on the event via `url` and `routeParams`. +- Calls to `router.prefetch()` do not count as a user navigation and never seed a `cold_ttr` or `warm_ttr` measurement. The next user-driven navigation to that route emits `warm_ttr` because the screen has already rendered. +- The integration only activates if `expo-router` is installed at runtime. If it is not installed, `useObserve()` and `ObserveRoot` continue to work but no per-route navigation metrics are emitted. +- The integration must be enabled before mount via `ExpoObserve.configure({ integrations: { 'expo-router': true } })`. Toggling it after the app has mounted throws. +- If `markInteractive()` logs `Calling markInteractive on unmounted screen` or `No metadata available for the current screen`, the call ran outside a screen component or after unmount. Move the call into a `useEffect` inside the screen component. +- For general issues with EAS Observe, see [Troubleshooting](/eas/observe/reference/troubleshooting/). diff --git a/docs/pages/eas/observe/introduction.mdx b/docs/pages/eas/observe/introduction.mdx index eedc10812b2211..31d5928035d9f8 100644 --- a/docs/pages/eas/observe/introduction.mdx +++ b/docs/pages/eas/observe/introduction.mdx @@ -1,7 +1,7 @@ --- -title: Introduction to Expo Observe +title: Introduction to EAS Observe sidebar_title: Introduction -description: Expo Observe is a performance monitoring service that tracks how your app performs in production across real devices and conditions. +description: EAS Observe is a performance monitoring service that tracks how your app performs in production across real devices and conditions. searchRank: 10 --- @@ -13,11 +13,11 @@ import { NoIcon, YesIcon } from '~/ui/components/DocIcons'; import { FAQ } from '~/ui/components/FAQ'; import { Terminal } from '~/ui/components/Snippet'; -> **important** **Expo Observe** is in [Private Preview](/more/release-statuses/#preview) and subject to breaking changes. Access is granted on request ([request here](https://expo.dev/changelog/introducing-expo-observe)). While in preview, it is free to use. +> **important** **EAS Observe** is in [Private Preview](/more/release-statuses/#preview) and subject to breaking changes. Access is granted on request ([request here](https://expo.dev/changelog/introducing-expo-observe)). While in preview, it is free to use. -**Expo Observe** is a performance monitoring service from Expo for tracking how your app performs in production. It gives you visibility into real-world startup times, rendering performance, and user experience across different devices, networks, and conditions. +**EAS Observe** is a performance monitoring service from Expo for tracking how your app performs in production. It gives you visibility into real-world startup times, rendering performance, and user experience across different devices, networks, and conditions. -Debugging performance in React Native has traditionally been limited to development tools. Expo Observe focuses on production, where performance characteristics differ significantly from what you see during development. +Debugging performance in React Native has traditionally been limited to development tools. EAS Observe focuses on production, where performance characteristics differ significantly from what you see during development. ## Quick start @@ -25,16 +25,16 @@ Debugging performance in React Native has traditionally been limited to developm Wrap your root layout with the `AppMetricsRoot` component (SDK 55) or the `ObserveRoot` component (SDK 56 and later) and call `markInteractive()` when your app is ready for user input. See [Get started](/eas/observe/get-started/) for the full setup guide. -## Why Expo Observe +## Why EAS Observe -Traditional development-time profiling tools show how your app performs on your machine. Expo Observe shows how it performs for real users: +Traditional development-time profiling tools show how your app performs on your machine. EAS Observe shows how it performs for real users: - **Production performance data**: Track startup times, render performance, and bundle load times from real user sessions across a range of devices - **Release comparison**: See how metrics change between app versions and OTA updates to catch regressions early - **Session investigation**: Drill into individual user sessions to understand why certain devices or conditions lead to slower performance - **CLI and dashboard access**: Query metrics from the terminal with `eas observe:` commands or view them in the EAS dashboard -## When to use Expo Observe +## When to use EAS Observe | Scenario | Recommendation | | --------------------------------------------------- | -------------- | @@ -48,27 +48,27 @@ Traditional development-time profiling tools show how your app performs on your **Development-time profiling and debugging**: Use [React Native DevTools](/debugging/tools/#debugging-with-react-native-devtools) for debugging and [Expo Atlas](/guides/analyzing-bundles/) for bundle inspection. -**Crash reporting and error tracking**: This is a planned addition for Observe in the future. In the interim we suggest a crash reporting service such as [Sentry](/guides/using-sentry/) or [BugSnag](/guides/using-bugsnag/). +**Crash reporting and error tracking**: This is a planned addition for EAS Observe in the future. In the interim we suggest a crash reporting service such as [Sentry](/guides/using-sentry/) or [BugSnag](/guides/using-bugsnag/). -**Custom analytics and event tracking**: This is a planned addition for Observe in the future. In the interim, choose an analytics provider from the [React Native analytics guide](/guides/using-analytics/), for example PostHog, Amplitude, or Firebase Analytics. +**Custom analytics and event tracking**: This is a planned addition for EAS Observe in the future. In the interim, choose an analytics provider from the [React Native analytics guide](/guides/using-analytics/), for example PostHog, Amplitude, or Firebase Analytics. ## Frequently asked questions (FAQ) - + -Expo Observe focuses on startup metrics: cold launch time, warm launch time, time to first render, time to interactive, and bundle load time. See the [Metrics reference](/eas/observe/reference/metrics/) for detailed descriptions of each metric. +EAS Observe focuses on startup metrics: cold launch time, warm launch time, time to first render, time to interactive, and bundle load time. See the [Metrics reference](/eas/observe/reference/metrics/) for detailed descriptions of each metric. -Expo Observe supports Android and iOS. Metrics are collected from production builds and can be filtered by platform in both the dashboard and CLI. +EAS Observe supports Android and iOS. Metrics are collected from production builds and can be filtered by platform in both the dashboard and CLI. - + No. Users are identified by an anonymous ID that is unique per app installation. This ID is not personally identifiable and is reset if the user uninstalls and reinstalls the app. See [Metrics reference: User](/eas/observe/reference/metrics/#user) for more details. @@ -97,14 +97,14 @@ Metric data is retained for a minimum of 60 days. ## Get started You'll need to create a project with the following command: - + diff --git a/docs/pages/eas/workflows/pre-packaged-jobs.mdx b/docs/pages/eas/workflows/pre-packaged-jobs.mdx index 0f46b3af22dce8..799d9eb67b4d8f 100644 --- a/docs/pages/eas/workflows/pre-packaged-jobs.mdx +++ b/docs/pages/eas/workflows/pre-packaged-jobs.mdx @@ -521,6 +521,9 @@ jobs: params: build_id: string # required profile: string # optional - default: production + hooks: + before_submit: step[] # optional - steps to run before the submission starts. + after_submit: step[] # optional - steps to run after the submission completes. ``` #### Parameters @@ -542,6 +545,15 @@ You can reference the following outputs in subsequent jobs: | ios_bundle_identifier | string | The iOS bundle identifier of the submitted build. | | android_package_id | string | The Android package ID of the submitted build. | +#### Hooks + +The following hooks are supported for the Submit job: + +- `before_submit`: steps to run before the submission starts. +- `after_submit`: steps to run after the submission completes. + +See [`jobs..hooks`](/eas/workflows/syntax/#jobsjob_idhooks) for the general hooks syntax. + ### Examples Here are some practical examples of using the submit job: @@ -839,7 +851,7 @@ jobs: ## Maestro -Run Maestro tests on a Android emulator or iOS Simulator build. +Run Maestro tests on an Android Emulator or iOS Simulator build. > **important** Maestro tests are in [alpha](/more/release-statuses/#alpha). @@ -862,8 +874,11 @@ jobs: exclude_tags: string | string[] # optional maestro_version: string # optional - defaults to latest android_system_image_package: string # optional - device_identifier: string | { android: string, ios: string } # optional + device_identifier: string | { android?: string, ios?: string } # optional output_format: string # optional - defaults to junit + hooks: + before_maestro_tests: step[] # optional - steps to run before the tests start. + after_maestro_tests: step[] # optional - steps to run after the tests complete. ``` #### Parameters @@ -886,6 +901,15 @@ You can pass the following parameters into the `params` list: | device_identifier | string or `{ android?: string, ios?: string }` object | Optional. Device identifier to use for the tests. You can also use a single-value expression like `pixel_6`, `iPhone 16 Plus` or `${{ needs.build.outputs.platform == "android" ? "pixel_6" : "iPhone 16 Plus" }}` and an object like `device_identifier: { android: "pixel_6", ios: "iPhone 16 Plus" }`. Note that iOS devices availability differs across runner images. A list of available devices can be found in the jobs logs. | | skip_build_check | boolean | Optional. Skip validation of the build (whether an iOS build is a simulator build). Defaults to false. | +#### Hooks + +The following hooks are supported for the Maestro job: + +- `before_maestro_tests`: steps to run before the tests start. +- `after_maestro_tests`: steps to run after the tests complete. + +See [`jobs..hooks`](/eas/workflows/syntax/#jobsjob_idhooks) for the general hooks syntax. + ### Examples Here are some practical examples of using the Maestro job: @@ -911,7 +935,7 @@ jobs: -This workflow runs Maestro tests on an Android emulator build with 3 shards and 2 retries for failed tests. +This workflow runs Maestro tests on an Android Emulator build with 3 shards and 2 retries for failed tests. ```yaml .eas/workflows/maestro-sharded.yml name: Sharded Maestro Test @@ -950,9 +974,32 @@ jobs: + + +This workflow uses a hook to generate the `maestro_tests` directory right before Maestro starts running tests. + +```yaml .eas/workflows/maestro-hooks.yml +name: Maestro Hooks + +jobs: + test: + name: Run Maestro Tests + type: maestro + environment: preview + params: + build_id: ${{ needs.build_ios_simulator.outputs.build_id }} + flow_path: ./maestro_tests + hooks: + before_maestro_tests: + - name: Generate Maestro flows + run: npx tsx scripts/generate-maestro-tests.ts +``` + + + -This workflow runs Maestro tests on an Android emulator build with a specific device and records the screen. +This workflow runs Maestro tests on an Android Emulator build with a specific device and records the screen. ```yaml .eas/workflows/maestro-sharded.yml name: Pixel E2E Test @@ -992,6 +1039,32 @@ The assets will be available within the "Maestro Test Results" artifact in the A + + +This workflow saves screenshots and recordings to `MAESTRO_TESTS_DIR`, then runs a script after the tests finish to upload those files or send a summary to Slack. + +```yaml .eas/workflows/maestro-report-artifacts.yml +name: Maestro Artifact Reporting + +jobs: + test: + name: Run Maestro Tests + type: maestro + environment: preview + env: + SLACK_WEBHOOK_URL: ${{ env.SLACK_WEBHOOK_URL }} + params: + build_id: ${{ needs.build_ios_simulator.outputs.build_id }} + flow_path: ./maestro/flows + record_screen: true + hooks: + after_maestro_tests: + - name: Report Maestro artifacts + run: npx tsx scripts/report-maestro-artifacts.ts "$MAESTRO_TESTS_DIR" +``` + + + ## Maestro Cloud Run Maestro tests on Maestro Cloud. @@ -1021,6 +1094,9 @@ jobs: name: string # optional - name for the Maestro Cloud upload. Corresponds to `--name` param to `maestro cloud`. branch: string # optional - override for the branch the Maestro Cloud upload originated from. By default, if the workflow run has been triggered from GitHub, the branch of the workflow run will be used. Corresponds to `--branch` param to `maestro cloud`. async: boolean # optional - run the Maestro Cloud tests asynchronously. If true, the status of the job will only denote whether the upload was successful, _not_ whether the tests succeeded. Corresponds to `--async` param to `maestro cloud`. + hooks: + before_maestro_cloud: step[] # optional - steps to run before the Maestro Cloud upload. + after_maestro_cloud: step[] # optional - steps to run after the Maestro Cloud upload. ``` #### Parameters @@ -1046,6 +1122,15 @@ You can pass the following parameters into the `params` list: > **important** You need to either set `maestro_api_key` parameter or `MAESTRO_CLOUD_API_KEY` environment variable in the job environment. Go to "Settings" on [Maestro Cloud](https://app.maestro.dev/) to generate an API key and then to [Environment variables](https://expo.dev/accounts/[account]/projects/[project]/environment-variables) to add it to your project. +#### Hooks + +The following hooks are supported for the Maestro Cloud job: + +- `before_maestro_cloud`: steps to run before the Maestro Cloud upload. +- `after_maestro_cloud`: steps to run after the Maestro Cloud upload. + +See [`jobs..hooks`](/eas/workflows/syntax/#jobsjob_idhooks) for the general hooks syntax. + #### Outputs You can reference the following outputs in subsequent jobs: @@ -1061,9 +1146,11 @@ You can reference the following outputs in subsequent jobs: > **Note:** When using `async: true` mode, only the `maestro_cloud_url` output is guaranteed to be valid. Other outputs (flow counts and flow names) may be invalid or empty because the job does not wait for the upload to complete and the flows have not been executed yet. +You can also define additional outputs for this job using [`jobs..outputs`](/eas/workflows/syntax/#jobsjob_idoutputs). + ### Examples -Here are some practical examples of using the Maestro job: +Here are some practical examples of using the Maestro Cloud job: diff --git a/docs/pages/eas/workflows/syntax.mdx b/docs/pages/eas/workflows/syntax.mdx index 793a77c797917c..fe2e0d5b78cbfe 100644 --- a/docs/pages/eas/workflows/syntax.mdx +++ b/docs/pages/eas/workflows/syntax.mdx @@ -441,6 +441,25 @@ jobs: # @end # ``` +### `jobs..hooks` + +Some pre-packaged jobs support hooks to run additional steps before or after the main job action (for example, `maestro-cloud`, `maestro`, and `submit`). Hook names are job-specific. See the job's documentation for the available hook keys. + +```yaml +jobs: + maestro_test: + type: maestro-cloud + params: + build_id: ${{ needs.build.outputs.build_id }} + maestro_project_id: proj_xyz + flows: ./maestro/flows + hooks: + before_maestro_cloud: + - run: echo "Before upload" + after_maestro_cloud: + - run: echo "After upload" +``` + ### `jobs..defaults.run.working_directory` Sets the directory to run commands in for all steps in the job. @@ -1153,6 +1172,9 @@ jobs: build_id: string # required profile: string # optional, default: production groups: string[] # optional + hooks: + before_submit: step[] # optional + after_submit: step[] # optional ``` This job outputs the following properties: @@ -1246,9 +1268,12 @@ jobs: include_tags: string | string[] # optional. Tags to include in the tests. Will be passed to Maestro as `--include-tags`. exclude_tags: string | string[] # optional. Tags to exclude from the tests. Will be passed to Maestro as `--exclude-tags`. maestro_version: string # optional. Version of Maestro to use for the tests. If not provided, the latest version will be used. - android_system_image_package: string # optional. Android emulator system image package to use. + android_system_image_package: string # optional. Android Emulator system image package to use. device_identifier: string | { android?: string, ios?: string } # optional. Device identifier to use for the tests. output_format?: string # optional, defaults to junit. Maestro test report format. Will be passed to Maestro as `--format`. Can be `junit` or other supported formats. + hooks: + before_maestro_tests: step[] # optional + after_maestro_tests: step[] # optional ``` #### `maestro-cloud` @@ -1280,6 +1305,9 @@ jobs: name: string # optional. Name for the Maestro Cloud upload. Corresponds to `--name` param to `maestro cloud`. branch: string # optional. Override for the branch the Maestro Cloud upload originated from. By default, if the workflow run has been triggered from GitHub, the branch of the workflow run will be used. Corresponds to `--branch` param to `maestro cloud`. async: boolean # optional. Run the Maestro Cloud tests asynchronously. If true, the status of the job will only denote whether the upload was successful, *not* whether the tests succeeded. Corresponds to `--async` param to `maestro cloud`. + hooks: + before_maestro_cloud: step[] # optional. Steps to run before the Maestro Cloud upload. + after_maestro_cloud: step[] # optional. Steps to run after the Maestro Cloud upload. ``` #### `slack` diff --git a/docs/pages/get-started/create-a-project.mdx b/docs/pages/get-started/create-a-project.mdx index 54bd32e772ff71..1a24c654a32f73 100644 --- a/docs/pages/get-started/create-a-project.mdx +++ b/docs/pages/get-started/create-a-project.mdx @@ -19,9 +19,9 @@ We recommend starting with the default project created by `create-expo-app`. The To create a new project, run the following command: - + -> **Note:** During the SDK 55 transition period, `create-expo-app@latest` without the `--template` flag creates an SDK 54 project. If you plan to use Expo Go on a physical device, use an SDK 54 project. Otherwise, use `--template default@sdk-55` to create an SDK 55 project. You can also choose a different template by adding the [`--template` option](/more/create-expo/#--template). +> **Note:** During the SDK 56 transition period, `create-expo-app@latest` without the `--template` flag creates an SDK 55 project. If you plan to use Expo Go on a physical device, use an SDK 55 project. Otherwise, use `--template default@sdk-56` to create an SDK 56 project. You can also choose a different template by adding the [`--template` option](/more/create-expo/#--template). ## Next step diff --git a/docs/pages/guides/local-https-development.mdx b/docs/pages/guides/local-https-development.mdx index 62ac4224974bd7..228fa5b95db24f 100644 --- a/docs/pages/guides/local-https-development.mdx +++ b/docs/pages/guides/local-https-development.mdx @@ -39,7 +39,7 @@ Create or navigate to your Expo project: diff --git a/docs/pages/guides/new-architecture.mdx b/docs/pages/guides/new-architecture.mdx index 4f97c33015642d..4b96805a8beb0f 100644 --- a/docs/pages/guides/new-architecture.mdx +++ b/docs/pages/guides/new-architecture.mdx @@ -85,7 +85,7 @@ You can configure the React Native Directory check in your **package.json** file **As of SDK 52**, all new projects will be initialized with the New Architecture enabled by default. - + ## Enable the New Architecture in an existing project diff --git a/docs/pages/guides/typescript.mdx b/docs/pages/guides/typescript.mdx index 12cd377111e0bb..d48a46c6879728 100644 --- a/docs/pages/guides/typescript.mdx +++ b/docs/pages/guides/typescript.mdx @@ -19,7 +19,7 @@ This guide provides a quick way to get started for a new project and also steps To create a new project, use the default template which includes base TypeScript configuration, example code, and basic navigation structure: - + After you create a new project using the command above, make sure to follow instructions from: diff --git a/docs/pages/modules/use-standalone-expo-module-in-your-project.mdx b/docs/pages/modules/use-standalone-expo-module-in-your-project.mdx index 6ffaa3496d5453..6dcc761b81887a 100644 --- a/docs/pages/modules/use-standalone-expo-module-in-your-project.mdx +++ b/docs/pages/modules/use-standalone-expo-module-in-your-project.mdx @@ -172,9 +172,9 @@ Apart from publishing your module to npm, you can use it in your project in the To test the published module in a new project, create a new app and install the module as a dependency by running the following command: -## Expo Observe +## EAS Observe -[Expo Observe](/eas/observe/introduction/) is a performance monitoring service from Expo that tracks how your app performs in production. It gives you visibility in startup metrics (such as cold launch time, time to first render, and time to interactive) from real app user sessions, rendering performance, and app user experience across different devices, networks, and conditions. +[EAS Observe](/eas/observe/introduction/) is a performance monitoring service from Expo that tracks how your app performs in production. It gives you visibility in startup metrics (such as cold launch time, time to first render, and time to interactive) from real app user sessions, rendering performance, and app user experience across different devices, networks, and conditions. Get started with the following guide: diff --git a/docs/pages/more/create-expo.mdx b/docs/pages/more/create-expo.mdx index 1f7a2b5dab7244..00d8000cf32bd6 100644 --- a/docs/pages/more/create-expo.mdx +++ b/docs/pages/more/create-expo.mdx @@ -14,14 +14,14 @@ To create a new project, run the following command: -> **Note:** During the SDK 55 transition period, `create-expo-app@latest` without the `--template` flag creates an SDK 54 project. If you plan to use Expo Go on a physical device, use an SDK 54 project. Otherwise, use `--template default@sdk-55` to create an SDK 55 project. +> **Note:** During the SDK 56 transition period, `create-expo-app@latest` without the `--template` flag creates an SDK 54 project. If you plan to use Expo Go on a physical device, use an SDK 54 project. Otherwise, use `--template default@sdk-56` to create an SDK 56 project. Running the above command will prompt you to enter the app name of your project. This app name is also used in the app config's [`name`](/versions/latest/config/app/#name) property. diff --git a/docs/pages/more/glossary-of-terms.mdx b/docs/pages/more/glossary-of-terms.mdx index 727449f88b12fb..e2db04ee9a39c2 100644 --- a/docs/pages/more/glossary-of-terms.mdx +++ b/docs/pages/more/glossary-of-terms.mdx @@ -126,7 +126,7 @@ The development server is typically hosted on `http://localhost:8081`. It hosts ### Expo Application Services (EAS) -[Expo Application Services (EAS)](/eas) are deeply integrated cloud services for Expo and React Native apps, such as [EAS Build](/build/introduction/), [EAS Submit](/submit/introduction/), [EAS Update](/eas-update/introduction/), [EAS Metadata](/eas/metadata/), [EAS Insights](/eas-insights/introduction/), [EAS Hosting](/eas/hosting/introduction/), [EAS Workflows](/eas/workflows/introduction/), and [Expo Observe](/eas/observe/introduction/). +[Expo Application Services (EAS)](/eas) are deeply integrated cloud services for Expo and React Native apps, such as [EAS Build](/build/introduction/), [EAS Submit](/submit/introduction/), [EAS Update](/eas-update/introduction/), [EAS Metadata](/eas/metadata/), [EAS Insights](/eas-insights/introduction/), [EAS Hosting](/eas/hosting/introduction/), [EAS Workflows](/eas/workflows/introduction/), and [EAS Observe](/eas/observe/introduction/). ### EAS Build @@ -152,6 +152,10 @@ The **eas.json** file used to configure [EAS CLI](#eas-cli). For more informatio A command-line tool for uploading and downloading Apple App Store metadata as JSON. This tool is available in the [EAS CLI](#eas-cli) package and should be used to improve the iOS submission process. For more information, see [EAS Metadata](/eas/metadata/). +### EAS Observe + +[EAS Observe](/eas/observe/introduction/) is a performance monitoring service that tracks how an app performs in production, including cold and warm launch times, time to first render, and time to interactive. It uses the `expo-observe` library to collect metrics from production builds, which can then be viewed in the Observe dashboard. + ### EAS Update 1. The cloud hosting service [EAS Update](/eas-update/introduction/) from [EAS](#expo-application-services-eas) that is used for OTA Updates. @@ -223,10 +227,6 @@ A file named **expo-module.config.json** that lives in the root directory of a [ [Expo Modules API](/modules/module-api/) is a cross-platform API for writing native modules in Kotlin and Swift to add new capabilities to your apps. This API is provided by the library `expo-modules-core` which is included in the `expo` package. -### Expo Observe - -[Expo Observe](/eas/observe/introduction/) is a performance monitoring service that tracks how an app performs in production, including cold and warm launch times, time to first render, and time to interactive. It uses the `expo-observe` library to collect metrics from production builds, which can then be viewed in the Observe dashboard. - ### Expo Orbit [Expo Orbit](/build/orbit/) is an application for macOS, Windows, and Linux that enables faster installation and launching of builds or updates from EAS, local files, or Snack projects, on devices or emulators/simulators. diff --git a/docs/pages/router/error-handling.mdx b/docs/pages/router/error-handling.mdx index 105b32a5806899..957c472a938464 100644 --- a/docs/pages/router/error-handling.mdx +++ b/docs/pages/router/error-handling.mdx @@ -86,7 +86,7 @@ React Native LogBox needs to be presented less aggressively to develop with erro > **important** Custom suspense fallbacks are available in SDK 56 and later. -Expo Router wraps each route in a [React Suspense](https://react.dev/reference/react/Suspense) boundary. You can export a [`SuspenseFallback`](/versions/unversioned/sdk/router/#suspensefallback) component from a layout file to customize the loading UI shown while any child route is suspended: +Expo Router wraps each route in a [React Suspense](https://react.dev/reference/react/Suspense) boundary. You can export a [`SuspenseFallback`](/versions/latest/sdk/router/#suspensefallback) component from a layout file to customize the loading UI shown while any child route is suspended: ```tsx src/app/_layout.tsx import { ActivityIndicator, View } from 'react-native'; @@ -109,7 +109,7 @@ export default function RootLayout() { ### Accessing route parameters -The [`SuspenseFallback`](/versions/unversioned/sdk/router/#suspensefallback) component receives `route` and `params` props. You can use `params` to display context-specific loading states for dynamic routes, for example: +The [`SuspenseFallback`](/versions/latest/sdk/router/#suspensefallback) component receives `route` and `params` props. You can use `params` to display context-specific loading states for dynamic routes, for example: ```tsx src/app/(app)/_layout.tsx import { ActivityIndicator, Text, View } from 'react-native'; diff --git a/docs/pages/router/introduction.mdx b/docs/pages/router/introduction.mdx index a40856d7751338..f326520a862f66 100644 --- a/docs/pages/router/introduction.mdx +++ b/docs/pages/router/introduction.mdx @@ -29,14 +29,14 @@ We recommend creating a new Expo app using `create-expo-app` to create a project -> **Note:** During the SDK 55 transition period, `create-expo-app@latest` without the `--template` flag creates an SDK 54 project. If you plan to use Expo Go on a physical device, use an SDK 54 project. Otherwise, use `--template default@sdk-55` to create an SDK 55 project. +> **Note:** During the SDK 56 transition period, `create-expo-app@latest` without the `--template` flag creates an SDK 54 project. If you plan to use Expo Go on a physical device, use an SDK 54 project. Otherwise, use `--template default@sdk-56` to create an SDK 56 project. diff --git a/docs/pages/router/reference/testing.mdx b/docs/pages/router/reference/testing.mdx index bc5533e9a04408..ed278b72187ba3 100644 --- a/docs/pages/router/reference/testing.mdx +++ b/docs/pages/router/reference/testing.mdx @@ -155,8 +155,6 @@ expect(screen).useLocalSearchParams({ first: 'abc' }); -Assert the current screen's pathname that matches a value. Compares using the value of [`useGlobalSearchParams`](/versions/latest/sdk/router/#useglobalsearchparams) hook. - Assert the current global URL parameters against an object. The matcher uses the value of the [`useGlobalSearchParams`](/versions/latest/sdk/router/#useglobalsearchparams) hook on the current `screen`. ```tsx app.test.tsx diff --git a/docs/pages/router/web/data-loaders.mdx b/docs/pages/router/web/data-loaders.mdx index abe16b6bc719cc..b6631fa5434800 100644 --- a/docs/pages/router/web/data-loaders.mdx +++ b/docs/pages/router/web/data-loaders.mdx @@ -335,7 +335,7 @@ With server rendering, loaders execute on every request. This means: ### `createStaticLoader` -Use [`createStaticLoader`](/versions/unversioned/sdk/server/#createstaticloaderfn) for routes that only need route parameters. The callback only receives the route params, and is safe to use with both static and server rendering: +Use [`createStaticLoader`](/versions/latest/sdk/server/#createstaticloaderfn) for routes that only need route parameters. The callback only receives the route params, and is safe to use with both static and server rendering: ```tsx src/app/posts/[postId].tsx import { Text, View } from 'react-native'; @@ -360,7 +360,7 @@ export default function Post() { ### `createServerLoader` -Use [`createServerLoader`](/versions/unversioned/sdk/server/#createserverloaderfn) for routes that need access to the incoming HTTP request. The callback receives an [`ImmutableRequest`](/versions/latest/sdk/server/#immutablerequest) and the route params as arguments: +Use [`createServerLoader`](/versions/latest/sdk/server/#createserverloaderfn) for routes that need access to the incoming HTTP request. The callback receives an [`ImmutableRequest`](/versions/latest/sdk/server/#immutablerequest) and the route params as arguments: ```tsx src/app/profile.tsx import { Text, View } from 'react-native'; diff --git a/docs/pages/router/web/server-rendering.mdx b/docs/pages/router/web/server-rendering.mdx index 981d9aa86bf513..ae830add40ef63 100644 --- a/docs/pages/router/web/server-rendering.mdx +++ b/docs/pages/router/web/server-rendering.mdx @@ -106,14 +106,14 @@ In the above example, when the app user visits `/blog/my-post`, the page is rend You can customize the root HTML document by creating a **src/app/+html.tsx** file. This component wraps all routes and runs only on the server. -The [`useServerDocumentContext`](/versions/unversioned/sdk/router/#useserverdocumentcontext) hook from `expo-router/html` provides metadata and asset nodes that the server renderer injects into the document. You must spread these values into your HTML to ensure metadata, fonts, and CSS are included in the response: +The [`useServerDocumentContext`](/versions/latest/sdk/router/#useserverdocumentcontext) hook from `expo-router/html` provides metadata and asset nodes that the server renderer injects into the document. You must spread these values into your HTML to ensure metadata, fonts, and CSS are included in the response: - `htmlAttributes`: attributes to add to the `` element - `bodyAttributes`: attributes to add to the `` element - `headNodes`: React nodes for the `` element (metadata, CSS, and other assets) - `bodyNodes`: React nodes for the `` element (fonts and other deferred assets) -> **info** When creating a custom **+html.tsx** template, you must use all properties returned to you by [`useServerDocumentContext`](/versions/unversioned/sdk/router/#useserverdocumentcontext). Otherwise, your server-side rendered HTML may appear broken or your app may not function correctly. +> **info** When creating a custom **+html.tsx** template, you must use all properties returned to you by [`useServerDocumentContext`](/versions/latest/sdk/router/#useserverdocumentcontext). Otherwise, your server-side rendered HTML may appear broken or your app may not function correctly. ```tsx src/app/+html.tsx import { ScrollViewStyleReset, useServerDocumentContext } from 'expo-router/html'; @@ -155,7 +155,7 @@ export default function Root({ children }: { children: ReactNode }) { The **+html.tsx** file is only used by the server renderer and never by client code. This means: - It will be run by `expo-server` during server rendering -- It is not rehydrated on the client, and should only use [`useServerDocumentContext`](/versions/unversioned/sdk/router/#useserverdocumentcontext) React hook +- It is not rehydrated on the client, and should only use [`useServerDocumentContext`](/versions/latest/sdk/router/#useserverdocumentcontext) React hook - You may not import global CSS in `+html.tsx` (use the [Root Layout](/router/basics/navigation-layouts/#root-layout) for styles) - You may not call browser APIs like `window` or `document` in your `+html.tsx` @@ -163,9 +163,9 @@ All `+html.tsx` components are expected to render the `children` prop they recei ## Metadata -Routes may export a [`generateMetadata`](/versions/unversioned/sdk/server/#generatemetadatafunctionrequest-params) function to define per-page metadata such as title, description, and [Open Graph](https://ogp.me/) tags. This function runs on the server before rendering begins, and its result is injected into the `` of the HTML document via the `headNodes` provided by [`useServerDocumentContext`](/versions/unversioned/sdk/router/#useserverdocumentcontext) in your [Root HTML](#root-html) component. +Routes may export a [`generateMetadata`](/versions/latest/sdk/server/#generatemetadatafunctionrequest-params) function to define per-page metadata such as title, description, and [Open Graph](https://ogp.me/) tags. This function runs on the server before rendering begins, and its result is injected into the `` of the HTML document via the `headNodes` provided by [`useServerDocumentContext`](/versions/latest/sdk/router/#useserverdocumentcontext) in your [Root HTML](#root-html) component. -Export a [`generateMetadata`](/versions/unversioned/sdk/server/#generatemetadatafunctionrequest-params) function from your route file and return a [`Metadata`](/versions/unversioned/sdk/server/#metadata) object. The function receives the incoming request and route parameters, which you can use to generate metadata dynamically: +Export a [`generateMetadata`](/versions/latest/sdk/server/#generatemetadatafunctionrequest-params) function from your route file and return a [`Metadata`](/versions/latest/sdk/server/#metadata) object. The function receives the incoming request and route parameters, which you can use to generate metadata dynamically: ```tsx src/app/blog/[id].tsx import { Text } from 'react-native'; @@ -193,7 +193,7 @@ export default function BlogPost() { } ``` -The `generateMetadata` function executes on the server and is stripped from the client bundle, similar to [data loaders](/router/web/data-loaders). For a full list of supported metadata fields, see the [`Metadata`](/versions/unversioned/sdk/server/#metadata) type in the `expo-server` API reference. +The `generateMetadata` function executes on the server and is stripped from the client bundle, similar to [data loaders](/router/web/data-loaders). For a full list of supported metadata fields, see the [`Metadata`](/versions/latest/sdk/server/#metadata) type in the `expo-server` API reference. ### Using `` with server rendering diff --git a/docs/pages/troubleshooting/overview.mdx b/docs/pages/troubleshooting/overview.mdx index 8a4eb0cc680196..cc618e027a9651 100644 --- a/docs/pages/troubleshooting/overview.mdx +++ b/docs/pages/troubleshooting/overview.mdx @@ -158,8 +158,8 @@ This page lists a collection of various troubleshooting guides for Expo and EAS. /> diff --git a/docs/pages/tutorial/follow-up.mdx b/docs/pages/tutorial/follow-up.mdx index e802ed6d673f04..82edd8a7ac38ff 100644 --- a/docs/pages/tutorial/follow-up.mdx +++ b/docs/pages/tutorial/follow-up.mdx @@ -9,9 +9,9 @@ Now that the example app is done, let's learn more about the technologies we use ## Build your project into an app -To start creating a new app on your machine you can use `npx create-expo-app@latest --template default@sdk-55` and [set up your development environment](/get-started/set-up-your-environment/) sequentially. +To start creating a new app on your machine you can use `npx create-expo-app@latest --template default@sdk-56` and [set up your development environment](/get-started/set-up-your-environment/) sequentially. -> **Note:** During the SDK 55 transition period, `create-expo-app@latest` without the `--template` flag creates an SDK 54 project. If you plan to use Expo Go on a physical device, use an SDK 54 project. Otherwise, use `--template default@sdk-55` to create an SDK 55 project. +> **Note:** During the SDK 56 transition period, `create-expo-app@latest` without the `--template` flag creates an SDK 54 project. If you plan to use Expo Go on a physical device, use an SDK 54 project. Otherwise, use `--template default@sdk-56` to create an SDK 56 project. ### Recommended resources diff --git a/docs/pages/versions/unversioned/sdk/ui/jetpack-compose/horizontalfloatingtoolbar.mdx b/docs/pages/versions/unversioned/sdk/ui/jetpack-compose/horizontalfloatingtoolbar.mdx index bd105162e95006..5d958cf15766e9 100644 --- a/docs/pages/versions/unversioned/sdk/ui/jetpack-compose/horizontalfloatingtoolbar.mdx +++ b/docs/pages/versions/unversioned/sdk/ui/jetpack-compose/horizontalfloatingtoolbar.mdx @@ -12,7 +12,7 @@ import { ContentSpotlight } from '~/ui/components/ContentSpotlight'; Expo UI HorizontalFloatingToolbar wraps the official Jetpack Compose [`HorizontalFloatingToolbar`](https://kotlinlang.org/api/compose-multiplatform/material3/androidx.compose.material3/-horizontal-floating-toolbar.html) and displays a horizontal toolbar that floats above content, containing action buttons. -> **Note:** If you only need a single floating button, use [`FloatingActionButton`](/versions/unversioned/sdk/ui/jetpack-compose/floatingactionbutton/) instead. +> **Note:** If you only need a single floating button, use [`FloatingActionButton`](/versions/latest/sdk/ui/jetpack-compose/floatingactionbutton/) instead. - -## Properties - - diff --git a/docs/pages/versions/v53.0.0/config/babel.mdx b/docs/pages/versions/v53.0.0/config/babel.mdx deleted file mode 100644 index af29a639094238..00000000000000 --- a/docs/pages/versions/v53.0.0/config/babel.mdx +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: babel.config.js -description: A reference for Babel configuration file. ---- - -import { Terminal } from '~/ui/components/Snippet'; - -Babel is used as the JavaScript compiler to transform modern JavaScript (ES6+) into a version compatible with the JavaScript engine on mobile devices. - -Each new Expo project created using `npx create-expo-app` configures Babel automatically and uses [`babel-preset-expo`](https://github.com/expo/expo/tree/main/packages/babel-preset-expo) as the default preset. There is no need to create a **babel.config.js** file unless you need to customize the Babel configuration. - -## Create babel.config.js - -If your project requires a custom Babel configuration, you need to create the **babel.config.js** file in your project by following the steps below: - -1. Navigate to the root of your project and run the following command inside a terminal. This will generate a **babel.config.js** file in the root of your project. - - - -2. The **babel.config.js** file contains the following default configuration: - -```js babel.config.js -module.exports = function (api) { - api.cache(true); - return { - presets: ['babel-preset-expo'], - }; -}; -``` - -3. If you make a change to the **babel.config.js** file, you need to restart the Metro bundler to apply the changes and use `--clear` option from Expo CLI to clear the Metro bundler cache: - - - -## babel-preset-expo - -[`babel-preset-expo`](https://github.com/expo/expo/tree/main/packages/babel-preset-expo) is the default preset used in Expo projects. It extends the default React Native preset (`@react-native/babel-preset`) and adds support for decorators, tree-shaking web libraries, and loading font icons. diff --git a/docs/pages/versions/v53.0.0/config/metro.mdx b/docs/pages/versions/v53.0.0/config/metro.mdx deleted file mode 100644 index d86891536737e1..00000000000000 --- a/docs/pages/versions/v53.0.0/config/metro.mdx +++ /dev/null @@ -1,692 +0,0 @@ ---- -title: metro.config.js -description: A reference of available configurations in Metro. ---- - -import { BookOpen02Icon } from '@expo/styleguide-icons/outline/BookOpen02Icon'; - -import { BoxLink } from '~/ui/components/BoxLink'; -import { FileTree } from '~/ui/components/FileTree'; -import { DiffBlock, Terminal } from '~/ui/components/Snippet'; - -See more information about **metro.config.js** in the [customizing Metro guide](/guides/customizing-metro/). - -## Environment variables - -Expo CLI can load environment variables from **.env** files. Learn more about how to use environment variables in Expo CLI in the [environment variables guide](/guides/environment-variables/). - -EAS CLI uses a different mechanism for environment variables, except when it invokes Expo CLI for compiling and bundling. Learn more about [environment variables in EAS](/build-reference/variables/). - -If you are migrating an older project, then you should ignore local env files by adding the following to your **.gitignore**: - -```sh .gitignore -# local env files -.env*.local -``` - -### Disabling dotenv files - -Dotenv file loading can be fully disabled in Expo CLI by enabling the `EXPO_NO_DOTENV` environment variable, before invoking any Expo CLI command. - - - -### Disabling `EXPO_PUBLIC_`-prefixed client environment variables - -Environment variables prefixed with `EXPO_PUBLIC_` will be exposed to the app at build-time. For example, `EXPO_PUBLIC_API_KEY` will be available as `process.env.EXPO_PUBLIC_API_KEY`. - -Client environment variable inlining can be disabled with the environment variable `EXPO_NO_CLIENT_ENV_VARS=1`, this must be defined before any bundling is performed. - - - -## CSS - -> **info** CSS support is under development and currently only works on web. - -Expo supports CSS in your project. You can import CSS files from any component. CSS Modules are also supported. - -CSS support is enabled by default. You can disable the feature by setting `isCSSEnabled` in the Metro config. - -```js metro.config.js -/** @type {import('expo/metro-config').MetroConfig} */ -const config = getDefaultConfig(__dirname, { - // Disable CSS support. - isCSSEnabled: false, -}); -``` - -### Global CSS - -> **warning** Global styles are web-only, usage will cause your application to diverge visually on native. - -You can import a CSS file from any component. The CSS will be applied to the entire page. - -Here, we'll define a global style for the class name `.container`: - -```css styles.css -.container { - background-color: red; -} -``` - -We can then use the class name in our component by importing the stylesheet and using `.container`: - -```jsx App.js|collapseHeight=470 -import './styles.css'; -import { View } from 'react-native'; - -export default function App() { - return ( - <> - {/* Use `className` to assign the style with React DOM components. */} -
Hello World
- - {/* Use `style` with the following syntax to append class names in React Native for web. */} - - Hello World - - - ); -} -``` - -You can also import stylesheets that are vendored in libraries, just like you would any node module: - -```js index.js -// Applies the styles app-wide. -import 'emoji-mart/css/emoji-mart.css'; -``` - -- On native, all global stylesheets are automatically ignored. -- Hot reloading is supported for global stylesheets, simply save the file and the changes will be applied. - -### CSS Modules - -> **warning** CSS Modules for native are under development and currently only work on web. - -CSS Modules are a way to scope CSS to a specific component. This is useful for avoiding naming collisions and for ensuring that styles are only applied to the intended component. - -In Expo, CSS Modules are defined by creating a file with the `.module.css` extension. The file can be imported from any component. The exported value is an object with the class names as keys and the web-only scoped names as the values. The import `unstable_styles` can be used to access `react-native-web`-safe styles. - -CSS Modules support platform extensions to allow you to define different styles for different platforms. For example, you can define a `module.ios.css` and `module.android.css` file to define styles for Android and iOS respectively. You'll need to import without the extension, for example: - - - -Flipping the extension, for example, `App.ios.module.css` will not work and result in a universal module named `App.ios.module`. - -> You cannot pass styles to the `className` prop of a React Native or React Native for web component. Instead, you must use the `style` prop. - -```jsx App.js|collapseHeight=470 -import styles, { unstable_styles } from './App.module.css'; - -export default function Page() { - return ( - <> - - Hello World - - Hello World - {/* Web-only usage: */} -

Hello World

- - ); -} -``` - -```css App.module.css -.text { - color: red; -} -``` - -- On web, all CSS values are available. CSS is not processed or auto-prefixed like it is with the React Native Web `StyleSheet` API. You can use `postcss.config.js` to autoprefix your CSS. -- CSS Modules use [lightningcss](https://github.com/parcel-bundler/lightningcss) under the hood, check [the issues](https://github.com/parcel-bundler/lightningcss/issues) for unsupported features. - -### PostCSS - -[PostCSS](https://github.com/postcss/postcss) can be customized by adding a `postcss.config.json` file to the root of your project. This file should export a function that returns a PostCSS configuration object. For example: - -```json postcss.config.json -{ - "plugins": { - "autoprefixer": {} - } -} -``` - -Both `postcss.config.json` and `postcss.config.js` are supported, but `postcss.config.json` enables better caching. - -#### Resetting cache after updates - -Changing the Post CSS or `browserslist` config will require you to clear the Metro cache: - - - -### SASS - -Expo Metro has _partial_ support for SCSS/SASS. - -To setup, install the `sass` package in your project: - - - -Then, ensure [CSS is setup](#css) in the **metro.config.js** file. - -- When `sass` is installed, then modules without extensions will be resolved in the following order: `scss`, `sass`, `css`. -- Only use the intended syntax with `sass` files. -- Importing other files from inside a scss/sass file is not currently supported. - -### Tailwind - -> **info** Standard Tailwind CSS supports only web platform. For universal support, use a library such as [NativeWind](https://www.nativewind.dev/), which allows creating styled React Native components with Tailwind CSS. - - - -## Extending the Babel transformer - -Expo's Metro config uses a custom `transformer.babelTransformerPath` value to ensure `expo-babel-preset` is always used and web/Node.js environments are supported. - -If you want to extend the Babel transformer, import the upstream transformer from `@expo/metro-config/babel-transformer` instead of `metro-react-native-babel-transformer`. For example: - -```js metro.transformer.js -const upstreamTransformer = require('@expo/metro-config/babel-transformer'); - -module.exports.transform = async ({ src, filename, options }) => { - // Do something custom for SVG files... - if (filename.endsWith('.svg')) { - src = '...'; - } - // Pass the source through the upstream Expo transformer. - return upstreamTransformer.transform({ src, filename, options }); -}; -``` - -## Custom resolving - -Expo CLI extends the default Metro resolver to add features like Web, Server, and tsconfig aliases support. You can similarly customize the default resolution behavior of Metro by chaining the `config.resolver.resolveRequest` function. - -```tsx metro.config.js|collapseHeight=470 -const { getDefaultConfig } = require('expo/metro-config'); - -/** @type {import('expo/metro-config').MetroConfig} */ -const config = getDefaultConfig(__dirname); - -config.resolver.resolveRequest = (context, moduleName, platform) => { - if (moduleName.startsWith('my-custom-resolver:')) { - // Logic to resolve the module name to a file path... - // NOTE: Throw an error if there is no resolution. - return { - filePath: 'path/to/file', - type: 'sourceFile', - }; - } - - // Ensure you call the default resolver. - return context.resolveRequest(context, moduleName, platform); -}; - -module.exports = config; -``` - -Unlike traditional bundlers, Metro shared the same resolver function across all platforms. As a result, you can mutate the resolution settings dynamically on each request with the `context` object. - -### Mocking modules - -If you want a module to be empty for a given platform, you can return a `type: 'empty'` object from the resolver. The following example will cause `lodash` to be empty on web: - -```ts metro.config.js -const { getDefaultConfig } = require('expo/metro-config'); - -/** @type {import('expo/metro-config').MetroConfig} */ -const config = getDefaultConfig(__dirname); - -config.resolver.resolveRequest = (context, moduleName, platform) => { - if (platform === 'web' && moduleName === 'lodash') { - return { - type: 'empty', - }; - } - - // Ensure you call the default resolver. - return context.resolveRequest(context, moduleName, platform); -}; - -module.exports = config; -``` - -This technique is equivalent to using empty externals in Webpack or Vite, but with the added benefit of being able to target specific platforms. - -### Virtual modules - -Metro doesn't support virtual modules at the moment. One technique you can use to obtain similar behavior is to create a module in the `node_modules/.cache/...` directory and redirect the resolution to that file. - -The following example will create a module at `node_modules/.cache/virtual/virtual-module.js` and redirect the resolution of `virtual:my-module` to that file: - -```ts metro.config.js -const path = require('path'); -const fs = require('fs'); - -const { getDefaultConfig } = require('expo/metro-config'); - -/** @type {import('expo/metro-config').MetroConfig} */ -const config = getDefaultConfig(__dirname); - -const virtualPath = path.resolve(__dirname, 'node_modules/.cache/virtual/virtual-module.js'); - -// Create the virtual module in a generated directory... -fs.mkdirSync(path.dirname(virtualPath), { recursive: true }); -fs.writeFileSync(virtualPath, 'export default "Hello World";'); - -config.resolver.resolveRequest = (context, moduleName, platform) => { - if (moduleName === 'virtual:my-module') { - return { - filePath: virtualPath, - type: 'sourceFile', - }; - } - - // Ensure you call the default resolver. - return context.resolveRequest(context, moduleName, platform); -}; - -module.exports = config; -``` - -This can be used to emulate `externals` with custom imports. For example, if you want to redirect `require('expo')` to something custom like `SystemJS.require('expo')`, you can create a virtual module that exports `SystemJS.require('expo')` and redirect the resolution of `expo` to that file. - -## Custom transforming - -> Transformations are heavily cached in Metro. If you update something, use the `--clear` flag to see updates. For example, `npx expo start --clear`. - -Metro doesn't have a very expressive plugin system for transforming files, instead opt to use the [**babel.config.js**](../config/babel/) and caller object to customize the transformation. - -```js babel.config.js -module.exports = function (api) { - // Get the platform that Expo CLI is transforming for. - const platform = api.caller(caller => (caller ? caller.platform : 'ios')); - - // Detect if the bundling operation is for Hermes engine or not, e.g. `'hermes'` | `undefined`. - const engine = api.caller(caller => (caller ? caller.engine : null)); - - // Is bundling for a server environment, e.g. API Routes. - const isServer = api.caller(caller => (caller ? caller.isServer : false)); - - // Is bundling for development or production. - const isDev = api.caller(caller => - caller - ? caller.isDev - : process.env.BABEL_ENV === 'development' || process.env.NODE_ENV === 'development' - ); - - // Ensure the config is not cached otherwise the platform will not be updated. - api.cache(false); - // You can alternatively provide a more robust CONFIG cache invalidation: - // api.cache.invalidate(() => platform); - - return { - presets: ['babel-preset-expo'], - plugins: [ - // Add a plugin based on the platform... - platform === 'web' && 'my-plugin', - - // Ensure you filter out falsy values. - ].filter(Boolean), - }; -}; -``` - -If the caller doesn't have `engine`, `platform`, `bundler`, and so on, then ensure you are using `@expo/metro-config/babel-transformer` for the transformer. If you're using a custom transformer then it may need to extend the Expo transformer. - -Always try to implement custom logic in the resolver if possible, caching is much simpler and easier to reason about. For example, if you need to remap an import, it's simpler and faster to resolve to a static file with the resolver than to parse all possible import methods and remap them with the transformer. - -Always use `babel-preset-expo` as the default Babel preset, this ensures the transformation is always compatible with Expo runtimes. `babel-preset-expo` uses all of the caller inputs internally to optimize for a given platform, engine, and environment. - -## Node.js built-ins - -When bundling for a server environment, Expo's Metro config automatically supports externalizing Node.js built-in modules (`fs`, `path`, `node:crypto`, and more) based on the current Node.js version. If the CLI is bundling for a browser environment, then built-ins will first check if the module is installed locally, then fallback on an empty shim. For example, if you install `path` for use in the browser, this can be used, otherwise, the module will automatically be skipped. - -## Environment settings - -> **info** These environment variables will not be defined in test environments. - -Expo's Metro config injects build settings that can be used in the client bundle via environment variables. All variables will be inlined and cannot be used dynamically. For example, `process.env["EXPO_BASE_URL"]` won't work. - -- `process.env.EXPO_BASE_URL` exposes the base URL defined in `experiments.baseUrl`. This is used in Expo Router to respect the production base URL for deployment. - -## Bundle splitting - -Expo CLI automatically splits web bundles into multiple chunks based on async imports in production. This feature requires `@expo/metro-runtime` to be installed and imported somewhere in the entry bundle (available by default in Expo Router). - -Shared dependencies of async bundles are merged into a single chunk to reduce the number of requests. For example, if you have two async bundles that import `lodash`, then the library is merged into a single initial chunk. - -The chunk splitting heuristic cannot be customized. For example: - - - -```js math.js -export function add(a, b) { - return a + b; -} -``` - -```js index.js -import '@expo/metro-runtime'; - -// This will be split into a separate chunk. -import('./math').then(math => { - console.log(math.add(1, 2)); -}); -``` - -When you run `npx expo export -p web`, the bundles are split into multiple files, and the entry bundle is added to the main HTML file. `@expo/metro-runtime` adds the runtime code that loads and evaluates the async bundles. - -## Source map debug ID - -If a bundle is exported with an external source map, a [**Debug ID**](https://sentry.engineering/blog/the-case-for-debug-ids) annotation will be added to the end of the file, along with a matching `debugId` in the source map for corresponding the files together. If no source maps are exported, or inline source maps are used then this annotation will not be added. - -```js -// - -//# debugId= -``` - -The associated `*.js.map` or `*.hbc.map` source map will be a JSON file containing an equivalent `debugId` property. The `debugId` will be injected before hermes bytecode generation to ensure matching in all cases. - -The `debugId` is a deterministic hash of the bundle's contents without the external bundle splitting references. This is the same value used to create a chunks filename but formatted as a UUID. For example, `431b98e2-c997-4975-a3d9-2987710abd44`. - -`@expo/metro-config` injects `debugId` during `npx expo export` and `npx expo export:embed`. Any additional optimization steps in `npx expo export:embed` like Hermes bytecode generation will need to have the `debugId` injected manually. - -## Metro require runtime - -You can optionally enable a custom Metro `require` implementation with the environment variable `EXPO_USE_METRO_REQUIRE=1`. This runtime has the following features: - -- String module IDs that are human-readable and make missing module errors easier to follow. -- Deterministic IDs that are the same between runs and across modules (required for React Server Components in development). -- Removed support for legacy RAM bundles. - -## Magic import comments - -> Available from SDK 52 on all platforms. - -Server environments such as Workers, and Node.js support import arbitrary files at runtime, so you may want to keep `import` syntax in-tact instead of using Metro's require system. You can opt-out dynamic imports with the `/* @metro-ignore */` comment in `import()` statements. - -```js -// Manually ensure `./my-module.js` is included in the correct spot relative to the module. -const myModule = await import(/* @metro-ignore */ './my-module.js'); -``` - -Expo CLI will skip the `./my-module.js` dependency and assume that the developer has manually added it to the output bundle. Internally, this is used for exporting custom server code that dynamically switches between files based on the request. Avoid using this syntax for native bundles since `import()` is generally not available in React Native with Hermes enabled. - -Many React libraries shipped the Webpack `/* webpackIgnore: true */` comment to achieve similar behavior. To bridge the gap, we've also added support for Webpack's comment but recommend using the Metro equivalent in your app. - -## ES Module resolution - -> This sections applies from SDK 53 on all platforms. - -Metro resolves ES Module `import` and CommonJS `require` with separate resolution strategies. - -Previously, Metro applied the classic Node.js module resolution strategy (which matches Node.js versions before v12), with some additions to support ES Modules. In this resolution strategy, Metro resolves modules from `node_modules`, JS files, optionally while omitting extensions, such as `.js`, and uses `package.json` fields such as `main`, `module`, and `react-native`. - -Now, with the modern ES Modules resolution strategy, Metro instead resolves modules from `node_modules`, then matches different `package.json` fields, such as `exports`, [a nested map of sub-paths a package exposes](https://nodejs.org/api/packages.html#conditional-exports), and `main`. - -Depending on how a package is imported, one of these two resolution strategies will be used. Typically, a file that is imported with `import` from a Node module (rather than `require`), will use the ES Modules resolution strategy, and fall back on regular classic Node.js resolution. A file that wasn't resolved with ES Modules resolution or has been imported with CommonJS `require` will use the classic resolution strategy. - -### `package.json:exports` - -When performing ES Modules resolution, Metro will look at the `package.json:exports` conditions map. This is a mapping of import subpaths and conditions to files in the Node module package. - -For example, a package that always exposes an **index.js** file, and matches Metro's classic CommonJS module resolution, may specify a map with the `default` condition. - -```json -{ - "exports": { - "default": "./index.js" - } -} -``` - -However, a package providing both a CommonJS and ES Modules entrypoint may provide a mapping with the `import` and `require` conditions. - -```json -{ - "exports": { - "import": "./index.mjs", - "require": "./index.cjs" - } -} -``` - -By default, Metro will match different conditions depending on the platform and whether the resolution has started from a CommonJS `require` call, or an ES Modules `import` statement and will change the condition accordingly. - -For native platforms, the condition `react-native` is added, for web exports, the `browser` condition is added, and for server exports (such as API routes or React Server functions), the `node`, `react-server`, and `workerd` conditions are added. These conditions aren't matched in the order they're defined in. Instead, they're matched against the order of properties in the `package.json:exports` map. - -TypeScript performs ES Module resolution separately from Metro and will also respect `package.json:exports` maps, when its `compilerOptions.moduleResolution` configuration option has either been set to `"bundler"` (which matches Metro's behavior more closely) or to `"node16"` / `"nodenext"`. TypeScript will however also match the `types` condition. As such, types may not resolve properly when a package doesn't put the `types` condition first in its exports map. - -Since an exports map may contain subpaths, a package import may not have to match a file in the package's modules folder any longer, but may be a "redirected" import. Importing `'package/submodule'` may match a different file than **node_modules/package/submodule.js** if it's specified in `package.json:exports`. - -```json -{ - "exports": { - ".": "./index.js", - "./submodule": "./submodule/submodule.js" - } -} -``` - -If you're encountering packages that are incompatible or unprepared for the new ES Modules resolution strategy, you may be able to resolve problems by patching its `package.json` file and add or correct its `package.json:exports` conditions map. However, it's also possible to prevent Metro from using `package.json:exports` maps in its resolution by disabling the `unstable_enablePackageExports` option. - -```js metro.config.js -const { getDefaultConfig } = require('expo/metro-config'); - -/** @type {import('expo/metro-config').MetroConfig} */ -const config = getDefaultConfig(__dirname); - -config.resolver.unstable_enablePackageExports = false; - -module.exports = config; -``` - -## Asset imports - -When assets are imported, a virtual module is created to represent the data required for importing the asset. - -On native platforms, an asset will be a numeric ID: `1`, `2`, `3`, and so on, which can be looked up using `require("@react-native/assets-registry/registry").getAssetByID()`. On web and server platforms, the asset will change depending on the file type. If the file is an image, then the asset will be `{ uri: string, width?: number, height?: number }`, otherwise the asset will be a `string` representing the remote URL for the asset. - -The assets can be used as follows: - -```jsx -import { Image } from 'react-native'; - -import asset from './img.png'; - -function Demo() { - return ; -} -``` - -In API routes, you can always assume the type of the asset will not be a number: - -```js -import asset from './img.png'; - -export async function GET(req: Request) { - const ImageData = await fetch( - new URL( - // Access the asset URI. - asset.uri, - // Append to the current request URL origin. - req.url - ) - ).then(res => res.arrayBuffer()); - - return new Response(ImageData, { - headers: { - 'Content-Type': 'image/png', - }, - }); -} -``` - -## Web workers - -> **important** This feature is in alpha and subject to breaking changes. - -```ts -new Worker(new URL('./worker', window.location.href)); -``` - -Expo Metro has experimental web worker support in SDK 53 and later. This feature is currently web-only and does not work on native, usage on native will trigger an error "Property 'Worker' doesn't exist". - -Web workers can be used to offload work to a separate thread on web, allowing the main thread to remain responsive. This is useful for computationally expensive tasks, such as image processing, cryptography, or other tasks that would otherwise block the main thread. - -Workers can be generated inline using `Blob`, but sometimes you may want to leverage modern features like TypeScript or importing other modules. - -Web workers depend on Expo bundle splitting support, which means you need to either use Expo Router or install and import `@expo/metro-runtime`. You also cannot use the environment `EXPO_NO_METRO_LAZY=1` with web workers. - -Consider the following example of a worker that doubles a number: - -```ts worker.ts -self.onmessage = ({ data }) => { - const result = data * 2; // Example: double the number - self.postMessage(result); -}; -``` - -This worker file can be imported as a `Worker` in the main app: - -```ts -// worker is of type `Worker` -const worker = new Worker(new URL('./worker', window.location.href)); - -worker.onmessage = ({ data }) => { - console.log(`Worker responded: ${data}`); -}; - -worker.postMessage(5); -``` - -Behind the scenes, Expo CLI is generating code like this: - -```ts -const worker = new Worker( - new URL('/worker.bundle?platform=web&dev=true&etc', window.location.href) -); -``` - -The generated bundle URL changes based on development/production to ensure the worker is loaded and bundled correctly. Unlike traditional bundle splitting, a worker file needs to contain its own copy of all modules and cannot depend on common modules in the main bundle. - -The native API `Worker` is traditionally unavailable in React Native and not provided by the Expo SDK, so even though this bundling feature technically works for all platforms, it's only useful on web. You could theoretically write a native Expo module that polyfills the `Worker` API if you want to support native platforms too. Alternatively, you can use the "worklet" API in React Native Reanimated to offload work to a separate thread on native. - -Alternatively, you can import Workers using the public path by first putting a transformed JS file in the **public** directory, then referencing it in the worker import with a variable: - -```ts -// Will avoid the transform and use the public path directly. -const worker = new Worker('/worker.js'); - -// The variable breaks the transform causing the literal path to be used instead of the transformed path. -const path = '/worker.js'; - -const anotherWorker = new Worker(new URL(path, window.location.href)); -``` - -Using a variable in the `Worker` constructor is not supported for bundling. To inspect the internal URL, you may use the internal syntax `require.unstable_resolveWorker('./path/to/worker.js')` to get the URL fragment. - -## Existing React Native apps - -> This guide is versioned and will need to be revisited when upgrading/downgrading Expo. Alternatively, use [Expo Prebuild](/more/glossary-of-terms/#prebuild) for fully automated setup. - -Projects that don't use [Expo Prebuild](/more/glossary-of-terms/#prebuild) must configure native files to ensure the Expo Metro config is always used to bundle the project. - -{/* If this isn't done, then features like [aliases](/guides/typescript/#path-aliases-optional), [absolute imports](/guides/typescript/#absolute-imports-optional), asset hashing, and more will not work. */} - -These modifications are meant to replace `npx react-native bundle` and `npx react-native start` with `npx expo export:embed` and `npx expo start` respectively. - -### metro.config.js - -Ensure the **metro.config.js** extends `expo/metro-config`: - -```js metro.config.js -const { getDefaultConfig } = require('expo/metro-config'); - -const config = getDefaultConfig(__dirname); - -module.exports = config; -``` - -### `android/app/build.gradle` - -The Android **app/build.gradle** must be configured to use Expo CLI for production bundling. Modify the `react` config object: - - - -### `ios/.xcodeproj/project.pbxproj` - -In your **ios/<Project>.xcodeproj/project.pbxproj** file, replace the following scripts: - -#### "Start Packager" script - -Remove the **"Start Packager"** script. The dev server must be started with `npx expo` before/after running the app. - - - -#### "Bundle React Native code and images" script - - - -Alternatively, in the Xcode project, select the **"Bundle React Native code and images"** build phase and add the following modifications: - - - -> You can set `CLI_PATH`, `BUNDLE_COMMAND`, and `ENTRY_FILE` environment variables to overwrite these defaults. - -### Custom entry file - -By default, React Native only supports using a root `index.js` file as the entry file (or platform-specific variation like `index.ios.js`). Expo projects allow using any entry file, but this requires addition bare setup. - -#### Development - -Development mode entry files can be enabled by using the [`expo-dev-client`](../sdk/dev-client/) package. Alternatively you can add the following configuration: - - - - - -#### Production - -In your **ios/<Project>.xcodeproj/project.pbxproj** file, replace the **"Bundle React Native code and images"** script to set `$ENTRY_FILE` according using Metro: - - - -The Android **app/build.gradle** must be configured to use Metro module resolution to find the root entry file. Modify the `react` config object: - - diff --git a/docs/pages/versions/v53.0.0/config/package-json.mdx b/docs/pages/versions/v53.0.0/config/package-json.mdx deleted file mode 100644 index 0229c98fb267e9..00000000000000 --- a/docs/pages/versions/v53.0.0/config/package-json.mdx +++ /dev/null @@ -1,105 +0,0 @@ ---- -title: package.json -description: A reference for Expo-specific properties that can be used in the package.json file. ---- - -import { PaddedAPIBox } from '~/components/plugins/PaddedAPIBox'; - -**package.json** is a JSON file that contains the metadata for a JavaScript project. This is a reference to Expo-specific properties that can be used in the **package.json** file. - - - -## `install.exclude` - -The following commands perform a version check for the libraries installed in a project and give a warning when a library's version is different from the version recommended by Expo: - -- `npx expo start` and `npx expo-doctor` -- `npx expo install` (when installing a new version of that library or using `--check` or `--fix` options) - -By specifying the library under the `install.exclude` array in the **package.json** file, you can exclude it from the version checks: - -```json package.json -{ - "expo": { - "install": { - "exclude": ["expo-updates", "expo-splash-screen"] - } - } -} -``` - - - - - -## `autolinking` - -Allows configuring module resolution behavior by using `autolinking` property in **package.json**. - -For complete reference, see [Autolinking configuration](/modules/autolinking/#configuration). - - - - - -## `doctor` - -Allows configuring the behavior of the [`npx expo-doctor`](/develop/tools/#expo-doctor) command. - - - -### `reactNativeDirectoryCheck` - -By default, Expo Doctor validates your project's packages against the [React Native directory](https://reactnative.directory/). This check throws a warning with a list of packages that are not included in the React Native Directory. - -You can customize this check by adding the following configuration in your project's **package.json** file: - -```json package.json -{ - "expo": { - "doctor": { - "reactNativeDirectoryCheck": { - /* @info Use this option to disable/enable the check. */ - "enabled": true, - /* @end */ - /* @info Use this option to exclude specific packages. */ - "exclude": ["/foo/", "bar"], - /* @end */ - /* @info Use this option to disable/enable listing unknown packages. */ - "listUnknownPackages": true - /* @end */ - } - } - } -} -``` - -By default, the check is enabled and unknown packages are listed. - - - - - -### `appConfigFieldsNotSyncedCheck` - -Expo Doctor checks if your project includes native project directories such as **android** or **ios**. If these directories exist but are not listed in your **.gitignore** or [**.easignore**](/build-reference/easignore) files, Expo Doctor verifies the presence of an app config file. If this file exists, it means your project is configured to use [Prebuild](/more/glossary-of-terms/#prebuild). - -When the **android** or **ios** directories are present, EAS Build does not sync app config properties to the native projects. Expo Doctor throws a warning if these conditions are true. - -You can disable or enable this check by adding the following configuration to your project's **package.json** file: - -```json package.json -{ - "expo": { - "doctor": { - "appConfigFieldsNotSyncedCheck": { - "enabled": false - } - } - } -} -``` - - - - diff --git a/docs/pages/versions/v53.0.0/index.mdx b/docs/pages/versions/v53.0.0/index.mdx deleted file mode 100644 index 0777391afeb226..00000000000000 --- a/docs/pages/versions/v53.0.0/index.mdx +++ /dev/null @@ -1,131 +0,0 @@ ---- -title: Expo SDK reference -description: Access device and system functionality in your Expo and React Native apps using Expo SDK packages. -hideTOC: true ---- - -import { BookOpen02Icon } from '@expo/styleguide-icons/outline/BookOpen02Icon'; - -import { BoxLink } from '~/ui/components/BoxLink'; -import { Collapsible } from '~/ui/components/Collapsible'; -import RedirectNotification from '~/ui/components/RedirectNotification'; -import { - AndroidIOSCompatibilityTable, - ReactNativeCompatibilityTable, -} from '~/ui/components/SDKTables'; -import { Terminal } from '~/ui/components/Snippet'; -import { CODE } from '~/ui/components/Text'; - - - The page you are looking for does not exist in this SDK version. It may have been deprecated or - added to a newer SDK version. - - -The Expo SDK is a collection of packages that provide access to device and system functionality such as camera, contacts, location, sensors, haptics, and more. Each package targets a specific feature and can be used independently. All packages work in any React Native app with the `expo` package installed. - -You can install any Expo SDK package using the [`npx expo install`](/more/expo-cli/#install) command. For example, three different packages are installed using the following command: - - - -After installing one or more packages, you can import them into your JavaScript code: - -```js -import { CameraView } from 'expo-camera'; -import * as Contacts from 'expo-contacts'; -import { Gyroscope } from 'expo-sensors'; -``` - -This allows you to write [`Contacts.getContactsAsync()`](./sdk/contacts#contactsgetcontactsasynccontactquery) and read the contacts from the device, read the gyroscope sensor to detect device movement, or start the phone's camera and take photos. - -## All Expo SDK packages work in any React Native app - -Expo apps are React Native apps, so all Expo SDK packages work in any React Native app with the `expo` package installed and configured. The easiest way to create a React Native app with support for Expo SDK packages is to use `create-expo-app`. However, you can also add Expo SDK support to an existing React Native app with the `npx install-expo-modules` command. - - - - - Learn more about configuring projects created with{' '} - npx @react-native-community/cli@latest init to Expo SDK packages. - - } - Icon={BookOpen02Icon} -/> - - - -## Using pre-release versions - -New Expo SDK versions are released three times each year. Between these releases, we publish pre-release versions of the `expo` package and all of the Expo SDK packages. Pre-releases are not considered stable and should only be used if you are comfortable with the risk of encountering bugs or other issues. - -### Canary releases - -Canary releases represent a snapshot of the state of the `main` branch at the time they are published. Canary package versions include `-canary` in the name, along with the date and commit hash, such as `53.0.0-canary-20240418-8d74597`. To install the latest canary release: - - - -You can often use pre-release versions of individual packages with stable releases of the Expo SDK. There may occasionally be incompatibilities or other issues that arise in canary-quality releases. You may want to [silence dependency validation warnings](/more/expo-cli/#configuring-dependency-validation) if you opt in to the canary package and once you have verified that it works well for your use cases. - -### Beta releases - -Before each Expo SDK release, we publish beta versions of the `expo` package and all of the Expo SDK packages. Beta releases are considered much more stable than canary releases, and we encourage developers to try them out on their apps and share their feedback. Beta releases use the `beta` tag on npm and follow the instructions in the related [changelog](https://expo.dev/changelog) post. - -## Each Expo SDK version depends on a React Native version - - - -### Additional information - - - -- Expo SDK versions are released three times each year, and each Expo SDK release targets a single React Native version. This is typically the latest stable version at the time of the release. -- The release cadence of React Native has varied over its history and it is currently on pace for six releases in 2025. While on this cadence, you can expect that there will be an Expo SDK version for every second React Native release. -- Pre-release versions of the upcoming Expo SDK will include support for the latest version of React Native quickly, usually the same day it is released. A member of the Expo SDK team works on the React Native releases team for each release, and is responsible for continuously updating the React Native version in the Expo repository, verifying compatibility, and reporting regressions back to the team at Meta. - - - - - -At Expo, we have found that releasing three major version provides a good balance of stability and innovation for developers depending on our open source tools. Expo and Meta work closely together on releases, and we will keep improving our processes to get the latest Expo and React Native features to you as quickly as possible. - - - - -We work closely with the team at Meta to ensure that any urgent fixes are included in the React Native version used by the latest Expo SDK. If your issue won't be cherrypicked into an existing release because it is more niche, or it involves a breaking change, then you have two options: - -1. Use [`patch-package`](https://github.com/ds300/patch-package) to pull in the fix. -2. Use a [pre-release version of the Expo SDK](#using-pre-release-versions). An ([example](https://expo.dev/changelog/react-native-78)). - - - - - -Packages in the Expo SDK are intended to support the target React Native version for that SDK. Typically, they will not support older versions of React Native, but they may. When a new version of React Native is released, the latest versions of the Expo SDK packages are typically updated to support it. However, this may take weeks or more, depending on the extent of the changes in the release. - - - -## Support for Android and iOS versions - -Each version of Expo SDK supports a minimum OS version of Android and iOS. For Android, the `compileSdkVersion` is defined which tells the [Gradle](https://developer.android.com/studio/build) which Android SDK version to use to compile the app. This also means that you can use the Android API features included in that SDK version and from the previous versions. For iOS, the [Xcode](https://developer.apple.com/news/upcoming-requirements/) tells the minimum Xcode SDK version to use to compile the app. - - - -When deciding whether to upgrade your Expo SDK version, consider both Expo's SDK version and app store submission requirements, as described in the above table. Google Play Store and Apple App Store periodically increase their minimum required OS versions and API levels, which are required for new app submissions. Expo has no control over the app store requirements, and you should check [Google](https://developer.android.com/studio/build) and [Apple](https://developer.apple.com/news/upcoming-requirements/) for the current store submission requirements. diff --git a/docs/pages/versions/v53.0.0/sdk/accelerometer.mdx b/docs/pages/versions/v53.0.0/sdk/accelerometer.mdx deleted file mode 100644 index 3586296cc5cc5a..00000000000000 --- a/docs/pages/versions/v53.0.0/sdk/accelerometer.mdx +++ /dev/null @@ -1,112 +0,0 @@ ---- -title: Accelerometer -description: A library that provides access to the device's accelerometer sensor. -sourceCodeUrl: 'https://github.com/expo/expo/tree/sdk-53/packages/expo-sensors' -packageName: 'expo-sensors' -iconUrl: '/static/images/packages/expo-sensors.png' -platforms: ['android', 'ios*', 'web', 'expo-go'] ---- - -import APISection from '~/components/plugins/APISection'; -import { APIInstallSection } from '~/components/plugins/InstallSection'; -import { SnackInline } from '~/ui/components/Snippet'; - -`Accelerometer` from `expo-sensors` provides access to the device accelerometer sensor(s) and associated listeners to respond to changes in acceleration in three-dimensional space, meaning any movement or vibration. - -## Installation - - - -## Usage - - - -```jsx -import { useState, useEffect } from 'react'; -import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'; -import { Accelerometer } from 'expo-sensors'; - -export default function App() { - const [{ x, y, z }, setData] = useState({ - x: 0, - y: 0, - z: 0, - }); - const [subscription, setSubscription] = useState(null); - - const _slow = () => Accelerometer.setUpdateInterval(1000); - const _fast = () => Accelerometer.setUpdateInterval(16); - - const _subscribe = () => { - setSubscription(Accelerometer.addListener(setData)); - }; - - const _unsubscribe = () => { - subscription && subscription.remove(); - setSubscription(null); - }; - - useEffect(() => { - _subscribe(); - return () => _unsubscribe(); - }, []); - - return ( - - Accelerometer: (in gs where 1g = 9.81 m/s^2) - x: {x} - y: {y} - z: {z} - - - {subscription ? 'On' : 'Off'} - - - Slow - - - Fast - - - - ); -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - paddingHorizontal: 20, - }, - text: { - textAlign: 'center', - }, - buttonContainer: { - flexDirection: 'row', - alignItems: 'stretch', - marginTop: 15, - }, - button: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - backgroundColor: '#eee', - padding: 10, - }, - middleButton: { - borderLeftWidth: 1, - borderRightWidth: 1, - borderColor: '#ccc', - }, -}); -``` - - - -## API - -```js -import { Accelerometer } from 'expo-sensors'; -``` - - diff --git a/docs/pages/versions/v53.0.0/sdk/apple-authentication.mdx b/docs/pages/versions/v53.0.0/sdk/apple-authentication.mdx deleted file mode 100644 index de1bfda165c9da..00000000000000 --- a/docs/pages/versions/v53.0.0/sdk/apple-authentication.mdx +++ /dev/null @@ -1,160 +0,0 @@ ---- -title: AppleAuthentication -description: A library that provides Sign-in with Apple capability for iOS. -sourceCodeUrl: 'https://github.com/expo/expo/tree/sdk-53/packages/expo-apple-authentication' -packageName: 'expo-apple-authentication' -platforms: ['ios', 'tvos', 'expo-go'] ---- - -import APISection from '~/components/plugins/APISection'; -import { APIInstallSection } from '~/components/plugins/InstallSection'; -import { ConfigReactNative, ConfigPluginExample } from '~/ui/components/ConfigSection'; -import { SnackInline } from '~/ui/components/Snippet'; - -`expo-apple-authentication` provides Apple authentication for iOS. It does not yet support Android or web. - -Any app that includes third-party authentication options **must** provide Apple authentication as an option to comply with App Store Review guidelines. For more information, see Apple authentication on the [Sign In with Apple](https://developer.apple.com/sign-in-with-apple/) website. - -## Installation - - - -## Configuration in app config - -You can configure `expo-apple-authentication` using its built-in [config plugin](/config-plugins/introduction/) if you use config plugins in your project ([Continuous Native Generation (CNG)](/workflow/continuous-native-generation/)). The plugin allows you to configure various properties that cannot be set at runtime and require building a new app binary to take effect. If your app does **not** use CNG, then you'll need to manually configure the library. - -### Setup iOS project - -To enable the **Sign In with Apple** capability in your app, set the [`ios.usesAppleSignIn`](../config/app/#usesapplesignin) property to `true` in your project's app config: - -```json app.json -{ - "expo": { - "ios": { - "usesAppleSignIn": true - } - } -} -``` - - - -Running [EAS Build](/build/introduction) locally will use [iOS capabilities signing](/build-reference/ios-capabilities) to enable the required capabilities before building. - -```json app.json -{ - "expo": { - "plugins": ["expo-apple-authentication"] - } -} -``` - - - - - -Apps that don't use [EAS Build](/build/introduction) must [manually configure](/build-reference/ios-capabilities#manual-setup) the **Apple Sign In** capability for their bundle identifier. - -If you enable the **Apple Sign In** capability through the [Apple Developer Console](/build-reference/ios-capabilities#apple-developer-console), then be sure to add the following entitlements in your **ios/[app]/[app].entitlements** file: - -```xml -com.apple.developer.applesignin - - Default - -``` - -Also, set `CFBundleAllowMixedLocalizations` to `true` in your **ios/[app]/Info.plist** to ensure the sign-in button uses the device locale. - - - -## Usage - - - -```jsx -import * as AppleAuthentication from 'expo-apple-authentication'; -import { View, StyleSheet } from 'react-native'; - -export default function App() { - return ( - - { - try { - const credential = await AppleAuthentication.signInAsync({ - requestedScopes: [ - AppleAuthentication.AppleAuthenticationScope.FULL_NAME, - AppleAuthentication.AppleAuthenticationScope.EMAIL, - ], - }); - // signed in - } catch (e) { - if (e.code === 'ERR_REQUEST_CANCELED') { - // handle that the user canceled the sign-in flow - } else { - // handle other errors - } - } - }} - /> - - ); -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - alignItems: 'center', - justifyContent: 'center', - }, - button: { - width: 200, - height: 44, - }, -}); -``` - - - -## Development and testing - -You can test this library in Expo Go on iOS without following any of the instructions above. -However, you'll need to add the config plugin to use this library if you are using EAS Build. -When you sign into Expo Go, the identifiers and values you receive will likely be different than what you'll receive in standalone apps. - -You can do limited testing of this library on the iOS Simulator. However, not all methods will behave the same as on a device, -so we highly recommend testing on a real device when possible while developing. - -## Verifying the Response from Apple - -Apple's response includes a signed JWT with information about the user. To ensure that the response came from Apple, -you can cryptographically verify the signature with Apple's public key, which is published at https://appleid.apple.com/auth/keys. -This process is not specific to Expo. - -## API - -```js -import * as AppleAuthentication from 'expo-apple-authentication'; -``` - - - -## Error codes - -Most of the error codes match the official [Apple Authorization errors](https://developer.apple.com/documentation/authenticationservices/asauthorizationerror/code). - -| Code | Description | -| --------------------------- | ----------------------------------------------------------------------------------- | -| ERR_INVALID_OPERATION | An invalid authorization operation has been performed. | -| ERR_INVALID_RESPONSE | The authorization request received an invalid response. | -| ERR_INVALID_SCOPE | An invalid [`AppleAuthenticationScope`](#appleauthenticationscope) was passed in. | -| ERR_REQUEST_CANCELED | The user canceled the authorization attempt. | -| ERR_REQUEST_FAILED | The authorization attempt failed. See the error message for additional information. | -| ERR_REQUEST_NOT_HANDLED | The authorization request wasn't correctly handled. | -| ERR_REQUEST_NOT_INTERACTIVE | The authorization request isn't interactive. | -| ERR_REQUEST_UNKNOWN | The authorization attempt failed for an unknown reason. | diff --git a/docs/pages/versions/v53.0.0/sdk/application.mdx b/docs/pages/versions/v53.0.0/sdk/application.mdx deleted file mode 100644 index 7e54ed911e34d9..00000000000000 --- a/docs/pages/versions/v53.0.0/sdk/application.mdx +++ /dev/null @@ -1,35 +0,0 @@ ---- -title: Application -description: A universal library that provides information about the native application's ID, app name, and build version at runtime. -sourceCodeUrl: 'https://github.com/expo/expo/tree/sdk-53/packages/expo-application' -packageName: 'expo-application' -platforms: ['android', 'ios', 'web', 'tvos', 'expo-go'] ---- - -import APISection from '~/components/plugins/APISection'; -import { APIInstallSection } from '~/components/plugins/InstallSection'; - -`expo-application` provides useful information about the native application's ID, app name, and build version at runtime. - -## Installation - - - -## API - -```js -import * as Application from 'expo-application'; -``` - - - -## Error codes - -| Code | Description | -| ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `ERR_APPLICATION_PACKAGE_NAME_NOT_FOUND` | Error code thrown by `getInstallationTimeAsync` and `getLastUpdateTimeAsync`. This may be thrown if the package information or package name could not be retrieved. | -| `ERR_APPLICATION_INSTALL_REFERRER_UNAVAILABLE` | The current Play Store app doesn't provide the installation referrer API, or the Play Store may not be installed. This error code may come up when testing on an AVD that doesn't come with the Play Store pre-installed, such as the Google Pixel 3 and Nexus 6. | -| `ERR_APPLICATION_INSTALL_REFERRER_CONNECTION` | A connection could not be established to the Google Play Store. | -| `ERR_APPLICATION_INSTALL_REFERRER_REMOTE_EXCEPTION` | A `RemoteException` was thrown after a connection was established to the Play Store. This may happen if the process hosting the remote object is no longer available, which usually means the process crashed. See [this StackOverflow answer on `RemoteException`](https://stackoverflow.com/questions/3156389/android-remoteexceptions-and-services) for more information. | -| `ERR_APPLICATION_INSTALL_REFERRER` | General default case error code for the `getInstallReferrerAsync` method. This error code will be thrown if an exception occurred when getting the install referrer, but the exception was none of the more precise errors. The [`responseCode`](https://developer.android.com/reference/com/android/installreferrer/api/InstallReferrerClient.InstallReferrerResponse.html) is provided along with the error. | -| `ERR_APPLICATION_INSTALL_REFERRER_SERVICE_DISCONNECTED` | Connection to the install referrer service was lost. This error is thrown when an attempt was made to connect and set up the install referrer service, but the connection was lost. See the [Android documentation](https://developer.android.com/reference/com/android/installreferrer/api/InstallReferrerStateListener) for more information. | diff --git a/docs/pages/versions/v53.0.0/sdk/asset.mdx b/docs/pages/versions/v53.0.0/sdk/asset.mdx deleted file mode 100644 index 064ea9bb416b62..00000000000000 --- a/docs/pages/versions/v53.0.0/sdk/asset.mdx +++ /dev/null @@ -1,71 +0,0 @@ ---- -title: Asset -description: A universal library that allows downloading assets and using them with other libraries. -sourceCodeUrl: 'https://github.com/expo/expo/tree/sdk-53/packages/expo-asset' -packageName: 'expo-asset' -platforms: ['android', 'ios', 'tvos', 'web', 'expo-go'] ---- - -import APISection from '~/components/plugins/APISection'; -import { APIInstallSection } from '~/components/plugins/InstallSection'; -import { ConfigPluginExample, ConfigPluginProperties } from '~/ui/components/ConfigSection'; - -`expo-asset` provides an interface to Expo's asset system. An asset is any file that lives alongside the source code of your app that the app needs at runtime. Examples include images, fonts, and sounds. Expo's asset system integrates with React Native's, so that you can refer to files with `require('path/to/file')`. This is how you refer to static image files in React Native for use in an `Image` component, for example. Check out React Native's [documentation on static image resources](https://reactnative.dev/docs/images#static-image-resources) for more information. This method of referring to static image resources works out of the box with Expo. - -## Installation - - - -## Configuration in app config - -You can configure `expo-asset` using its built-in [config plugin](/config-plugins/introduction/) if you use config plugins in your project ([Continuous Native Generation (CNG)](/workflow/continuous-native-generation/)). The plugin allows you to configure various properties that cannot be set at runtime and require building a new app binary to take effect. If your app does **not** use CNG, then you'll need to manually configure the library. - - - -```json app.json -{ - "expo": { - "plugins": [ - [ - "expo-asset", - { - "assets": ["path/to/file.png", "path/to/directory"] - } - ] - ] - } -} -``` - - - - **Note**: To import an existing database file (`.db`), see instructions in [SQLite API reference](./sqlite/#import-an-existing-database). For other file types (such as `.lottie` or `.riv`), see [how to add a file extension to `assetExts` in metro config](/guides/customizing-metro/#adding-more-file-extensions-to-assetexts).', - ].join('\n'), - default: '[]', - }, - ]} -/> - -### Usage - -Learn more about how to use the `expo-asset` config plugin to embed an asset file in your project in [Load an asset at build time](/develop/user-interface/assets/#load-an-asset-at-build-time). - -## API - -```js -import { Asset } from 'expo-asset'; -``` - - diff --git a/docs/pages/versions/v53.0.0/sdk/async-storage.mdx b/docs/pages/versions/v53.0.0/sdk/async-storage.mdx deleted file mode 100644 index 073a566e501701..00000000000000 --- a/docs/pages/versions/v53.0.0/sdk/async-storage.mdx +++ /dev/null @@ -1,28 +0,0 @@ ---- -title: '@react-native-async-storage/async-storage' -description: A library that provides an asynchronous, unencrypted, persistent, key-value storage API. -sourceCodeUrl: 'https://github.com/react-native-async-storage/async-storage' -packageName: '@react-native-async-storage/async-storage' -platforms: ['android', 'ios', 'tvos', 'macos', 'web', 'expo-go'] -inExpoGo: true ---- - -import { BookOpen02Icon } from '@expo/styleguide-icons/outline/BookOpen02Icon'; - -import { APIInstallSection } from '~/components/plugins/InstallSection'; -import { BoxLink } from '~/ui/components/BoxLink'; - -Async Storage is asynchronous, unencrypted, persistent, key-value storage solution. - -## Installation - - - -## Learn more - - diff --git a/docs/pages/versions/v53.0.0/sdk/audio-av.mdx b/docs/pages/versions/v53.0.0/sdk/audio-av.mdx deleted file mode 100644 index f3dd0933082f60..00000000000000 --- a/docs/pages/versions/v53.0.0/sdk/audio-av.mdx +++ /dev/null @@ -1,198 +0,0 @@ ---- -title: Audio (expo-av) -description: A library that provides an API to implement audio playback and recording in apps. -sourceCodeUrl: 'https://github.com/expo/expo/tree/sdk-53/packages/expo-av' -packageName: 'expo-av' -iconUrl: '/static/images/packages/expo-av.png' -platforms: ['android', 'ios', 'tvos', 'web'] -isDeprecated: true ---- - -import APISection from '~/components/plugins/APISection'; -import { APIInstallSection } from '~/components/plugins/InstallSection'; -import { SnackInline } from '~/ui/components/Snippet'; -import { PlatformTags } from '~/ui/components/Tag/PlatformTags'; - -> **warning** **Deprecated:** The `Audio` component from `expo-av`, which is documented on this page, has now been deprecated and replaced by an improved version in `expo-audio`. [Learn about `expo-audio`](./audio/). - -`Audio` from `expo-av` allows you to implement audio playback and recording in your app. - -Note that audio automatically stops if headphones/bluetooth audio devices are disconnected. - -See the [playlist example app](https://github.com/expo/playlist-example) for an example on the media playback API, and the [recording example app](https://github.com/expo/audio-recording-example) for an example of the recording API. - -## Installation - - - -## Usage - -### Playing sounds - - - -```jsx -import { useEffect, useState } from 'react'; -import { View, StyleSheet, Button } from 'react-native'; -import { Audio } from 'expo-av'; - -export default function App() { - const [sound, setSound] = useState(); - - async function playSound() { - console.log('Loading Sound'); - /* @info */ const { sound } = await Audio.Sound.createAsync( - /* @end */ require('./assets/Hello.mp3') - ); - setSound(sound); - - console.log('Playing Sound'); - await /* @info */ sound.playAsync(); /* @end */ - } - - useEffect(() => { - return sound - ? () => { - console.log('Unloading Sound'); - /* @info Always unload the Sound after using it to prevent memory leaks.*/ sound.unloadAsync(); /* @end */ - } - : undefined; - }, [sound]); - - return ( - - -``` - *See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/button)* - - - -### CircularProgress - - - - - - - ```tsx - import { CircularProgress } from '@expo/ui/swift-ui'; - - - ``` - *See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/progressview)* - - - - -### ColorPicker - - - - - - - - -```tsx -import { ColorPicker } from '@expo/ui/swift-ui'; - - -``` - *See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/colorpicker)* - - - -### ContextMenu - -> **Note:** Also known as **DropdownMenu**. - - - - - - - ```tsx - import { ContextMenu } from '@expo/ui/swift-ui'; - - - - - - setSelectedIndex(index)} - /> - - - - - - ``` - *See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/contextmenu(menuitems:))* - - - - -### DateTimePicker (date) - - - - - - -```tsx -import { DateTimePicker } from '@expo/ui/swift-ui'; - - { - setSelectedDate(date); - }} - displayedComponents='date' - initialDate={selectedDate.toISOString()} - variant='wheel' -/> -``` - *See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/datepicker)* - - - -### DateTimePicker (time) - - - - - - - ```tsx - import { DateTimePicker } from '@expo/ui/swift-ui'; - - { - setSelectedDate(date); - }} - displayedComponents='hourAndMinute' - initialDate={selectedDate.toISOString()} - variant='wheel' - /> - ``` - *See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/datepicker)* - - - - -### Gauge - - - - - - - -```tsx -import { Gauge } from "@expo/ui/swift-ui"; - - -``` - *See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/gauge)* - - - -### LinearProgress - - - - - - -```tsx -import { LinearProgress } from '@expo/ui/swift-ui'; - - -``` - *See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/progressview)* - - - -### List - - - - - - - ```tsx - import { List } from '@expo/ui/swift-ui'; - - alert(`indexes of selected items: ${items.join(', ')}`)} - moveEnabled={moveEnabled} - onMoveItem={(from, to) => alert(`moved item at index ${from} to index ${to}`)} - onDeleteItem={(item) => alert(`deleted item at index: ${item}`)} - style={{ flex: 1 }} - listStyle='automatic' - deleteEnabled={deleteEnabled} - selectEnabled={selectEnabled}> - {data.map((item, index) => ( - - ))} - - ``` - *See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/list)* - - - - -### Picker (segmented) - - - - - - -```tsx -import { Picker } from '@expo/ui/swift-ui'; - - { - setSelectedIndex(index); - }} - variant="segmented" - /> - ``` - *See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/picker#Styling-pickers)* - - - -### Picker (wheel) - - - - - - -```tsx -import { Picker } from '@expo/ui/swift-ui'; - - { - setSelectedIndex(index); - }} - variant="wheel" - style={{ - height: 100, - }} -/> -``` - *See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/pickerstyle/wheel)* - - - -### Slider - - - - - - - ```tsx - import { Slider } from '@expo/ui/swift-ui'; - - { - setValue(value); - }} - /> - ``` - *See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/slider)* - - - - -### Switch (toggle) - -> **Note:** Also known as **Toggle**. - - - - - - -```tsx -import { Switch } from '@expo/ui/swift-ui'; - - { - setChecked(checked); - }} - color="#ff0000" - label="Play music" - variant="switch" -/> -``` - *See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/toggle)* - - - -### Switch (checkbox) - - - - - - -```tsx -import { Switch } from '@expo/ui/swift-ui'; - - { - setChecked(checked); - }} - label="Play music" - variant="checkbox" -/> -``` - *See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/toggle)* - - - -### TextInput - - - - - - - ```tsx - import { TextInput } from '@expo/ui/swift-ui'; - - - ``` - *See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/textfield)* - - - - -## Jetpack Compose examples - -### Button - - - - - - -```tsx -import { Button } from '@expo/ui/jetpack-compose'; - - -``` -*See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/components/button)* - - - -### CircularProgress - - - - - - - ```tsx - import { CircularProgress } from '@expo/ui/jetpack-compose'; - - - ``` - *See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/components/progress)* - - - - -### ContextMenu - -> **Note:** Also known as **DropdownMenu**. - - - - - - - ```tsx - import { ContextMenu } from '@expo/ui/jetpack-compose'; - - - - - - setSelectedIndex(index)} - /> - - - - - - ``` - *See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/components/menu)* - - - - -### DateTimePicker (date) - - - - - - -```tsx -import { DateTimePicker } from '@expo/ui/jetpack-compose'; - - { - setSelectedDate(date); - }} - displayedComponents='date' - initialDate={selectedDate.toISOString()} - variant='picker' -/> -``` - *See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/components/datepickers)* - - - -### DateTimePicker (time) - - - - - - - ```tsx - import { DateTimePicker } from '@expo/ui/jetpack-compose'; - - { - setSelectedDate(date); - }} - displayedComponents='hourAndMinute' - initialDate={selectedDate.toISOString()} - variant='picker' - /> - ``` - *See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/components/time-pickers)* - - - - -### LinearProgress - - - - - - - ```tsx - import { LinearProgress } from '@expo/ui/jetpack-compose'; - - - ``` - *See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/components/progress)* - - - - -### Picker (radio) - - - - - - - ```tsx - import { Picker } from '@expo/ui/jetpack-compose'; - - { - setSelectedIndex(index); - }} - variant="radio" - /> - ``` - *See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/components/radio-button)* - - - - -### Picker (segmented) - - - - - - -```tsx -import { Picker } from '@expo/ui/jetpack-compose'; - - { - setSelectedIndex(index); - }} - variant="segmented" -/> -``` - *See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/components/segmented-button)* - - - -### Slider - - - - - - - ```tsx - import { Slider } from '@expo/ui/jetpack-compose'; - - { - setValue(value); - }} - /> - ``` - *See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/components/slider)* - - - - -### Switch (toggle) - -> **Note:** Also known as **Toggle**. - - - - - - - - ```tsx - import { Switch } from '@expo/ui/jetpack-compose'; - - { - setChecked(checked); - }} - color="#ff0000" - label="Play music" - variant="switch" - /> - ``` - *See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/components/switch)* - - - - -### Switch (checkbox) - - - - - - - - ```tsx - import { Switch } from '@expo/ui/jetpack-compose'; - - { - setChecked(checked); - }} - label="Play music" - color="#ff0000" - variant="checkbox" - /> - ``` - *See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/components/checkbox)* - - - - -### TextInput - - - - - - - ```tsx - import { TextInput } from '@expo/ui/jetpack-compose'; - - - ``` - *See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/text/user-input)* - - - - -## API - -Full documentation is not yet available. Use TypeScript types to explore the API. - -```ts -// Import from the SwiftUI package -import { BottomSheet } from '@expo/ui/swift-ui'; -``` - -```ts -// Import from the Jetpack Compose package -import { Button } from '@expo/ui/jetpack-compose'; -``` - -{/* */} diff --git a/docs/pages/versions/v53.0.0/sdk/updates.mdx b/docs/pages/versions/v53.0.0/sdk/updates.mdx deleted file mode 100644 index 466689f36d7f5d..00000000000000 --- a/docs/pages/versions/v53.0.0/sdk/updates.mdx +++ /dev/null @@ -1,286 +0,0 @@ ---- -title: Updates -description: A library that enables your app to manage remote updates to your application code. -sourceCodeUrl: 'https://github.com/expo/expo/tree/sdk-53/packages/expo-updates' -packageName: 'expo-updates' -iconUrl: '/static/images/packages/expo-updates.png' -platforms: ['android', 'ios', 'tvos', 'expo-go'] -searchRank: 100 -searchPosition: 1 ---- - -import { GithubIcon } from '@expo/styleguide-icons/custom/GithubIcon'; - -import APISection from '~/components/plugins/APISection'; -import { APIInstallSection } from '~/components/plugins/InstallSection'; -import { BoxLink } from '~/ui/components/BoxLink'; -import { Collapsible } from '~/ui/components/Collapsible'; -import { YesIcon, NoIcon } from '~/ui/components/DocIcons'; - -`expo-updates` is a library that enables your app to manage remote updates to your application code. It communicates with the configured remote update service to get information about available updates. - -## Installation - -The `expo-updates` library can be automatically configured using [EAS Update](/eas-update/introduction/), which is a hosted service that manages and serves updates to your app. To get started with EAS Update, follow the instructions in the [Get started](/eas-update/getting-started/) guide. - -Alternatively, it is also possible to configure the `expo-updates` library manually in cases where a different remote update service is required or configuration is only specified in native files. - - - - - -If you're installing this library in a [bare React Native app](/bare/overview/) or a generic app with manually configured native code, follow these [installation instructions](/bare/installing-updates/). - -If using [app config](/workflow/configuration/) for configuration, this library can be configured by setting at least the following app config properties: - -- [`updates.url`](../config/app/#updates): a URL of a remote service implementing the [Expo Updates protocol](/technical-specs/expo-updates-1/) -- [`runtimeVersion`](../config/app/#runtimeversion): a [runtime version](#runtime-version) - -The remote service must implement the [Expo Updates protocol](/technical-specs/expo-updates-1/). [EAS Update](/eas-update/introduction) is one such service, but it is also possible to use this library with a custom server. - - - - - -## Configuration - -There are build-time configuration options that control the behavior of the library. For most apps, these configuration values are set in the [app config](/workflow/configuration/) under the [`updates` property](../config/app/#updates). - -| [App config property](../config/app/#updates) | Default | Required? | iOS plist/dictionary key | Android meta-data name | Android Map key | -| ----------------------------------------------------------------------------------- | -------- | ----------- | -------------------------------------- | ---------------------------------------------------------------- | ----------------------------- | -| [`updates.enabled`](../config/app/#enabled) | `true` | | `EXUpdatesEnabled` | `expo.modules.updates.ENABLED` | `enabled` | -| [`updates.url`](../config/app/#url) | (none) | | `EXUpdatesURL` | `expo.modules.updates.EXPO_UPDATE_URL` | `updateUrl` | -| [`updates.requestHeaders`](../config/app/#requestheaders) | (none) | | `EXUpdatesRequestHeaders` | `expo.modules.updates.UPDATES_CONFIGURATION_REQUEST_HEADERS_KEY` | `requestHeaders` | -| [`runtimeVersion`](../config/app/#runtimeversion) | (none) | | `EXUpdatesRuntimeVersion` | `expo.modules.updates.EXPO_RUNTIME_VERSION` | `runtimeVersion` | -| [`updates.checkAutomatically`](../config/app/#checkautomatically) | `ALWAYS` | | `EXUpdatesCheckOnLaunch` | `expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH` | `checkOnLaunch` | -| [`updates.fallbackToCacheTimeout`](../config/app/#fallbacktocachetimeout) | `0` | | `EXUpdatesLaunchWaitMs` | `expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS` | `launchWaitMs` | -| [`updates.useEmbeddedUpdate`](../config/app/#useembeddedupdate) | `true` | | `EXUpdatesHasEmbeddedUpdate` | `expo.modules.updates.HAS_EMBEDDED_UPDATE` | `hasEmbeddedUpdate` | -| [`updates.codeSigningCertificate`](../config/app/#codesigningcertificate) | (none) | | `EXUpdatesCodeSigningCertificate` | `expo.modules.updates.CODE_SIGNING_CERTIFICATE` | `codeSigningCertificate` | -| [`updates.codeSigningMetadata`](../config/app/#codesigningmetadata) | (none) | | `EXUpdatesCodeSigningMetadata` | `expo.modules.updates.CODE_SIGNING_METADATA` | `codeSigningMetadata` | -| [`updates.assetPatternsToBeBundled`](../config/app/#assetpatternstobebundled) | (none) | | N/A | N/A | N/A | -| [`updates.disableAntiBrickingMeasures`](../config/app/#disableantibrickingmeasures) | `false` | | `EXUpdatesDisableAntiBrickingMeasures` | `expo.modules.updates. DISABLE_ANTI_BRICKING_MEASURES` | `disableAntiBrickingMeasures` | - -The two core required configuration options are: - -- [`updates.url`](../config/app/#updates): the URL at which the library fetches remote updates -- [`runtimeVersion`](../config/app/#runtimeversion): a [runtime version](#runtime-version) - -These are configured automatically when following the EAS Update [Get started](/eas-update/getting-started/) guide. - -#### Runtime version - -Each time you build a binary for your app it includes the native code and configuration present at the time of the build as well as native configuration, and this unique combination is represented by a string called a runtime version. A remote update targets one runtime version, indicating that only binaries with a matching runtime version can load the remote update. - - - -The runtime version can be managed manually by setting the string value in the config field. - -```json -{ - "expo": { - "runtimeVersion": "" - } -} -``` - - - - - -Runtime version policies derive the runtime version from another piece of information already present in your project. They can be set in the [`runtimeVersion`](../config/app/#runtimeversion) config field as follows: - -```json -{ - "expo": { - "runtimeVersion": { - "policy": "" - } - } -} -``` - -Available policy types: - - - -The `"appVersion"` policy is provided for projects with that wish to define their runtime compatibility based on the app version. - -For example, in a project that has the following in its app config: - -```json -{ - "expo": { - "runtimeVersion": { - "policy": "appVersion" - }, - "version": "1.0.0", - "ios": { - "buildNumber": "1" - }, - "android": { - "versionCode": 1 - } - } -} -``` - -The `"appVersion"` policy will set the runtime version to the project's current `"version"` property. In this case, the runtime version for the Android and iOS builds and any updates would be `"1.0.0"`. - -This policy is great for projects that contain custom native code and that update the `"version"` field after every public release. To submit an app, the app stores require an updated native version number for each submitted build, which makes this policy convenient if you want to be sure that every version installed on user devices has a different runtime version. - -When using this policy, you need to manually update `"version"` field in the app config every time there is a public release, but for Play Store's Internal Test Track and the App Store's TestFlight uploads, you can rely on `"autoIncrement"` option in **eas.json** to [manage versions for you](/build-reference/app-versions/#remote-version-source). - - - - - -The `"nativeVersion"` policy is provided for projects that wish to define their runtime compatibility based on the project's current `"version"` and `"versionCode"` (Android) or `"buildNumber"` (iOS) properties. - -For example, in a project that has the following in its app config: - -```json -{ - "expo": { - "runtimeVersion": { - "policy": "nativeVersion" - }, - "version": "1.0.0", - "ios": { - "buildNumber": "1" - }, - "android": { - "versionCode": 1 - } - } -} -``` - -The runtime version for the Android and iOS builds and any updates would be the combination of `"[version]([buildNumber|versionCode])"`, which in this case would be `"1.0.0(1)"`. - -This policy is great for projects containing custom native code that update the native version numbers (`"buildNumber"` for iOS and `"versionCode"` for Android) for each build. To submit an app, the app stores require an updated native version number for each submitted build, which makes this policy convenient if you want to be sure that every app uploaded to the Play Store's Internal Test Track and the App Store's TestFlight distribution tools has a different `runtimeVersion`. - -It's important to know that this policy requires management of the native version numbers manually between each build. - -Also, if you select a different native version between Android and iOS, you'll end up with builds and updates with separate runtime versions. - - - - - -The `"fingerprint"` runtime version policy automatically calculates the runtime version for you, including through changes like SDK upgrades or adding custom native code. - -```json -{ - "expo": { - "runtimeVersion": { - "policy": "fingerprint" - } - } -} -``` - -This policy works for both projects with and without custom native code. It works by using the [`@expo/fingerprint`](fingerprint) package to calculate the hash of your project during builds and updates to determine build-update compatibility (also known as the runtime). - - - - - -#### Native configuration and overriding - -If your project does not use Continuous Native Generation, these configuration values may also be set in your app's native configuration files or overridden during initialization in native code. - - - -On Android, these options are set as `meta-data` tags in the **AndroidManifest.xml** file (adjacent to the tags added during installation if auto-setup was used). You can also set or override them at runtime using `UpdatesController.overrideConfiguration()`. - -On iOS, these properties are set as keys in the **Expo.plist** file. You can also set or override them at runtime by calling `AppController.overrideConfiguration`. - - - -If your iOS native code or `AppDelegate.mm` is written in Objective-C++, you will need to add the following imports to reference methods on `EXUpdatesAppController`. This is only necessary for overriding configuration at runtime. - -```objc -#import "ExpoModulesCore-Swift.h" -#import "EXUpdatesInterface-Swift.h" -#import "EXUpdates-Swift.h" -``` - - - - - -## Usage - -By default, `expo-updates` checks for updates when the app launches. If an update is available, it downloads the update and applies it the next time the app is restarted. You can tune this startup behavior using the `checkAutomatically` and `fallbackToCacheTimeout` configuration options above. - -The library also provides a variety of constants to inspect the current update and functions to customize update behavior from your application code (after startup). For example, one common alternative usage pattern is to manually check for updates after the app has started instead of doing the default check on launch. - - - -You can configure your app to check for updates manually by doing the following steps: - -1. Set the `checkAutomatically` configuration value to `ON_ERROR_RECOVERY` or `NEVER` to disable the library's default launch behavior. -2. Add the following code to check for available updates, download them, and reload: - - ```jsx App.js - import { View, Button } from 'react-native'; - import * as Updates from 'expo-updates'; - - function App() { - async function onFetchUpdateAsync() { - try { - const update = await Updates.checkForUpdateAsync(); - - if (update.isAvailable) { - await Updates.fetchUpdateAsync(); - await Updates.reloadAsync(); - } - } catch (error) { - // You can also add an alert() to see the error message in case of an error when fetching updates. - alert(`Error fetching latest Expo update: ${error}`); - } - } - - return ( - -