首页指南参考教程

原生项目升级助手

查看你需要对原生项目进行的所有更改的逐个文件差异,以将其升级到下一个 Expo SDK 版本。


如果你管理你的原生项目(以前称为裸工作流),到 升级到最新的 Expo SDK,你必须对你的原生项目进行更改。查找哪些原生文件发生更改以及要更新哪个文件中的内容可能是一个复杂的过程。

¥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.

以下指南提供了比较项目当前 SDK 版本和要升级的目标 SDK 版本之间的原生项目文件的差异。你可以使用它们根据你的项目使用的 expo 软件包版本对你的项目进行更改。此页面上的工具与 React Native 升级助手 类似。然而,它们面向使用 Expo 模块和相关工具的项目。

¥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.

有兴趣完全避免升级原生代码吗?请参阅 持续的原生生成 (CNG) 了解 Expo Prebuild 如何在构建之前生成你的原生项目。

¥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

一旦你拥有 升级你的 Expo SDK 版本和相关依赖,请使用下面的 diff 工具来了解你需要对原生项目进行的更改,并将其更新为当前的 Expo SDK 版本。

¥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.

选择你的 SDK 版本和 SDK 版本以查看生成的差异。然后,通过复制和粘贴或手动更改项目文件,将这些更改应用到你的原生项目。

