原生项目升级助手 查看你需要对原生项目进行的所有更改的逐个文件差异,以将其升级到下一个 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 Upgrade Helper ,但它们主要面向使用 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.
想完全避免升级原生代码吗?请参阅 Continuous Native Generation (CNG) 了解 Expo Prebuild 如何在构建之前生成你的原生项目。
升级原生项目文件
🌐 Upgrade native project files
一旦你升级了 Expo SDK 版本及相关依赖 ,请使用下面的差异工具了解需要对你的原生项目进行的更改,并将其更新到当前的 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 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 { 111 113 // Caution! In production, you need to generate your own keystore file. 112 114 // see https://reactnative.dev/docs/signed-apk-android. 113 115 signingConfig signingConfigs.debug 114 shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false) 115 minifyEnabled enableProguardInReleaseBuilds 116 def enableShrinkResources = findProperty('android.enableShrinkResourcesInReleaseBuilds') ?: 'false' 117 shrinkResources enableShrinkResources.toBoolean() 118 minifyEnabled enableMinifyInReleaseBuilds 116 119 proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 117 crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true) 120 def enablePngCrunchInRelease = findProperty('android.enablePngCrunchInReleaseBuilds') ?: 'true' 121 crunchPngs enablePngCrunchInRelease.toBoolean() 118 122 } 119 123 } 120 124 packagingOptions { 121 125 jniLibs { 122 useLegacyPackaging (findProperty('expo.useLegacyPackaging')?.toBoolean() ?: false) 126 def enableLegacyPackaging = findProperty('expo.useLegacyPackaging') ?: 'false' 127 useLegacyPackaging enableLegacyPackaging.toBoolean() 123 128 } 124 129 } 125 130 androidResources {
android/app/src/debugOptimized/AndroidManifest.xml ADDED
1 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools"> 3 4 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> 5 6 <application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" tools:replace="android:usesCleartextTraffic" /> 7 </manifest>
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 DefaultNewArchitectureEntryPoint.releaseLevel = try { 44 ReleaseLevel.valueOf(BuildConfig.REACT_NATIVE_RELEASE_LEVEL.uppercase()) 45 } catch (e: IllegalArgumentException) { 46 ReleaseLevel.STABLE 49 47 } 48 loadReactNative(this) 50 49 ApplicationLifecycleDispatcher.onApplicationCreate(this) 51 50 } 52 51
android/build.gradle MODIFIED
12 12 } 13 13 } 14 14 15 def reactNativeAndroidDir = new File( 16 providers.exec { 17 workingDir(rootDir) 18 commandLine("node", "--print", "require.resolve('react-native/package.json')") 19 }.standardOutput.asText.get().trim(), 20 "../android" 21 ) 22 23 15 allprojects { 24 16 repositories { 25 maven { 26 // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 27 url(reactNativeAndroidDir) 28 } 29 30 17 google() 31 18 mavenCentral() 32 19 maven { url 'https://www.jitpack.io' }
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
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/SplashScreen.storyboard MODIFIED
1 1 <?xml version="1.0" encoding="UTF-8"?> 2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="EXPO-VIEWCONTROLLER-1"> 2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="24093.7" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="EXPO-VIEWCONTROLLER-1"> 3 3 <device id="retina6_12" orientation="portrait" appearance="light"/> 4 4 <dependencies> 5 5 <deployment identifier="iOS"/> 6 <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/> 6 <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24053.1"/> 7 7 <capability name="Named colors" minToolsVersion="9.0"/> 8 8 <capability name="Safe area layout guides" minToolsVersion="9.0"/> 9 <capability name="System colors in document resources" minToolsVersion="11.0"/> 9 10 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> 10 11 </dependencies> 11 12 <scenes> 29 30 <constraint firstItem="EXPO-SplashScreen" firstAttribute="centerY" secondItem="EXPO-ContainerView" secondAttribute="centerY" id="0VC-Wk-OaO"/> 30 31 <constraint firstItem="EXPO-SplashScreen" firstAttribute="centerX" secondItem="EXPO-ContainerView" secondAttribute="centerX" id="zR4-NK-mVN"/> 31 32 </constraints> 33 <color key="backgroundColor" systemColor="systemBackgroundColor"/> 32 34 </view> 33 35 </viewController> 34 36 <placeholder placeholderIdentifier="IBFirstResponder" id="EXPO-PLACEHOLDER-1" userLabel="First Responder" sceneMemberID="firstResponder"/> 38 40 </scenes> 39 41 <resources> 40 42 <image name="SplashScreenLogo" width="100" height="90.333335876464844"/> 43 <systemColor name="systemBackgroundColor"> 44 <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> 45 </systemColor> 41 46 </resources> 42 47 </document>
4 4 require 'json' 5 5 podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json'))) rescue {} 6 6 7 ENV['RCT_NEW_ARCH_ENABLED'] = '0' if podfile_properties['newArchEnabled'] == 'false' 8 ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] = podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR'] 7 def ccache_enabled?(podfile_properties) 8 # Environment variable takes precedence 9 return ENV['USE_CCACHE'] == '1' if ENV['USE_CCACHE'] 10 11 # Fall back to Podfile properties 12 podfile_properties['apple.ccacheEnabled'] == 'true' 13 end 9 14 15 ENV['RCT_NEW_ARCH_ENABLED'] ||= '0' if podfile_properties['newArchEnabled'] == 'false' 16 ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] ||= podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR'] 17 ENV['RCT_USE_RN_DEP'] ||= '1' if podfile_properties['ios.buildReactNativeFromSource'] != 'true' && podfile_properties['newArchEnabled'] != 'false' 18 ENV['RCT_USE_PREBUILT_RNCORE'] ||= '1' if podfile_properties['ios.buildReactNativeFromSource'] != 'true' && podfile_properties['newArchEnabled'] != 'false' 10 19 platform :ios, podfile_properties['ios.deploymentTarget'] || '15.1' 11 install! 'cocoapods', 12 :deterministic_uuids => false 13 20 14 21 prepare_react_native_project! 15 22 20 27 config_command = ['node', '-e', "process.argv=['', '', 'config'];require('@react-native-community/cli').run()"]; 21 28 else 22 29 config_command = [ 23 'npx', 30 'node', 31 '--no-warnings', 32 '--eval', 33 'require(\'expo/bin/autolinking\')', 24 34 'expo-modules-autolinking', 25 35 'react-native-config', 26 36 '--json', 47 57 installer, 48 58 config[:reactNativePath], 49 59 :mac_catalyst_enabled => false, 50 :ccache_enabled => podfile_properties['apple.ccacheEnabled'] == 'true', 60 :ccache_enabled => ccache_enabled?(podfile_properties), 51 61 ) 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 62 end 64 63 end
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.41", 5 "version": "54.0.50", 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.26", 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.33", 15 "expo-status-bar": "~3.0.9", 16 "react": "19.1.0", 17 "react-native": "0.81.5" 21 18 } 22 19 } 23 20