Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions .github/actions/expo-caches/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,12 +194,28 @@ runs:
shell: bash
run: sudo $ANDROID_SDK_ROOT/tools/bin/sdkmanager --install "ndk;${{ inputs.ndk-version }}"

- name: ♻️ Restore ccache
if: inputs.ccache == 'true'
- name: 🔍️ Get Xcode version for iOS ccache key
if: inputs.ccache == 'true' && runner.os == 'macOS'
id: xcode-version
shell: bash
run: echo "hash=$(xcodebuild -version | md5)" >> $GITHUB_OUTPUT

- name: ♻️ Restore ccache (iOS)
if: inputs.ccache == 'true' && runner.os == 'macOS'
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/.ccache
# It is necessary to include Xcode version in the cache key, because each Xcode version introduces changes to clang compiler,
# which is a part of ccache hashes. After an Xcode version change the hit rate would drop to 0% until a new cache is built.
key: ${{ runner.os }}-ccache-${{ steps.xcode-version.outputs.hash }}-${{ hashFiles('**/Podfile.lock', 'yarn.lock', 'packages/**/*.c', 'packages/**/*.cpp', 'packages/**/*.h', 'packages/**/*.mm', 'packages/**/*.m') }}
restore-keys: ${{ runner.os }}-ccache-${{ steps.xcode-version.outputs.hash }}-

- name: ♻️ Restore ccache (Android)
if: inputs.ccache == 'true' && runner.os == 'Linux'
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/.ccache
key: ${{ runner.os }}-ccache-${{ hashFiles('yarn.lock', 'packages/**/*.cpp', 'packages/**/*.h', 'packages/**/*.mm', 'packages/**/*.m') }}
key: ${{ runner.os }}-ccache-${{ hashFiles('yarn.lock', 'packages/**/*.c', 'packages/**/*.cpp', 'packages/**/*.h') }}
restore-keys: ${{ runner.os }}-ccache-

