原生项目升级助手
查看你需要对原生项目进行的所有更改的逐个文件差异,以将其升级到下一个 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.
From SDK version:
To SDK version:
Native code changes from SDK 54 to 55
| 11 | 11 | react { |
| 12 | 12 | entryFile = file(["node", "-e", "require('expo/scripts/resolveAppEntry')", projectRoot, "android", "absolute"].execute(null, rootDir).text.trim()) |
| 13 | 13 | reactNativeDir = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile() |
| 14 | hermesCommand = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/sdks/hermesc/%OS-BIN%/hermesc" | |
| 14 | hermesCommand = new File(["node", "--print", "require.resolve('hermes-compiler/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/hermesc/%OS-BIN%/hermesc" | |
| 15 | 15 | codegenDir = new File(["node", "--print", "require.resolve('@react-native/codegen/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile() |
| 16 | 16 | |
| 17 | 17 | enableBundleCompression = (findProperty('android.enableBundleCompression') ?: false).toBoolean() |
| 5 | 5 | <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> |
| 6 | 6 | <uses-permission android:name="android.permission.VIBRATE"/> |
| 7 | 7 | <!-- These require runtime permissions on M --> |
| 8 | <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> | |
| 9 | <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> | |
| 8 | <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/> | |
| 9 | <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32"/> | |
| 10 | 10 | <!-- END OPTIONAL PERMISSIONS --> |
| 11 | 11 | |
| 12 | 12 | <queries> |
| 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" android:supportsRtl="true"> |
| 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"> | |
| 22 | <activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|uiMode|smallestScreenSize" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true"> | |
| 23 | 23 | <intent-filter> |
| 24 | 24 | <action android:name="android.intent.action.MAIN"/> |
| 25 | 25 | <category android:name="android.intent.category.LAUNCHER"/> |
| 6 | 6 | import com.facebook.react.PackageList |
| 7 | 7 | import com.facebook.react.ReactApplication |
| 8 | 8 | import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative |
| 9 | import com.facebook.react.ReactNativeHost | |
| 10 | 9 | import com.facebook.react.ReactPackage |
| 11 | 10 | import com.facebook.react.ReactHost |
| 12 | 11 | import com.facebook.react.common.ReleaseLevel |
| 13 | 12 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint |
| 14 | import com.facebook.react.defaults.DefaultReactNativeHost | |
| 15 | 13 | |
| 16 | 14 | import expo.modules.ApplicationLifecycleDispatcher |
| 17 | import expo.modules.ReactNativeHostWrapper | |
| 15 | import expo.modules.ExpoReactHostFactory | |
| 18 | 16 | |
| 19 | 17 | class MainApplication : Application(), ReactApplication { |
| 20 | 18 | |
| 21 | override val reactNativeHost: ReactNativeHost = ReactNativeHostWrapper( | |
| 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 | } | |
| 29 | ||
| 30 | override fun getJSMainModuleName(): String = ".expo/.virtual-metro-entry" | |
| 31 | ||
| 32 | override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG | |
| 33 | ||
| 34 | override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED | |
| 35 | } | |
| 36 | ) | |
| 37 | ||
| 38 | override val reactHost: ReactHost | |
| 39 | get() = ReactNativeHostWrapper.createReactHost(applicationContext, reactNativeHost) | |
| 19 | override val reactHost: ReactHost by lazy { | |
| 20 | ExpoReactHostFactory.getDefaultReactHost( | |
| 21 | context = applicationContext, | |
| 22 | packageList = | |
| 23 | PackageList(this).packages.apply { | |
| 24 | // Packages that cannot be autolinked yet can be added manually here, for example: | |
| 25 | // add(MyReactNativePackage()) | |
| 26 | } | |
| 27 | ) | |
| 28 | } | |
| 40 | 29 | |
| 41 | 30 | override fun onCreate() { |
| 42 | 31 | super.onCreate() |
| 1 | 1 | distributionBase=GRADLE_USER_HOME |
| 2 | 2 | distributionPath=wrapper/dists |
| 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip | |
| 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip | |
| 4 | 4 | networkTimeout=10000 |
| 5 | 5 | validateDistributionUrl=true |
| 6 | 6 | zipStoreBase=GRADLE_USER_HOME |
| 1 | 1 | #!/bin/sh |
| 2 | 2 | |
| 3 | 3 | # |
| 4 | # Copyright © 2015-2021 the original authors. | |
| 4 | # Copyright © 2015 the original authors. | |
| 5 | 5 | # |
| 6 | 6 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 7 | 7 | # you may not use this file except in compliance with the License. |
| 1 | import Expo | |
| 1 | internal import Expo | |
| 2 | 2 | import React |
| 3 | 3 | import ReactAppDependencyProvider |
| 4 | 4 | |
| 5 | @UIApplicationMain | |
| 6 | public class AppDelegate: ExpoAppDelegate { | |
| 5 | @main | |
| 6 | class AppDelegate: ExpoAppDelegate { | |
| 7 | 7 | var window: UIWindow? |
| 8 | 8 | |
| 9 | 9 | var reactNativeDelegate: ExpoReactNativeFactoryDelegate? |
| 19 | 19 | |
| 20 | 20 | reactNativeDelegate = delegate |
| 21 | 21 | reactNativeFactory = factory |
| 22 | bindReactNativeFactory(factory) | |
| 23 | 22 | |
| 24 | 23 | #if os(iOS) || os(tvOS) |
| 25 | 24 | window = UIWindow(frame: UIScreen.main.bounds) |
| 7 | 7 | def ccache_enabled?(podfile_properties) |
| 8 | 8 | # Environment variable takes precedence |
| 9 | 9 | return ENV['USE_CCACHE'] == '1' if ENV['USE_CCACHE'] |
| 10 | ||
| 10 | ||
| 11 | 11 | # Fall back to Podfile properties |
| 12 | 12 | podfile_properties['apple.ccacheEnabled'] == 'true' |
| 13 | 13 | end |
| 14 | 14 | |
| 15 | ENV['RCT_NEW_ARCH_ENABLED'] ||= '0' if podfile_properties['newArchEnabled'] == 'false' | |
| 16 | 15 | 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' | |
| 16 | ENV['RCT_USE_RN_DEP'] ||= '1' if podfile_properties['ios.buildReactNativeFromSource'] != 'true' | |
| 17 | ENV['RCT_USE_PREBUILT_RNCORE'] ||= '1' if podfile_properties['ios.buildReactNativeFromSource'] != 'true' | |
| 18 | ENV['RCT_HERMES_V1_ENABLED'] ||= '1' if podfile_properties['expo.useHermesV1'] == 'true' | |
| 19 | 19 | platform :ios, podfile_properties['ios.deploymentTarget'] || '15.1' |
| 20 | 20 | |
| 21 | 21 | prepare_react_native_project! |
| 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": "54.0.50", | |
| 5 | "version": "55.0.8", | |
| 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": "~54.0.33", | |
| 15 | "expo-status-bar": "~3.0.9", | |
| 16 | "react": "19.1.0", | |
| 17 | "react-native": "0.81.5" | |
| 14 | "expo": "~55.0.0-preview.9", | |
| 15 | "expo-status-bar": "~55.0.2", | |
| 16 | "react": "19.2.0", | |
| 17 | "react-native": "0.83.1" | |
| 18 | 18 | } |
| 19 | 19 | } |
| 20 | 20 |