在现有原生应用中使用 EAS 更新
了解如何将 EAS 更新集成到你现有的原生 Android 和 iOS 应用中以启用无线更新。
如果你的项目是一个全新的 React Native 应用 - 从一开始就主要使用 React Native 构建,并且应用的入口点是 React Native,那么请跳过本指南并继续执行 开始使用 EAS 更新。
本指南讲解了如何将 EAS 更新集成到现有的原生应用(有时也称为“棕地应用”)中。它假定你使用的是 Expo SDK 52 或更高版本以及 React Native 0.76 或更高版本。
¥This guide explains how to integrate EAS Update in an existing native app, sometimes referred to as a brownfield app. It assumes that you are using Expo SDK 52 or later, and React Native 0.76 or later.
此说明不适用于旧版 Expo SDK 和 React Native。仅向企业客户提供与旧版本集成的额外实际支持 (联系我们)。
¥Instructions are not available for older Expo SDK and React Native versions. Additional hands-on support for integrating with older versions can only be provided for enterprise customers (contact us).
先决条件
¥Prerequisites
以下说明可能不适用于所有项目。将 EAS 更新集成到现有项目的具体细节很大程度上取决于你的应用的具体情况,因此你可能需要根据你独特的设置调整说明。如果你遇到问题,请提交 在 GitHub 上创建问题 或提交拉取请求以改进本指南。
你应该有一个安装并配置了 React Native 的棕地原生项目来渲染根视图。如果你还没有这个,请按照 React Native 文档中的 与现有应用集成 指南进行操作,然后在完成步骤后返回此处。
¥You should have a brownfield native project with React Native installed and configured to render a root view. If you don't have this yet, follow the Integration with Existing Apps guide from the React Native documentation and then come back here once you have followed the steps.
-
你的应用必须使用 最新的 Expo SDK 版本及其支持的 React Native 版本。
¥Your app must be using the latest Expo SDK version and its supported React Native version.
-
从你的应用中删除任何其他更新库集成,例如 react-native-code-push,并确保你的应用在你支持的平台上的调试和发布版本中都能成功编译和运行。
¥Remove any other update library integration from your app, such as react-native-code-push, and ensure that your app compiles and runs successfully in both debug and release on your supported platforms.
-
必须在项目中安装并配置对 Expo 模块的支持(通过
expo
软件包)。了解更多。¥Support for Expo modules (through the
expo
package) must be installed and configured in your project. Learn more. -
你的 metro.config.js 必须扩展
expo/metro-config
。¥Your metro.config.js must extend
expo/metro-config
. -
你的 babel.config.js 必须扩展
babel-preset-expo
。¥Your babel.config.js must extend
babel-preset-expo
. -
如果你的项目支持 Android,则命令
npx expo export -p android
必须在项目中成功运行;如果你的项目支持 iOS,则命令npx expo export -p ios
必须在项目中成功运行。¥The command
npx expo export -p android
must run successfully in your project if it supports Android, andnpx expo export -p ios
if it supports iOS.
安装和基本配置
¥Installation and basic configuration
请按照 开始使用 EAS 更新 指南中的步骤 1、2、3 和 4 进行操作。
¥Follow steps 1, 2, 3, and 4 from the Get started with EAS Update guide.
完成后,你将安装 eas-cli
并通过身份验证,将 expo-updates
安装到你的项目中,初始化关联的 EAS 项目,并为原生项目添加基本配置。
¥After this is complete, you will have installed and authenticated with eas-cli
, installed expo-updates
to your project, initialized an associated EAS project, and added basic configuration to your native projects.
退出自动设置
¥Opt out of automatic setup
下一步是禁用 expo-updates
的默认行为,以便自动设置自身,从而支持全新的 React Native 项目。
¥The next step is to disable the default behavior of expo-updates
to automatically set itself up in a way that supports greenfield React Native projects.
禁用 Android 上的自动设置
¥Disable automatic setup on Android
修改 android/settings.gradle 文件,设置禁用自动更新初始化的属性,如下例所示:
¥Modify android/settings.gradle to set the property that disables automatic updates initialization, as in the example below:
iOS 上禁用自动设置
¥Disable automatic setup on iOS
将环境变量传递给 CocoaPods 安装以禁用自动更新初始化。
¥Pass in the environment variable to CocoaPods installation to disable automatic updates initialization.
-
EX_UPDATES_CUSTOM_INIT=1 npx pod-install
设置你的 React Native 应用以使用 expo-updates 加载发布包
¥Set up your React Native app to use expo-updates for loading the release bundle
下一步是将 expo-updates
集成到你的 Android 和 iOS 项目中,以便你的应用在发布版本中使用 expo-updates
作为 JavaScript 代码的来源。
¥The next step is to integrate expo-updates
into your Android and iOS projects so that your app will use expo-updates
as the source of your app JavaScript in release builds.
Example
A complete working example is available at this GitHub repository .
Integrating expo-updates with your React Native bundling
-
Ensure that your Metro config extends the Expo config, as in this example:
!!!IG0!!!
-
If you are using a custom entry point, be sure to include Expo initialization there. This ensures that Expo libraries (including
expo-updates
) are all initialized properly. Here are two examples:
!!!IG1!!!
!!!IG2!!!
Integrating expo-updates on Android
The following instructions assume you have an app written in Kotlin, with one or more native activities. Open android/app/src/main/java/com/<your-app-name>/MainActivity.kt and follow the steps below.
- Your React Native activity should subclass
com.facebook.react.ReactActivity
. - In this activity, add code to
onCreate()
to initialize the updates system. The initialization should not happen in the main thread (otherwise a lockup and ANR will occur). - Override
getMainComponentName()
to return the name of the app you registered in your JS entry point above. - Show the React Native view, by overriding the
createReactActivityDelegate()
method as shown below.
!!!IG3!!!
Integrating expo-updates on iOS
The following instructions assume you have an app written in Swift, with one or more native screens that have custom UIViewControllers. We will add a custom view controller that renders your React Native app.
!!!IG9!!!
!!!IG10!!!
AppDelegate changes
- Modify AppDelegate.swift so that it extends
ExpoAppDelegate
. - If you are not already doing so, add a public method to get the running
AppDelegate
instance, so that your custom view controller can access it later. - Add a reference to the singleton instance of the
expo-updates
AppController
class, which manages the updates system on iOS. - Add a new class,
CustomReactNativeFactoryDelegate
, that extendsExpoReactNativeFactoryDelegate
and overrides thebundleUrl()
method to return the correct bundle URL for updates, if the updates system is running. - The
didFinishLaunchingWithOptions()
method needs to perform two steps:- Initialize the
ExpoReactNativeFactory
using theCustomReactNativeFactoryDelegate
created above. This will be used later to create the React Native root view. - Call
AppController.initializeWithoutStarting()
. This creates the controller instance, but defers the rest of the updates startup procedure until it is needed.
- Initialize the
!!!IG4!!!
Implementing a custom view controller
- The view controller should implement the updates protocol
AppControllerDelegate
. - The view controller initialization should
- Set the app delegate's updates controller instance, so that its
bundleURL()
method above works correctly for updates. - Set the
AppController
delegate to the view controller instance - Start the
AppController
- Set the app delegate's updates controller instance, so that its
- Finally, the view controller must implement the one method in the
AppControllerDelegate
protocol,appController(_ appController: AppControllerInterface, didStartWithSuccess success: Bool)
. This method will be called once the updates system is fully initialized, and the latest update (or the embedded bundle) is ready to be rendered.- Create the React Native root view using the
ExpoReactNativeFactory
created by the app delegate. The app name passed in must match the app name that you registered in your JS entry point above. - Add this root view to the view controller.
- Create the React Native root view using the
!!!IG5!!!
!!!IG11!!!
!!!IG12!!!
AppDelegate changes
- Modify AppDelegate.swift so that it extends
EXAppDelegateWrapper
. - If you are not already doing so, add a public method to get the running
AppDelegate
instance, so that your custom view controller can access it later. - Add a reference to the singleton instance of the
expo-updates
AppController
class, which manages the updates system on iOS. - Override the
bundleUrl()
method to return the correct bundle URL for updates, if the updates system is running. - The
didFinishLaunchingWithOptions()
method needs to perform two steps:- Initialize the root view factory used later to create the React Native root view.
- Call
AppController.initializeWithoutStarting()
. This creates the controller instance, but defers the rest of the updates startup procedure until it is needed.
!!!IG6!!!
Implementing a custom view controller
- The view controller should implement the updates protocol
AppControllerDelegate
. - The view controller initialization should
- Set the app delegate's updates controller instance, so that its
bundleURL()
method above works correctly for updates. - Set the
AppController
delegate to the view controller instance - Start the
AppController
- Set the app delegate's updates controller instance, so that its
- Finally, the view controller must implement the one method in the
AppControllerDelegate
protocol,appController(_ appController: AppControllerInterface, didStartWithSuccess success: Bool)
. This method will be called once the updates system is fully initialized, and the latest update (or the embedded bundle) is ready to be rendered.- Create the React Native root view using the root view factory created by the app delegate. The app name passed in must match the app name that you registered in your JS entry point above.
- Add this root view to the view controller.
!!!IG7!!!
!!!IG13!!!
!!!IG14!!!
Common questions
How long will this take to add to my app?
Assuming you are using the latest version of React Native supported by the Expo SDK, and you are comfortable with the React Native integration in your native projects, then you can likely integrate EAS Update in a similar amount of time as it would take you to integrate with a tool like CodePush or Sentry.
The most important factor is the React Native version that your app uses. If your app uses anything older than the latest supported version by the Expo SDK (as referenced at the top of this guide), then you will want to upgrade to that version first, and the time that will take is heavily dependent on the size and complexity of the app and skill and experience level of the team working on it.
I'm migrating from CodePush, what else do I need to know?
To learn more, see Migrating from CodePush guide.