原生项目升级助手
编辑
查看您需要对原生项目进行的所有更改的逐文件差异,以将其升级到下一个 Expo SDK 版本。
如果您管理您的原生项目(以前称为裸工作流),要 升级到最新的 Expo SDK,您必须对您的原生项目进行更改。找到哪些原生文件需要更改以及需要在文件中更新什么可能是一个复杂的过程。
以下指南提供比较您的项目当前 SDK 版本与您希望升级的目标 SDK 版本之间原生项目文件的差异。您可以根据项目使用的 expo 包版本对项目进行更改。此页面上的工具类似于 React Native 升级助手。然而,它们是围绕使用 Expo 模块和相关工具的项目进行的。
想避免完全升级原生代码吗?请查看 连续原生生成 (CNG),了解 Expo Prebuild 如何在构建之前生成您的原生项目。
升级原生项目文件
一旦您 升级了您的 Expo SDK 版本和相关依赖项,请使用下面的差异工具了解您需要对原生项目进行的更改,并使其与当前 Expo SDK 版本保持同步。
选择您的 from SDK version 和 to SDK version 以查看生成的差异。然后,通过复制和粘贴或手动对项目文件进行更改来将这些更改应用到您的原生项目中。
From SDK version:
To SDK version:
Native code changes from SDK 53 to 54
android/app/build.gradle
MODIFIED
| 64 | 64 | } |
| 65 | 65 | |
| 66 | 66 | /** |
| 67 | * Set this to true to Run Proguard on Release builds to minify the Java bytecode. | |
| 67 | * Set this to true in release builds to optimize the app using [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization). | |
| 68 | 68 | */ |
| 69 | def enableProguardInReleaseBuilds = (findProperty('android.enableProguardInReleaseBuilds') ?: false).toBoolean() | |
| 69 | def enableMinifyInReleaseBuilds = (findProperty('android.enableMinifyInReleaseBuilds') ?: false).toBoolean() | |
| 70 | 70 | |
| 71 | 71 | /** |
| 72 | 72 | * The preferred build flavor of JavaScriptCore (JSC) |
| 94 | 94 | targetSdkVersion rootProject.ext.targetSdkVersion |
| 95 | 95 | versionCode 1 |
| 96 | 96 | versionName "1.0" |
| 97 | ||
| 98 | buildConfigField "String", "REACT_NATIVE_RELEASE_LEVEL", "\"${findProperty('reactNativeReleaseLevel') ?: 'stable'}\"" | |
| 97 | 99 | } |
| 98 | 100 | signingConfigs { |
| 99 | 101 | debug { |
| 112 | 114 | // see https://reactnative.dev/docs/signed-apk-android. |
| 113 | 115 | signingConfig signingConfigs.debug |
| 114 | 116 | shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false) |
| 115 | minifyEnabled enableProguardInReleaseBuilds | |
| 117 | minifyEnabled enableMinifyInReleaseBuilds | |
| 116 | 118 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" |
| 117 | 119 | crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true) |
| 118 | 120 | } |
android/app/src/main/java/com/helloworld/MainApplication.kt
MODIFIED
| 5 | 5 | |
| 6 | 6 | import com.facebook.react.PackageList |
| 7 | 7 | import com.facebook.react.ReactApplication |
| 8 | import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative | |
| 8 | 9 | import com.facebook.react.ReactNativeHost |
| 9 | 10 | import com.facebook.react.ReactPackage |
| 10 | 11 | import com.facebook.react.ReactHost |
| 11 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load | |
| 12 | import com.facebook.react.common.ReleaseLevel | |
| 13 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint | |
| 12 | 14 | import com.facebook.react.defaults.DefaultReactNativeHost |
| 13 | import com.facebook.react.soloader.OpenSourceMergedSoMapping | |
| 14 | import com.facebook.soloader.SoLoader | |
| 15 | 15 | |
| 16 | 16 | import expo.modules.ApplicationLifecycleDispatcher |
| 17 | 17 | import expo.modules.ReactNativeHostWrapper |
| 19 | 19 | class MainApplication : Application(), ReactApplication { |
| 20 | 20 | |
| 21 | 21 | override val reactNativeHost: ReactNativeHost = ReactNativeHostWrapper( |
| 22 | this, | |
| 23 | object : DefaultReactNativeHost(this) { | |
| 24 | override fun getPackages(): List<ReactPackage> { | |
| 25 | val packages = PackageList(this).packages | |
| 26 | // Packages that cannot be autolinked yet can be added manually here, for example: | |
| 27 | // packages.add(MyReactNativePackage()) | |
| 28 | return packages | |
| 29 | } | |
| 22 | this, | |
| 23 | object : DefaultReactNativeHost(this) { | |
| 24 | override fun getPackages(): List<ReactPackage> = | |
| 25 | PackageList(this).packages.apply { | |
| 26 | // Packages that cannot be autolinked yet can be added manually here, for example: | |
| 27 | // add(MyReactNativePackage()) | |
| 28 | } | |
| 30 | 29 | |
| 31 | 30 | override fun getJSMainModuleName(): String = ".expo/.virtual-metro-entry" |
| 32 | 31 | |
| 33 | 32 | override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG |
| 34 | 33 | |
| 35 | 34 | override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED |
| 36 | override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED | |
| 37 | 35 | } |
| 38 | 36 | ) |
| 39 | 37 | |
| 42 | 40 | |
| 43 | 41 | override fun onCreate() { |
| 44 | 42 | super.onCreate() |
| 45 | SoLoader.init(this, OpenSourceMergedSoMapping) | |
| 46 | if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { | |
| 47 | // If you opted-in for the New Architecture, we load the native entry point for this app. | |
| 48 | load() | |
| 43 | try { | |
| 44 | DefaultNewArchitectureEntryPoint.releaseLevel = ReleaseLevel.valueOf(BuildConfig.REACT_NATIVE_RELEASE_LEVEL.uppercase()) | |
| 45 | } catch (e: IllegalArgumentException) { | |
| 46 | DefaultNewArchitectureEntryPoint.releaseLevel = ReleaseLevel.STABLE | |
| 49 | 47 | } |
| 48 | loadReactNative(this) | |
| 50 | 49 | ApplicationLifecycleDispatcher.onApplicationCreate(this) |
| 51 | 50 | } |
| 52 | 51 |
android/gradle.properties
MODIFIED
| 15 | 15 | # When configured, Gradle will run in incubating parallel mode. |
| 16 | 16 | # This option should only be used with decoupled projects. More details, visit |
| 17 | 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects |
| 18 | # org.gradle.parallel=true | |
| 18 | org.gradle.parallel=true | |
| 19 | 19 | |
| 20 | 20 | # AndroidX package structure to make it clearer which packages are bundled with the |
| 21 | 21 | # Android operating system, and which are packaged with your app's APK |
| 41 | 41 | # If set to false, you will be using JSC instead. |
| 42 | 42 | hermesEnabled=true |
| 43 | 43 | |
| 44 | # Use this property to enable edge-to-edge display support. | |
| 45 | # This allows your app to draw behind system bars for an immersive UI. | |
| 46 | # Note: Only works with ReactActivity and should not be used with custom Activity. | |
| 47 | edgeToEdgeEnabled=true | |
| 48 | ||
| 44 | 49 | # Enable GIF support in React Native images (~200 B increase) |
| 45 | 50 | expo.gif.enabled=true |
| 46 | 51 | # Enable webp support in React Native images (~85 KB increase) |
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.13-bin.zip | |
| 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip | |
| 4 | 4 | networkTimeout=10000 |
| 5 | 5 | validateDistributionUrl=true |
| 6 | 6 | zipStoreBase=GRADLE_USER_HOME |
android/gradlew
MODIFIED
| 114 | 114 | NONSTOP* ) nonstop=true ;; |
| 115 | 115 | esac |
| 116 | 116 | |
| 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar | |
| 117 | CLASSPATH="\\\"\\\"" | |
| 118 | 118 | |
| 119 | 119 | |
| 120 | 120 | # Determine the Java command to use to start the JVM. |
| 213 | 213 | set -- \ |
| 214 | 214 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ |
| 215 | 215 | -classpath "$CLASSPATH" \ |
| 216 | org.gradle.wrapper.GradleWrapperMain \ | |
| 216 | -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ | |
| 217 | 217 | "$@" |
| 218 | 218 | |
| 219 | 219 | # Stop when "xargs" is not available. |
android/gradlew.bat
MODIFIED
| 70 | 70 | :execute |
| 71 | 71 | @rem Setup the command line |
| 72 | 72 | |
| 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar | |
| 73 | set CLASSPATH= | |
| 74 | 74 | |
| 75 | 75 | |
| 76 | 76 | @rem Execute Gradle |
| 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* | |
| 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* | |
| 78 | 78 | |
| 79 | 79 | :end |
| 80 | 80 | @rem End local scope for the variables with windows NT shell |
ios/HelloWorld.xcodeproj/project.pbxproj
MODIFIED
| 168 | 168 | files = ( |
| 169 | 169 | ); |
| 170 | 170 | inputPaths = ( |
| 171 | "$(SRCROOT)/.xcode.env", | |
| 172 | "$(SRCROOT)/.xcode.env.local", | |
| 171 | 173 | ); |
| 172 | 174 | name = "Bundle React Native code and images"; |
| 173 | 175 | outputPaths = ( |
ios/HelloWorld/Images.xcassets/SplashScreenLegacy.imageset/Contents.json
ADDED
| 1 | { | |
| 2 | "images" : [ | |
| 3 | { | |
| 4 | "filename" : "SplashScreenLegacy.png", | |
| 5 | "idiom" : "universal", | |
| 6 | "scale" : "1x" | |
| 7 | }, | |
| 8 | { | |
| 9 | "idiom" : "universal", | |
| 10 | "scale" : "2x" | |
| 11 | }, | |
| 12 | { | |
| 13 | "idiom" : "universal", | |
| 14 | "scale" : "3x" | |
| 15 | } | |
| 16 | ], | |
| 17 | "info" : { | |
| 18 | "author" : "xcode", | |
| 19 | "version" : 1 | |
| 20 | } | |
| 21 | } |
ios/Podfile
MODIFIED
| 6 | 6 | |
| 7 | 7 | ENV['RCT_NEW_ARCH_ENABLED'] = '0' if podfile_properties['newArchEnabled'] == 'false' |
| 8 | 8 | ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] = podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR'] |
| 9 | ||
| 9 | ENV['RCT_USE_RN_DEP'] = '1' if podfile_properties['ios.buildReactNativeFromSource'] != 'true' && podfile_properties['newArchEnabled'] != 'false' | |
| 10 | ENV['RCT_USE_PREBUILT_RNCORE'] = '1' if podfile_properties['ios.buildReactNativeFromSource'] != 'true' && podfile_properties['newArchEnabled'] != 'false' | |
| 10 | 11 | platform :ios, podfile_properties['ios.deploymentTarget'] || '15.1' |
| 11 | install! 'cocoapods', | |
| 12 | :deterministic_uuids => false | |
| 13 | 12 | |
| 14 | 13 | prepare_react_native_project! |
| 15 | 14 | |
| 49 | 48 | :mac_catalyst_enabled => false, |
| 50 | 49 | :ccache_enabled => podfile_properties['apple.ccacheEnabled'] == 'true', |
| 51 | 50 | ) |
| 52 | ||
| 53 | # This is necessary for Xcode 14, because it signs resource bundles by default | |
| 54 | # when building for devices. | |
| 55 | installer.target_installation_results.pod_target_installation_results | |
| 56 | .each do |pod_name, target_installation_result| | |
| 57 | target_installation_result.resource_bundle_targets.each do |resource_bundle_target| | |
| 58 | resource_bundle_target.build_configurations.each do |config| | |
| 59 | config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO' | |
| 60 | end | |
| 61 | end | |
| 62 | end | |
| 63 | 51 | end |
| 64 | 52 | end |
package.json
MODIFIED
| 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 | 4 | "license": "0BSD", |
| 5 | "version": "53.0.38", | |
| 5 | "version": "54.0.1", | |
| 6 | 6 | "main": "index.js", |
| 7 | 7 | "scripts": { |
| 8 | 8 | "start": "expo start --dev-client", |
| 11 | 11 | "web": "expo start --web" |
| 12 | 12 | }, |
| 13 | 13 | "dependencies": { |
| 14 | "expo": "~53.0.20", | |
| 15 | "expo-status-bar": "~2.2.3", | |
| 16 | "react": "19.0.0", | |
| 17 | "react-native": "0.79.6" | |
| 18 | }, | |
| 19 | "devDependencies": { | |
| 20 | "@babel/core": "^7.20.0" | |
| 14 | "expo": "~54.0.0-preview.1", | |
| 15 | "expo-status-bar": "~3.0.1", | |
| 16 | "react": "19.1.0", | |
| 17 | "react-native": "0.81.0" | |
| 21 | 18 | } |
| 22 | 19 | } |