原生项目升级助手 查看你需要对原生项目进行的所有更改的逐个文件差异,以将其升级到下一个 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.
Native code changes from SDK 50 to 51 22 22 android/app/build 23 23 android/.gradle 24 24 ios/.xcode.env.local 25 26 # Exclude tarballs generated by `npm pack` 27 /*.tgz
android/app/build.gradle MODIFIED
4 4 5 5 def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath() 6 6 7 static def versionToNumber(major, minor, patch) { 8 return patch * 100 + minor * 10000 + major * 1000000 9 } 10 11 def 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 } 26 def rnVersion = getRNVersion() 27 7 28 /** 8 29 * This is the configuration block to customize your React Native Android app. 9 30 * By default you don't need to apply any configuration, just uncomment the lines you need. 57 78 // 58 79 // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" 59 80 // hermesFlags = ["-O", "-output-source-map"] 81 82 if (rnVersion >= versionToNumber(0, 75, 0)) { 83 /* Autolinking */ 84 autolinkLibrariesWithApp() 85 } 60 86 } 61 87 62 88 /** 90 116 targetSdkVersion rootProject.ext.targetSdkVersion 91 117 versionCode 1 92 118 versionName "1.0" 93 94 buildConfigField("boolean", "REACT_NATIVE_UNSTABLE_USE_RUNTIME_SCHEDULER_ALWAYS", (findProperty("reactNative.unstable_useRuntimeSchedulerAlways") ?: true).toString()) 95 119 } 96 120 signingConfigs { 97 121 debug { 112 136 shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false) 113 137 minifyEnabled enableProguardInReleaseBuilds 114 138 proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 139 crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true) 115 140 } 116 141 } 117 142 packagingOptions { 163 188 } 164 189 } 165 190 166 implementation("com.facebook.react:flipper-integration") 167 168 191 if (hermesEnabled.toBoolean()) { 169 192 implementation("com.facebook.react:hermes-android") 170 193 } else { 172 195 } 173 196 } 174 197 175 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"); 176 applyNativeModulesAppBuildGradle(project) 198 if (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
19 19 </queries> 20 20 21 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"> 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"/> 24 22 <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"> 25 23 <intent-filter> 26 24 <action android:name="android.intent.action.MAIN"/> 29 27 </activity> 30 28 <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" android:exported="false"/> 31 29 </application> 32 </manifest> 30 </manifest>
android/app/src/main/java/com/helloworld/MainApplication.kt MODIFIED
2 2 3 3 import android.app.Application 4 4 import android.content.res.Configuration 5 import androidx.annotation.NonNull 6 5 7 6 import com.facebook.react.PackageList 8 7 import com.facebook.react.ReactApplication 9 8 import com.facebook.react.ReactNativeHost 10 9 import com.facebook.react.ReactPackage 11 10 import com.facebook.react.ReactHost 12 import com.facebook.react.config.ReactFeatureFlags 13 11 import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load 14 import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost 15 12 import com.facebook.react.defaults.DefaultReactNativeHost 16 import com.facebook.react.flipper.ReactNativeFlipper 17 13 import com.facebook.soloader.SoLoader 18 14 19 15 import expo.modules.ApplicationLifecycleDispatcher 40 36 ) 41 37 42 38 override val reactHost: ReactHost 43 get() = getDefaultReactHost(this.applicationContext, reactNativeHost) 39 get() = ReactNativeHostWrapper.createReactHost(applicationContext, reactNativeHost) 44 40 45 41 override fun onCreate() { 46 42 super.onCreate() 47 43 SoLoader.init(this, false) 48 if (!BuildConfig.REACT_NATIVE_UNSTABLE_USE_RUNTIME_SCHEDULER_ALWAYS) { 49 ReactFeatureFlags.unstable_useRuntimeSchedulerAlways = false 50 } 51 44 if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { 52 45 // If you opted-in for the New Architecture, we load the native entry point for this app. 53 46 load() 54 47 } 55 if (BuildConfig.DEBUG) { 56 ReactNativeFlipper.initializeFlipper(this, reactNativeHost.reactInstanceManager) 57 } 58 48 ApplicationLifecycleDispatcher.onApplicationCreate(this) 59 49 } 60 50
android/app/src/main/res/drawable/rn_edit_text_material.xml MODIFIED
17 17 android:insetLeft="@dimen/abc_edit_text_inset_horizontal_material" 18 18 android:insetRight="@dimen/abc_edit_text_inset_horizontal_material" 19 19 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 > 21 22 22 23 <selector> 23 24 <!--
android/build.gradle MODIFIED
6 6 minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '23') 7 7 compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '34') 8 8 targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '34') 9 kotlinVersion = findProperty('android.kotlinVersion') ?: '1.8.10' 9 kotlinVersion = findProperty('android.kotlinVersion') ?: '1.9.23' 10 10 11 ndkVersion = "25.1.8937393" 11 ndkVersion = "26.1.10909125" 12 12 } 13 13 repositories { 14 14 google() 17 17 dependencies { 18 18 classpath('com.android.tools.build:gradle') 19 19 classpath('com.facebook.react:react-native-gradle-plugin') 20 classpath('org.jetbrains.kotlin:kotlin-gradle-plugin') 20 21 } 21 22 } 22 23
android/gradle.properties MODIFIED
25 25 # Automatically convert third-party libraries to use AndroidX 26 26 android.enableJetifier=true 27 27 28 # Enable AAPT2 PNG crunching 29 android.enablePngCrunchInReleaseBuilds=true 30 28 31 # Use this property to specify which architecture you want to build. 29 32 # You can also override it from the CLI using 30 33 # ./gradlew <task> -PreactNativeArchitectures=x86_64
android/gradle/wrapper/gradle-wrapper.properties MODIFIED
1 1 distributionBase=GRADLE_USER_HOME 2 2 distributionPath=wrapper/dists 3 distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip 3 distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-all.zip 4 4 networkTimeout=10000 5 5 validateDistributionUrl=true 6 6 zipStoreBase=GRADLE_USER_HOME
android/gradlew.bat MODIFIED
26 26
27 27 set DIRNAME=%~dp0
28 28 if "%DIRNAME%"=="" set DIRNAME=.
29 @rem This is normally unused
29 30 set APP_BASE_NAME=%~n0
30 31 set APP_HOME=%DIRNAME%
31 32
42 43 %JAVA_EXE% -version >NUL 2>&1
43 44 if %ERRORLEVEL% equ 0 goto execute
44 45
45 echo.
46 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 echo.
48 echo Please set the JAVA_HOME variable in your environment to match the
49 echo location of your Java installation.
46 echo. 1>&2
47 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
48 echo. 1>&2
49 echo Please set the JAVA_HOME variable in your environment to match the 1>&2
50 echo location of your Java installation. 1>&2
50 51
51 52 goto fail
52 53
56 57
57 58 if exist "%JAVA_EXE%" goto execute
58 59
59 echo.
60 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 echo.
62 echo Please set the JAVA_HOME variable in your environment to match the
63 echo location of your Java installation.
60 echo. 1>&2
61 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
62 echo. 1>&2
63 echo Please set the JAVA_HOME variable in your environment to match the 1>&2
64 echo location of your Java installation. 1>&2
64 65
65 66 goto fail
66 67
android/settings.gradle MODIFIED
1 pluginManagement { 2 includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json')"].execute(null, rootDir).text.trim()).getParentFile().toString()) 3 } 4 plugins { id("com.facebook.react.settings") } 5 6 def 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 17 if (getRNMinorVersion() >= 75) { 18 extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> 19 ex.autolinkLibrariesFromCommand() 20 } 21 } 22 1 23 rootProject.name = 'HelloWorld' 2 24 3 25 dependencyResolutionManagement { 11 33 apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle"); 12 34 useExpoModules() 13 35 14 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"); 15 applyNativeModulesSettingsGradle(settings) 36 if (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 } 16 40 17 41 include ':app' 18 42 includeBuild(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())
2 2 "expo": { 3 3 "name": "HelloWorld", 4 4 "slug": "expo-template-bare", 5 "version": "1.0.0", 6 "assetBundlePatterns": ["**/*"] 5 "version": "1.0.0" 7 6 } 8 7 }
ios/HelloWorld.xcodeproj/project.pbxproj MODIFIED
212 212 ); 213 213 runOnlyForDeploymentPostprocessing = 0; 214 214 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"; 216 216 }; 217 217 08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */ = { 218 218 isa = PBXShellScriptBuildPhase;
ios/HelloWorld/AppDelegate.mm MODIFIED
18 18 19 19 - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge 20 20 { 21 return [self getBundleURL]; 21 return [self bundleURL]; 22 22 } 23 23 24 - (NSURL *)getBundleURL 24 - (NSURL *)bundleURL 25 25 { 26 26 #if DEBUG 27 27 return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@".expo/.virtual-metro-entry"];
ios/HelloWorld/Info.plist MODIFIED
35 35 <string>SplashScreen</string> 36 36 <key>UIRequiredDeviceCapabilities</key> 37 37 <array> 38 <string>armv7</string> 38 <string>arm64</string> 39 39 </array> 40 40 <key>UIStatusBarStyle</key> 41 41 <string>UIStatusBarStyleDefault</string>
ios/HelloWorld/Supporting/Expo.plist MODIFIED
2 2 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 3 <plist version="1.0"> 4 4 <dict> 5 <key>EXUpdatesSDKVersion</key> 6 <string>YOUR-APP-SDK-VERSION-HERE</string> 7 <key>EXUpdatesURL</key> 8 <string>YOUR-APP-URL-HERE</string> 9 5 </dict> 10 6 </plist>
13 13 14 14 prepare_react_native_project! 15 15 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 # ``` 27 flipper_config = FlipperConfiguration.disabled 28 if ENV['NO_FLIPPER'] == '1' then 29 # Explicitly disabled through environment variables 30 flipper_config = FlipperConfiguration.disabled 31 elsif 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 38 end 39 40 16 target 'HelloWorld' do 41 17 use_expo_modules! 42 18 config = use_native_modules! 49 25 :hermes_enabled => podfile_properties['expo.jsEngine'] == nil || podfile_properties['expo.jsEngine'] == 'hermes', 50 26 # An absolute path to your application root. 51 27 :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', 54 29 ) 55 30 56 31 post_install do |installer| 57 32 react_native_post_install( 58 33 installer, 59 34 config[:reactNativePath], 60 :mac_catalyst_enabled => false 35 :mac_catalyst_enabled => false, 36 :ccache_enabled => podfile_properties['apple.ccacheEnabled'] == 'true', 61 37 ) 62 38 63 39 # This is necessary for Xcode 14, because it signs resource bundles by default
1 1 { 2 2 "name": "expo-template-bare-minimum", 3 3 "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", 5 5 "main": "index.js", 6 6 "scripts": { 7 7 "start": "expo start --dev-client", 10 10 "web": "expo start --web" 11 11 }, 12 12 "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", 15 15 "react": "18.2.0", 16 "react-native": "0.73.6" 16 "react-native": "0.74.5" 17 17 }, 18 18 "devDependencies": { 19 19 "@babel/core": "^7.20.0"
Expo 中文网 - 粤ICP备13048890号