¥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 50 to 51

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
728/**
829 * This is the configuration block to customize your React Native Android app.
930 * By default you don't need to apply any configuration, just uncomment the lines you need.
5778 //
5879 // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
5980 // hermesFlags = ["-O", "-output-source-map"]
81
82 if (rnVersion >= versionToNumber(0, 75, 0)) {
83 /* Autolinking */
84 autolinkLibrariesWithApp()
85 }
6086}
6187
6288/**
90116 targetSdkVersion rootProject.ext.targetSdkVersion
91117 versionCode 1
92118 versionName "1.0"
93
94 buildConfigField("boolean", "REACT_NATIVE_UNSTABLE_USE_RUNTIME_SCHEDULER_ALWAYS", (findProperty("reactNative.unstable_useRuntimeSchedulerAlways") ?: true).toString())
95119 }
96120 signingConfigs {
97121 debug {
112136 shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false)
113137 minifyEnabled enableProguardInReleaseBuilds
114138 proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
139 crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true)
115140 }
116141 }
117142 packagingOptions {
163188 }
164189 }
165190
166 implementation("com.facebook.react:flipper-integration")
167
168191 if (hermesEnabled.toBoolean()) {
169192 implementation("com.facebook.react:hermes-android")
170193 } else {
172195 }
173196}
174197
175apply 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");
176applyNativeModulesAppBuildGradle(project)
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
1919 </queries>
2020
2121 <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">
22 <meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL" android:value="YOUR-APP-URL-HERE"/>
23 <meta-data android:name="expo.modules.updates.EXPO_SDK_VERSION" android:value="YOUR-APP-SDK-VERSION-HERE"/>
2422 <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">
2523 <intent-filter>
2624 <action android:name="android.intent.action.MAIN"/>
2927 </activity>
3028 <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" android:exported="false"/>
3129 </application>
32</manifest>
30</manifest>
android/app/src/main/java/com/helloworld/MainApplication.kt
MODIFIED
22
33import android.app.Application
44import android.content.res.Configuration
5import androidx.annotation.NonNull
65
76import com.facebook.react.PackageList
87import com.facebook.react.ReactApplication
98import com.facebook.react.ReactNativeHost
109import com.facebook.react.ReactPackage
1110import com.facebook.react.ReactHost
12import com.facebook.react.config.ReactFeatureFlags
1311import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
14import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
1512import com.facebook.react.defaults.DefaultReactNativeHost
16import com.facebook.react.flipper.ReactNativeFlipper
1713import com.facebook.soloader.SoLoader
1814
1915import expo.modules.ApplicationLifecycleDispatcher
4036 )
4137
4238 override val reactHost: ReactHost
43 get() = getDefaultReactHost(this.applicationContext, reactNativeHost)
39 get() = ReactNativeHostWrapper.createReactHost(applicationContext, reactNativeHost)
4440
4541 override fun onCreate() {
4642 super.onCreate()
4743 SoLoader.init(this, false)
48 if (!BuildConfig.REACT_NATIVE_UNSTABLE_USE_RUNTIME_SCHEDULER_ALWAYS) {
49 ReactFeatureFlags.unstable_useRuntimeSchedulerAlways = false
50 }
5144 if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
5245 // If you opted-in for the New Architecture, we load the native entry point for this app.
5346 load()
5447 }
55 if (BuildConfig.DEBUG) {
56 ReactNativeFlipper.initializeFlipper(this, reactNativeHost.reactInstanceManager)
57 }
5848 ApplicationLifecycleDispatcher.onApplicationCreate(this)
5949 }
6050
android/app/src/main/res/drawable/rn_edit_text_material.xml
MODIFIED
1717 android:insetLeft="@dimen/abc_edit_text_inset_horizontal_material"
1818 android:insetRight="@dimen/abc_edit_text_inset_horizontal_material"
1919 android:insetTop="@dimen/abc_edit_text_inset_top_material"
20 android:insetBottom="@dimen/abc_edit_text_inset_bottom_material">
20 android:insetBottom="@dimen/abc_edit_text_inset_bottom_material"
21 >
2122
2223 <selector>
2324 <!--
android/build.gradle
MODIFIED
66 minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '23')
77 compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '34')
88 targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '34')
9 kotlinVersion = findProperty('android.kotlinVersion') ?: '1.8.10'
9 kotlinVersion = findProperty('android.kotlinVersion') ?: '1.9.23'
1010
11 ndkVersion = "25.1.8937393"
11 ndkVersion = "26.1.10909125"
1212 }
1313 repositories {
1414 google()
1717 dependencies {
1818 classpath('com.android.tools.build:gradle')
1919 classpath('com.facebook.react:react-native-gradle-plugin')
20 classpath('org.jetbrains.kotlin:kotlin-gradle-plugin')
2021 }
2122}
2223
android/gradle.properties
MODIFIED
2525# Automatically convert third-party libraries to use AndroidX
2626android.enableJetifier=true
2727
28# Enable AAPT2 PNG crunching
29android.enablePngCrunchInReleaseBuilds=true
30
2831# Use this property to specify which architecture you want to build.
2932# You can also override it from the CLI using
3033# ./gradlew <task> -PreactNativeArchitectures=x86_64
android/gradlew.bat
MODIFIED
2626
2727set DIRNAME=%~dp0
2828if "%DIRNAME%"=="" set DIRNAME=.
29@rem This is normally unused
2930set APP_BASE_NAME=%~n0
3031set APP_HOME=%DIRNAME%
3132
4243%JAVA_EXE% -version >NUL 2>&1
4344if %ERRORLEVEL% equ 0 goto execute
4445
45echo.
46echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47echo.
48echo Please set the JAVA_HOME variable in your environment to match the
49echo location of your Java installation.
46echo. 1>&2
47echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
48echo. 1>&2
49echo Please set the JAVA_HOME variable in your environment to match the 1>&2
50echo location of your Java installation. 1>&2
5051
5152goto fail
5253
5657
5758if exist "%JAVA_EXE%" goto execute
5859
59echo.
60echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61echo.
62echo Please set the JAVA_HOME variable in your environment to match the
63echo location of your Java installation.
60echo. 1>&2
61echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
62echo. 1>&2
63echo Please set the JAVA_HOME variable in your environment to match the 1>&2
64echo location of your Java installation. 1>&2
6465
6566goto fail
6667
android/settings.gradle
MODIFIED
1pluginManagement {
2 includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json')"].execute(null, rootDir).text.trim()).getParentFile().toString())
3}
4plugins { id("com.facebook.react.settings") }
5
6def getRNMinorVersion() {
7 def version = providers.exec {
8 commandLine("node", "-e", "console.log(require('react-native/package.json').version);")
9 }.standardOutput.asText.get().trim()
10
11 def coreVersion = version.split("-")[0]
12 def (major, minor, patch) = coreVersion.tokenize('.').collect { it.toInteger() }
13
14 return minor
15}
16
17if (getRNMinorVersion() >= 75) {
18 extensions.configure(com.facebook.react.ReactSettingsExtension){ ex ->
19 ex.autolinkLibrariesFromCommand()
20 }
21}
22
123rootProject.name = 'HelloWorld'
224
325dependencyResolutionManagement {
1133apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle");
1234useExpoModules()
1335
14apply 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");
15applyNativeModulesSettingsGradle(settings)
36if (getRNMinorVersion() < 75) {
37 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");
38 applyNativeModulesSettingsGradle(settings)
39}
1640
1741include ':app'
1842includeBuild(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
212212 );
213213 runOnlyForDeploymentPostprocessing = 0;
214214 shellPath = /bin/sh;
215 shellScript = "if [[ -f \"$PODS_ROOT/../.xcode.env\" ]]; then\n source \"$PODS_ROOT/../.xcode.env\"\nfi\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n# The project root by default is one level up from the ios directory\nexport PROJECT_ROOT=\"$PROJECT_DIR\"/..\n\nif [[ \"$CONFIGURATION\" = *Debug* ]]; then\n export SKIP_BUNDLING=1\nfi\nif [[ -z \"$ENTRY_FILE\" ]]; then\n # Set the entry JS file using the bundler's entry resolution.\n export ENTRY_FILE=\"$(\"$NODE_BINARY\" -e \"require('expo/scripts/resolveAppEntry')\" \"$PROJECT_ROOT\" ios relative | tail -n 1)\"\nfi\n\nif [[ -z \"$CLI_PATH\" ]]; then\n # Use Expo CLI\n export CLI_PATH=\"$(\"$NODE_BINARY\" --print \"require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })\")\"\nfi\nif [[ -z \"$BUNDLE_COMMAND\" ]]; then\n # Default Expo CLI command for bundling\n export BUNDLE_COMMAND=\"export:embed\"\nfi\n\n# Source .xcode.env.updates if it exists to allow\n# SKIP_BUNDLING to be unset if needed\nif [[ -f \"$PODS_ROOT/../.xcode.env.updates\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.updates\"\nfi\n# Source local changes to allow overrides\n# if needed\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n`\"$NODE_BINARY\" --print \"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/react-native-xcode.sh'\"`\n\n";
215 shellScript = "if [[ -f \"$PODS_ROOT/../.xcode.env\" ]]; then\n source \"$PODS_ROOT/../.xcode.env\"\nfi\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n# The project root by default is one level up from the ios directory\nexport PROJECT_ROOT=\"$PROJECT_DIR\"/..\n\nif [[ \"$CONFIGURATION\" = *Debug* ]]; then\n export SKIP_BUNDLING=1\nfi\nif [[ -z \"$ENTRY_FILE\" ]]; then\n # Set the entry JS file using the bundler's entry resolution.\n export ENTRY_FILE=\"$(\"$NODE_BINARY\" -e \"require('expo/scripts/resolveAppEntry')\" \"$PROJECT_ROOT\" ios absolute | tail -n 1)\"\nfi\n\nif [[ -z \"$CLI_PATH\" ]]; then\n # Use Expo CLI\n export CLI_PATH=\"$(\"$NODE_BINARY\" --print \"require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })\")\"\nfi\nif [[ -z \"$BUNDLE_COMMAND\" ]]; then\n # Default Expo CLI command for bundling\n export BUNDLE_COMMAND=\"export:embed\"\nfi\n\n# Source .xcode.env.updates if it exists to allow\n# SKIP_BUNDLING to be unset if needed\nif [[ -f \"$PODS_ROOT/../.xcode.env.updates\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.updates\"\nfi\n# Source local changes to allow overrides\n# if needed\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n`\"$NODE_BINARY\" --print \"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/react-native-xcode.sh'\"`\n\n";
216216 };
217217 08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */ = {
218218 isa = PBXShellScriptBuildPhase;
ios/HelloWorld/AppDelegate.mm
MODIFIED
1818
1919- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
2020{
21 return [self getBundleURL];
21 return [self bundleURL];
2222}
2323
24- (NSURL *)getBundleURL
24- (NSURL *)bundleURL
2525{
2626#if DEBUG
2727 return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@".expo/.virtual-metro-entry"];
ios/Podfile
MODIFIED
1313
1414prepare_react_native_project!
1515
16# If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set.
17# because `react-native-flipper` depends on (FlipperKit,...), which will be excluded. To fix this,
18# you can also exclude `react-native-flipper` in `react-native.config.js`
19#
20# ```js
21# module.exports = {
22# dependencies: {
23# ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}),
24# }
25# }
26# ```
27flipper_config = FlipperConfiguration.disabled
28if ENV['NO_FLIPPER'] == '1' then
29 # Explicitly disabled through environment variables
30 flipper_config = FlipperConfiguration.disabled
31elsif podfile_properties.key?('ios.flipper') then
32 # Configure Flipper in Podfile.properties.json
33 if podfile_properties['ios.flipper'] == 'true' then
34 flipper_config = FlipperConfiguration.enabled(["Debug", "Release"])
35 elsif podfile_properties['ios.flipper'] != 'false' then
36 flipper_config = FlipperConfiguration.enabled(["Debug", "Release"], { 'Flipper' => podfile_properties['ios.flipper'] })
37 end
38end
39
4016target 'HelloWorld' do
4117 use_expo_modules!
4218 config = use_native_modules!
4925 :hermes_enabled => podfile_properties['expo.jsEngine'] == nil || podfile_properties['expo.jsEngine'] == 'hermes',
5026 # An absolute path to your application root.
5127 :app_path => "#{Pod::Config.instance.installation_root}/..",
52 # Note that if you have use_frameworks! enabled, Flipper will not work if enabled
53 :flipper_configuration => flipper_config
28 :privacy_file_aggregation_enabled => podfile_properties['apple.privacyManifestAggregationEnabled'] != 'false',
5429 )
5530
5631 post_install do |installer|
5732 react_native_post_install(
5833 installer,
5934 config[:reactNativePath],
60 :mac_catalyst_enabled => false
35 :mac_catalyst_enabled => false,
36 :ccache_enabled => podfile_properties['apple.ccacheEnabled'] == 'true',
6137 )
6238
6339 # This is necessary for Xcode 14, because it signs resource bundles by default
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": "50.0.43",
4 "version": "51.0.51",
55 "main": "index.js",
66 "scripts": {
77 "start": "expo start --dev-client",
1010 "web": "expo start --web"
1111 },
1212 "dependencies": {
13 "expo": "~50.0.17",
14 "expo-status-bar": "~1.11.1",
13 "expo": "~51.0.26",
14 "expo-status-bar": "~1.12.1",
1515 "react": "18.2.0",
16 "react-native": "0.73.6"
16 "react-native": "0.74.5"
1717 },
1818 "devDependencies": {
1919 "@babel/core": "^7.20.0"
Expo 中文网 - 粤ICP备13048890号