- name: 🔍️ Get cache key of Git LFS files
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ class ExponentManifest @Inject constructor(

// NavigationBar
const val MANIFEST_NAVIGATION_BAR_KEY = "androidNavigationBar"
const val MANIFEST_NAVIGATION_BAR_VISIBLILITY = "visible"
const val MANIFEST_NAVIGATION_BAR_VISIBILITY = "visible"
const val MANIFEST_NAVIGATION_BAR_APPEARANCE = "barStyle"
const val MANIFEST_NAVIGATION_BAR_BACKGROUND_COLOR = "backgroundColor"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ object ExperienceActivityUtils {
fun configureStatusBar(manifest: Manifest, activity: Activity) {
val statusBarOptions = manifest.getAndroidStatusBarOptions()
val statusBarStyle = statusBarOptions?.getNullable<String>(ExponentManifest.MANIFEST_STATUS_BAR_APPEARANCE)
val statusBarBackgroundColor = statusBarOptions?.getNullable<String>(ExponentManifest.MANIFEST_STATUS_BAR_BACKGROUND_COLOR)

val statusBarHidden = statusBarOptions != null && statusBarOptions.optBoolean(
ExponentManifest.MANIFEST_STATUS_BAR_HIDDEN,
Expand All @@ -113,38 +112,9 @@ object ExperienceActivityUtils {

setTranslucent(activity)

val appliedStatusBarStyle = setStyle(statusBarStyle, activity)
setStyle(statusBarStyle, activity)

// Color passed from manifest is in format '#RRGGBB(AA)' and Android uses '#AARRGGBB'
val normalizedStatusBarBackgroundColor = RGBAtoARGB(statusBarBackgroundColor)

if (normalizedStatusBarBackgroundColor == null || !ColorParser.isValid(normalizedStatusBarBackgroundColor)) {
// backgroundColor is invalid or not set
if (appliedStatusBarStyle == STATUS_BAR_STYLE_LIGHT_CONTENT) {
// appliedStatusBarStyle is "light-content" so background color should be semi transparent black
setColor(Color.parseColor("#88000000"), activity)
} else {
// otherwise it has to be transparent
setColor(Color.TRANSPARENT, activity)
}
} else {
setColor(Color.parseColor(normalizedStatusBarBackgroundColor), activity)
}
}
}

/**
* If the string conforms to the "#RRGGBBAA" format then it's converted into the "#AARRGGBB" format.
* Otherwise noop.
*/
private fun RGBAtoARGB(rgba: String?): String? {
if (rgba == null) {
return null
}
return if (rgba.startsWith("#") && rgba.length == 9) {
"#" + rgba.substring(7, 9) + rgba.substring(1, 7)
} else {
rgba
setColor(Color.TRANSPARENT, activity)
}
}

Expand Down Expand Up @@ -178,28 +148,16 @@ object ExperienceActivityUtils {
* @return Effective style that is actually applied to the status bar.
*/
@UiThread
private fun setStyle(style: String?, activity: Activity): String {
var appliedStatusBarStyle = STATUS_BAR_STYLE_LIGHT_CONTENT
private fun setStyle(style: String?, activity: Activity) {
val decorView = activity.window.decorView
var systemUiVisibilityFlags = decorView.systemUiVisibility
when (style) {
STATUS_BAR_STYLE_LIGHT_CONTENT -> {
systemUiVisibilityFlags =
systemUiVisibilityFlags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
appliedStatusBarStyle = STATUS_BAR_STYLE_LIGHT_CONTENT
}
STATUS_BAR_STYLE_DARK_CONTENT -> {
systemUiVisibilityFlags = systemUiVisibilityFlags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
appliedStatusBarStyle = STATUS_BAR_STYLE_DARK_CONTENT
}
else -> {
systemUiVisibilityFlags = systemUiVisibilityFlags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
appliedStatusBarStyle = STATUS_BAR_STYLE_DARK_CONTENT
}
decorView.systemUiVisibility = when (style) {
STATUS_BAR_STYLE_LIGHT_CONTENT ->
decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
STATUS_BAR_STYLE_DARK_CONTENT ->
decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
else ->
decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
}
decorView.systemUiVisibility = systemUiVisibilityFlags

return appliedStatusBarStyle
}

@UiThread
Expand Down Expand Up @@ -246,17 +204,6 @@ object ExperienceActivityUtils {
fun setNavigationBar(manifest: Manifest, activity: Activity) {
val navBarOptions = manifest.getAndroidNavigationBarOptions() ?: return

// Set background color of navigation bar
val navBarColor = navBarOptions.getNullable<String>(ExponentManifest.MANIFEST_NAVIGATION_BAR_BACKGROUND_COLOR)
if (navBarColor != null && ColorParser.isValid(navBarColor)) {
try {
activity.window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
activity.window.navigationBarColor = Color.parseColor(navBarColor)
} catch (e: Throwable) {
EXL.e(TAG, e)
}
}

// Set icon color of navigation bar
val navBarAppearance = navBarOptions.getNullable<String>(ExponentManifest.MANIFEST_NAVIGATION_BAR_APPEARANCE)
if (navBarAppearance != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Expand All @@ -275,7 +222,7 @@ object ExperienceActivityUtils {
}

// Set visibility of navigation bar
val navBarVisible = navBarOptions.getNullable<String>(ExponentManifest.MANIFEST_NAVIGATION_BAR_VISIBLILITY)
val navBarVisible = navBarOptions.getNullable<String>(ExponentManifest.MANIFEST_NAVIGATION_BAR_VISIBILITY)
if (navBarVisible != null) {
// Hide both the navigation bar and the status bar. The Android docs recommend, "you should
// design your app to hide the status bar whenever you hide the navigation bar."
Expand Down
2 changes: 1 addition & 1 deletion docs/pages/build-reference/git-submodules.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ To initialize a submodule on EAS Build builder:

<Step label="1">

Create a [secret](/build-reference/variables/#using-secrets-in-environment-variables) with a base64 encoded private SSH key that has permission to access submodule repositories.
Create a [secret](/eas/environment-variables/#visibility-settings-for-environment-variables) with a base64 encoded private SSH key that has permission to access submodule repositories.

</Step>

Expand Down
2 changes: 1 addition & 1 deletion docs/pages/build-reference/private-npm-packages.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ The recommended way is to add the `NPM_TOKEN` secret to your account or project'
src="/static/images/eas-build/environment-secrets/secrets-create-filled.png"
/>

For more information on how to do that, see [secret environment variables](/build-reference/variables/#secrets-on-the-expo-website).
For more information on how to do that, see [secret environment variables](/eas/environment-variables/manage/#create-variables-in-the-dashboard).

When EAS detects that the `NPM_TOKEN` environment variable is available during a build, it automatically creates the following **.npmrc**:

Expand Down
4 changes: 2 additions & 2 deletions docs/pages/build-reference/troubleshooting.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ If your project imports a file listed in **.gitignore**, the build will fail wit

- Encode the file with `base64`, save that string as secrets, and create the file in an EAS Build hook. See [How can I upload files to EAS Build if they are gitignored?](https://expo.fyi/eas-build-archive.md#how-can-i-upload-files-to-eas-build-if-they-are-gitignored) for more information.

- Refactor your source code to avoid importing sensitive files on the client side. If a file is an auto-generated code from a third-party provider and that provider has automatically listed files in your **.gitignore**, then that file probably contains sensitive information. You should not include it on the client side. During app development, ensure you follow secure practices, such as using environment variables or serving them through your backend. See [Using secrets in environment variables](/build-reference/variables/#using-secrets-in-environment-variables) for more information.
- Refactor your source code to avoid importing sensitive files on the client side. If a file is an auto-generated code from a third-party provider and that provider has automatically listed files in your **.gitignore**, then that file probably contains sensitive information. You should not include it on the client side. During app development, ensure you follow secure practices, such as using environment variables or serving them through your backend. See [Using secrets in environment variables](/eas/environment-variables/#visibility-settings-for-environment-variables) for more information.

</Collapsible>

Expand Down Expand Up @@ -149,7 +149,7 @@ You can build the production bundle locally by running `npx expo export` to bypa
If the logs weren't enough to immediately help you understand and fix the root cause, it's time to try to reproduce the issue locally. If your project builds and runs locally in release mode then it will also build on EAS Build, provided that the following are all true:

- Relevant [Build tool versions](/build/eas-json#configuring-your-build-tools) (for example, Xcode, Node.js, npm, Yarn) are the same in both environments.
- Relevant [environment variables](/build-reference/variables) are the same in both environments.
- Relevant [environment variables](/eas/environment-variables) are the same in both environments.
- The [archive](https://expo.fyi/eas-build-archive) that is uploaded to EAS Build includes the same relevant source files.

You can verify that your project builds on your local machine with the `npx expo run:android` and `npx expo run:ios` commands, with variant/configuration flags set to release to most faithfully reproduce what executes on EAS Build. For more information, see [Android build process](/build-reference/android-builds) and [iOS build process](/build-reference/ios-builds).
Expand Down
2 changes: 1 addition & 1 deletion docs/pages/build/eas-json.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ You can configure environment variables on your build profiles using the `"env"`
}
```

The [Environment variables and secrets](/build-reference/variables) reference explains this topic in greater detail, and the [Use EAS Update](/build/updates) guide provides considerations when using this feature alongside `expo-updates`.
The [Environment variables and secrets](/eas/environment-variables) reference explains this topic in greater detail, and the [Use EAS Update](/build/updates) guide provides considerations when using this feature alongside `expo-updates`.

## More

Expand Down
2 changes: 1 addition & 1 deletion docs/pages/build/setup.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ For development, we recommend creating a [development build](/develop/developmen

Additional configuration may be required for some scenarios:

- Does your app code depend on environment variables? [Add them to your build configuration](/build-reference/variables).
- Does your app code depend on environment variables? [Add them to your build configuration](/eas/environment-variables).
- Is your project inside of a monorepo? [Follow these instructions](/build-reference/build-with-monorepos).
- Do you use private npm packages? [Add your npm token](/build-reference/private-npm-packages).
- Does your app depend on specific versions of tools like Node, Yarn, npm, CocoaPods, or Xcode? [Specify these versions in your build configuration](/build/eas-json).
Expand Down
2 changes: 1 addition & 1 deletion docs/pages/guides/environment-variables.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ If you're experiencing issues with environment variables, you can try disabling

### EAS Build

[EAS Build](/build/introduction/) uses Metro Bundler to build the JavaScript bundle embedded within your app binary, so it will use **.env** files uploaded with your build job to inline `EXPO_PUBLIC_` variables into your code. EAS Build also lets you define environment variables within build profiles in **eas.json** and via EAS Secrets. Check out the EAS Build documentation on [environment variables and build secrets](/build-reference/variables/) for more information.
[EAS Build](/build/introduction/) uses Metro Bundler to build the JavaScript bundle embedded within your app binary, so it will use **.env** files uploaded with your build job to inline `EXPO_PUBLIC_` variables into your code. EAS Build also lets you define environment variables within build profiles in **eas.json** and via EAS Secrets. Check out the EAS Build documentation on [environment variables and build secrets](/eas/environment-variables) for more information.

### EAS Update

Expand Down
18 changes: 9 additions & 9 deletions docs/pages/router/migrate/from-react-navigation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -201,11 +201,11 @@ Instead, migrate `navigation` to the `useRouter` hook.

<DiffBlock source="/static/diffs/router/migrate-from-react-navigation/use-router-hook.diff" />

Similarly, migrate from the `route` prop to the [`useLocalSearchParams`](/router/reference/hooks/#uselocalsearchparams) hook.
Similarly, migrate from the `route` prop to the [`useLocalSearchParams`](/versions/latest/sdk/router/#uselocalsearchparams) hook.

<DiffBlock source="/static/diffs/router/migrate-from-react-navigation/use-local-search-params.diff" />

To access the [`navigation.navigate`](https://reactnavigation.org/docs/navigation-object/#navigate), import the `navigation` prop from [`useNavigation`](/router/reference/hooks/#usenavigation) hook.
To access the [`navigation.navigate`](https://reactnavigation.org/docs/navigation-object/#navigate), import the `navigation` prop from [`useNavigation`](/versions/latest/sdk/router/#usenavigation) hook.

<DiffBlock source="/static/diffs/router/migrate-from-react-navigation/use-navigation-hook.diff" />

Expand Down Expand Up @@ -277,23 +277,23 @@ Use `useRootNavigationState()`.

#### `getCurrentRoute`

Unlike React Navigation, Expo Router can reliably represent any route with a string. Use the [`usePathname()`](/router/reference/hooks/#usepathname) or [`useSegments()`](/router/reference/hooks/#usesegments) hooks to identify the current route.
Unlike React Navigation, Expo Router can reliably represent any route with a string. Use the [`usePathname()`](/versions/latest/sdk/router/#usepathname) or [`useSegments()`](/versions/latest/sdk/router/#usesegments) hooks to identify the current route.

#### `getCurrentOptions`

Use the [`useLocalSearchParams()`](/router/reference/hooks/#uselocalsearchparams) hook to get the current route's query parameters.
Use the [`useLocalSearchParams()`](/versions/latest/sdk/router/#uselocalsearchparams) hook to get the current route's query parameters.

#### `addListener`

The following events can be migrated:

#### `state`

Use the [`usePathname()`](/router/reference/hooks/#usepathname) or [`useSegments()`](/router/reference/hooks/#usesegments) hooks to identify the current route. Use in conjunction with `useEffect(() => {}, [...])` to observe changes.
Use the [`usePathname()`](/versions/latest/sdk/router/#usepathname) or [`useSegments()`](/versions/latest/sdk/router/#usesegments) hooks to identify the current route. Use in conjunction with `useEffect(() => {}, [...])` to observe changes.

#### `options`

Use the [`useLocalSearchParams()`](/router/reference/hooks/#uselocalsearchparams) hook to get the current route's query parameters. Use in conjunction with `useEffect(() => {}, [...])` to observe changes.
Use the [`useLocalSearchParams()`](/versions/latest/sdk/router/#uselocalsearchparams) hook to get the current route's query parameters. Use in conjunction with `useEffect(() => {}, [...])` to observe changes.

### props

Expand All @@ -307,7 +307,7 @@ Avoid using this pattern in favor of deep linking (for example, a user opens you

#### `onStateChange`

Use the [`usePathname()`](/router/reference/hooks/#usepathname), [`useSegments()`](/router/reference/hooks/#usesegments), and [`useGlobalSearchParams()`](/router/reference/hooks/#useglobalsearchparams) hooks to identify the current route state. Use in conjunction with `useEffect(() => {}, [...])` to observe changes.
Use the [`usePathname()`](/versions/latest/sdk/router/#usepathname), [`useSegments()`](/versions/latest/sdk/router/#usesegments), and [`useGlobalSearchParams()`](/versions/latest/sdk/router/#useglobalsearchparams) hooks to identify the current route state. Use in conjunction with `useEffect(() => {}, [...])` to observe changes.

- If you're attempting to track screen changes, follow the [Screen Tracking guide](/router/reference/screen-tracking/).
- React Navigation recommends avoiding [`onStateChange`](https://reactnavigation.org/docs/navigation-container/#onstatechange).
Expand Down Expand Up @@ -434,7 +434,7 @@ Expo Router wraps `expo-splash-screen` and adds special handling to ensure it's

### Navigation state observation

If you're observing the navigation state directly, migrate to the [`usePathname`](/router/reference/hooks/#usepathname), [`useSegments`](/router/reference/hooks/#usesegments), and [`useGlobalSearchParams`](/router/reference/hooks/#useglobalsearchparams) hooks.
If you're observing the navigation state directly, migrate to the [`usePathname`](/versions/latest/sdk/router/#usepathname), [`useSegments`](/versions/latest/sdk/router/#usesegments), and [`useGlobalSearchParams`](/versions/latest/sdk/router/#useglobalsearchparams) hooks.

### Pass params to nested screens

Expand All @@ -457,7 +457,7 @@ In React Navigation, you can use the `initialRouteName` property of the linking

### Reset navigation state

You can use the [`reset`](https://reactnavigation.org/docs/navigation-actions/#reset) action from the React Navigation library to reset the navigation state. It is dispatched using the [`useNavigation`](/router/reference/hooks/#usenavigation) hook from Expo Router to access the `navigation` prop.
You can use the [`reset`](https://reactnavigation.org/docs/navigation-actions/#reset) action from the React Navigation library to reset the navigation state. It is dispatched using the [`useNavigation`](/versions/latest/sdk/router/#usenavigation) hook from Expo Router to access the `navigation` prop.

In the below example, the `navigation` prop is accessible from the `useNavigation` hook and the `CommonActions.reset` action from `@react-navigation/native`. The object specified in the `reset` action replaces the existing navigation state with the new one.

Expand Down
Loading
Loading