Native project upgrade helper

Edit this page

View file-by-file diffs of all the changes you need to make to your native projects to upgrade them to the next Expo SDK version.


If you manage your native projects (previously known as bare workflow), to upgrade to the latest Expo SDK, you have to make changes to your native projects. It can be a complex process to find which native file changes and what to update in which file.

The following guide provides diffs to compare native project files between your project's current SDK version and the target SDK version you want to upgrade. You can use them to make changes to your project depending on the expo package version your project uses. The tools on this page are similar to React Native Upgrade Helper. However, they are oriented around projects that use Expo modules and related tooling.

Interested in avoiding upgrading native code altogether? See Continuous Native Generation (CNG) to learn how Expo Prebuild can generate your native projects before a build.

Upgrade native project files

Once you have upgraded your Expo SDK version and related dependencies, use the diff tool below to learn about changes you need to make to your native project and bring them up to date with the current Expo SDK version.

Choose your from SDK version and to SDK version to see the generated diff. Then, apply those changes to your native projects by copying and pasting or manually making changes to the project files.

From SDK version:

To SDK version:

Native code changes from SDK 51 to 52

android/app/build.gradle
MODIFIED
44
55def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath()
66
7static def versionToNumber(major, minor, patch) {
8 return patch * 100 + minor * 10000 + major * 1000000
9}
10
11def getRNVersion() {
12 def version = providers.exec {
13 workingDir(projectDir)
14 commandLine("node", "-e", "console.log(require('react-native/package.json').version);")
15 }.standardOutput.asText.get().trim()
16
17 def coreVersion = version.split("-")[0]
18 def (major, minor, patch) = coreVersion.tokenize('.').collect { it.toInteger() }
19
20 return versionToNumber(
21 major,
22 minor,
23 patch
24 )
25}
26def rnVersion = getRNVersion()
27
287/**
298 * This is the configuration block to customize your React Native Android app.
309 * By default you don't need to apply any configuration, just uncomment the lines you need.
4120 bundleCommand = "export:embed"
4221
4322 /* Folders */
44 // The root of your project, i.e. where "package.json" lives. Default is '..'
45 // root = file("../")
46 // The folder where the react-native NPM package is. Default is ../node_modules/react-native
47 // reactNativeDir = file("../node_modules/react-native")
48 // The folder where the react-native Codegen package is. Default is ../node_modules/@react-native/codegen
49 // codegenDir = file("../node_modules/@react-native/codegen")
23 // The root of your project, i.e. where "package.json" lives. Default is '../..'
24 // root = file("../../")
25 // The folder where the react-native NPM package is. Default is ../../node_modules/react-native
26 // reactNativeDir = file("../../node_modules/react-native")
27 // The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen
28 // codegenDir = file("../../node_modules/@react-native/codegen")
5029
5130 /* Variants */
5231 // The list of variants to that are debuggable. For those we're going to
7958 // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
8059 // hermesFlags = ["-O", "-output-source-map"]
8160
82 if (rnVersion >= versionToNumber(0, 75, 0)) {
83 /* Autolinking */
84 autolinkLibrariesWithApp()
85 }
61 /* Autolinking */
62 autolinkLibrariesWithApp()
8663}
8764
8865/**
144121 useLegacyPackaging (findProperty('expo.useLegacyPackaging')?.toBoolean() ?: false)
145122 }
146123 }
124 androidResources {
125 ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~'
126 }
147127}
148128
149129// Apply static values from `gradle.properties` to the `android.packagingOptions`
194174 implementation jscFlavor
195175 }
196176}
197
198if (rnVersion < versionToNumber(0, 75, 0)) {
199 apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim(), "../native_modules.gradle");
200 applyNativeModulesAppBuildGradle(project)
201}
android/app/src/main/AndroidManifest.xml
MODIFIED
1818 </intent>
1919 </queries>
2020
21 <application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="false" android:theme="@style/AppTheme">
21 <application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="false" android:theme="@style/AppTheme" android:supportsRtl="true">
2222 <activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true">
2323 <intent-filter>
2424 <action android:name="android.intent.action.MAIN"/>
android/app/src/main/java/com/helloworld/MainApplication.kt
MODIFIED
1010import com.facebook.react.ReactHost
1111import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
1212import com.facebook.react.defaults.DefaultReactNativeHost
13import com.facebook.react.soloader.OpenSourceMergedSoMapping
1314import com.facebook.soloader.SoLoader
1415
1516import expo.modules.ApplicationLifecycleDispatcher
2122 this,
2223 object : DefaultReactNativeHost(this) {
2324 override fun getPackages(): List<ReactPackage> {
25 val packages = PackageList(this).packages
2426 // Packages that cannot be autolinked yet can be added manually here, for example:
2527 // packages.add(new MyReactNativePackage());
26 return PackageList(this).packages
28 return packages
2729 }
2830
2931 override fun getJSMainModuleName(): String = ".expo/.virtual-metro-entry"
4042
4143 override fun onCreate() {
4244 super.onCreate()
43 SoLoader.init(this, false)
45 SoLoader.init(this, OpenSourceMergedSoMapping)
4446 if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
4547 // If you opted-in for the New Architecture, we load the native entry point for this app.
4648 load()
android/build.gradle
MODIFIED
22
33buildscript {
44 ext {
5 buildToolsVersion = findProperty('android.buildToolsVersion') ?: '34.0.0'
6 minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '23')
7 compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '34')
5 buildToolsVersion = findProperty('android.buildToolsVersion') ?: '35.0.0'
6 minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '24')
7 compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '35')
88 targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '34')
9 kotlinVersion = findProperty('android.kotlinVersion') ?: '1.9.23'
9 kotlinVersion = findProperty('android.kotlinVersion') ?: '1.9.24'
1010
1111 ndkVersion = "26.1.10909125"
1212 }
android/gradle.properties
MODIFIED
2222# https://developer.android.com/topic/libraries/support-library/androidx-rn
2323android.useAndroidX=true
2424
25# Automatically convert third-party libraries to use AndroidX
26android.enableJetifier=true
27
2825# Enable AAPT2 PNG crunching
2926android.enablePngCrunchInReleaseBuilds=true
3027
android/gradle/wrapper/gradle-wrapper.properties
MODIFIED
11distributionBase=GRADLE_USER_HOME
22distributionPath=wrapper/dists
3distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-all.zip
3distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
44networkTimeout=10000
55validateDistributionUrl=true
66zipStoreBase=GRADLE_USER_HOME
android/gradlew
MODIFIED
1515# See the License for the specific language governing permissions and
1616# limitations under the License.
1717#
18# SPDX-License-Identifier: Apache-2.0
19#
1820
1921##############################################################################
2022#
5557# Darwin, MinGW, and NonStop.
5658#
5759# (3) This script is generated from the Groovy template
58# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
60# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
5961# within the Gradle project.
6062#
6163# You can find Gradle at https://github.com/gradle/gradle/.
8486# shellcheck disable=SC2034
8587APP_BASE_NAME=${0##*/}
8688# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
87APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
89APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
90' "$PWD" ) || exit
8891
8992# Use the maximum available, or set MAX_FD != -1 to use that value.
9093MAX_FD=maximum
android/gradlew.bat
MODIFIED
1313@rem See the License for the specific language governing permissions and
1414@rem limitations under the License.
1515@rem
16@rem SPDX-License-Identifier: Apache-2.0
17@rem
1618
1719@if "%DEBUG%"=="" @echo off
1820@rem ##########################################################################
android/settings.gradle
MODIFIED
11pluginManagement {
2 def version = providers.exec {
3 commandLine("node", "-e", "console.log(require('react-native/package.json').version);")
4 }.standardOutput.asText.get().trim()
5 def (_, reactNativeMinor, reactNativePatch) = version.split("-")[0].tokenize('.').collect { it.toInteger() }
6
7 includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json')"].execute(null, rootDir).text.trim()).getParentFile().toString())
8 if(reactNativeMinor == 74 && reactNativePatch <= 3){
9 includeBuild("react-settings-plugin")
10 }
2 includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json')"].execute(null, rootDir).text.trim()).getParentFile().toString())
113}
12
134plugins { id("com.facebook.react.settings") }
145
15def getRNMinorVersion() {
16 def version = providers.exec {
17 commandLine("node", "-e", "console.log(require('react-native/package.json').version);")
18 }.standardOutput.asText.get().trim()
19
20 def coreVersion = version.split("-")[0]
21 def (major, minor, patch) = coreVersion.tokenize('.').collect { it.toInteger() }
22
23 return minor
24}
25
26if (getRNMinorVersion() >= 75) {
27 extensions.configure(com.facebook.react.ReactSettingsExtension) { ex ->
28 if (System.getenv('EXPO_UNSTABLE_CORE_AUTOLINKING') == '1') {
29 println('\u001B[32mUsing expo-modules-autolinking as core autolinking source\u001B[0m')
30 def command = [
31 'node',
32 '--no-warnings',
33 '--eval',
34 'require(require.resolve(\'expo-modules-autolinking\', { paths: [require.resolve(\'expo/package.json\')] }))(process.argv.slice(1))',
35 'react-native-config',
36 '--json',
37 '--platform',
38 'android'
39 ].toList()
40 ex.autolinkLibrariesFromCommand(command)
41 } else {
42 ex.autolinkLibrariesFromCommand()
43 }
6extensions.configure(com.facebook.react.ReactSettingsExtension) { ex ->
7 if (System.getenv('EXPO_USE_COMMUNITY_AUTOLINKING') == '1') {
8 ex.autolinkLibrariesFromCommand()
9 } else {
10 def command = [
11 'node',
12 '--no-warnings',
13 '--eval',
14 'require(require.resolve(\'expo-modules-autolinking\', { paths: [require.resolve(\'expo/package.json\')] }))(process.argv.slice(1))',
15 'react-native-config',
16 '--json',
17 '--platform',
18 'android'
19 ].toList()
20 ex.autolinkLibrariesFromCommand(command)
4421 }
4522}
4623
5734apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle");
5835useExpoModules()
5936
60if (getRNMinorVersion() < 75) {
61 apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim(), "../native_modules.gradle");
62 applyNativeModulesSettingsGradle(settings)
63}
64
6537include ':app'
6638includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile())
ios/HelloWorld.xcodeproj/project.pbxproj
MODIFIED
287287 "FB_SONARKIT_ENABLED=1",
288288 );
289289 INFOPLIST_FILE = HelloWorld/Info.plist;
290 IPHONEOS_DEPLOYMENT_TARGET = 13.4;
290 IPHONEOS_DEPLOYMENT_TARGET = 15.1;
291291 LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
292292 MARKETING_VERSION = 1.0;
293293 OTHER_LDFLAGS = (
311311 CLANG_ENABLE_MODULES = YES;
312312 CURRENT_PROJECT_VERSION = 1;
313313 INFOPLIST_FILE = HelloWorld/Info.plist;
314 IPHONEOS_DEPLOYMENT_TARGET = 13.4;
314 IPHONEOS_DEPLOYMENT_TARGET = 15.1;
315315 LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
316316 MARKETING_VERSION = 1.0;
317317 OTHER_LDFLAGS = (
373373 GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
374374 GCC_WARN_UNUSED_FUNCTION = YES;
375375 GCC_WARN_UNUSED_VARIABLE = YES;
376 IPHONEOS_DEPLOYMENT_TARGET = 13.4;
376 IPHONEOS_DEPLOYMENT_TARGET = 15.1;
377377 LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";
378378 LIBRARY_SEARCH_PATHS = "\"$(inherited)\"";
379379 MTL_ENABLE_DEBUG_INFO = YES;
422422 GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
423423 GCC_WARN_UNUSED_FUNCTION = YES;
424424 GCC_WARN_UNUSED_VARIABLE = YES;
425 IPHONEOS_DEPLOYMENT_TARGET = 13.4;
425 IPHONEOS_DEPLOYMENT_TARGET = 15.1;
426426 LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";
427427 LIBRARY_SEARCH_PATHS = "\"$(inherited)\"";
428428 MTL_ENABLE_DEBUG_INFO = NO;
ios/Podfile
MODIFIED
77ENV['RCT_NEW_ARCH_ENABLED'] = podfile_properties['newArchEnabled'] == 'true' ? '1' : '0'
88ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] = podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR']
99
10use_autolinking_method_symbol = ('use' + '_native' + '_modules!').to_sym
11origin_autolinking_method = self.method(use_autolinking_method_symbol)
12self.define_singleton_method(use_autolinking_method_symbol) do |*args|
13 if ENV['EXPO_UNSTABLE_CORE_AUTOLINKING'] == '1'
14 Pod::UI.puts('Using expo-modules-autolinking as core autolinking source'.green)
10platform :ios, podfile_properties['ios.deploymentTarget'] || '15.1'
11install! 'cocoapods',
12 :deterministic_uuids => false
13
14prepare_react_native_project!
15
16target 'HelloWorld' do
17 use_expo_modules!
18
19 if ENV['EXPO_USE_COMMUNITY_AUTOLINKING'] == '1'
20 config_command = ['node', '-e', "process.argv=['', '', 'config'];require('@react-native-community/cli').run()"];
21 else
1522 config_command = [
1623 'node',
1724 '--no-warnings',
2229 '--platform',
2330 'ios'
2431 ]
25 origin_autolinking_method.call(config_command)
26 else
27 origin_autolinking_method.call()
2832 end
29end
3033
31platform :ios, podfile_properties['ios.deploymentTarget'] || '13.4'
32install! 'cocoapods',
33 :deterministic_uuids => false
34
35prepare_react_native_project!
36
37target 'HelloWorld' do
38 use_expo_modules!
39 config = use_native_modules!
34 config = use_native_modules!(config_command)
4035
4136 use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']
4237 use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS']
6863 end
6964 end
7065 end
71
72 post_integrate do |installer|
73 begin
74 expo_patch_react_imports!(installer)
75 rescue => e
76 Pod::UI.warn e
77 end
78 end
7966end
package.json
MODIFIED
11{
22 "name": "expo-template-bare-minimum",
33 "description": "This bare project template includes a minimal setup for using unimodules with React Native.",
4 "version": "51.0.56",
4 "license": "0BSD",
5 "version": "52.0.2",
56 "main": "index.js",
67 "scripts": {
78 "start": "expo start --dev-client",
1011 "web": "expo start --web"
1112 },
1213 "dependencies": {
13 "expo": "~51.0.28",
14 "expo-status-bar": "~1.12.1",
15 "react": "18.2.0",
16 "react-native": "0.74.5"
14 "expo": "~52.0.0-preview.2",
15 "expo-status-bar": "~2.0.0",
16 "react": "18.3.1",
17 "react-native": "0.76.0"
1718 },
1819 "devDependencies": {
1920 "@babel/core": "^7.20.0"