Expo SDK 58 beta 发布:iOS 27、Expo Modules 2.0、Rust 版打包器

SDK 58 beta 带来 iOS 27 与液态玻璃适配、Expo Modules 2.0、冷启动打包快约两倍的 Rust 转换器,以及一批破坏性变更;Expo Go 暂时只能通过 CLI 安装。

中文
复制
深色底上的 Expo SDK 58 beta 宣传图,标注 SDK 58 beta 包含 React Native 0.88 Release Candidate

SDK 58 beta 期从今天开始,持续三到四周。 beta 期是给开发者试用、确认新版本没有在自己的系统和应用配置上引入回归的窗口。期间我们会持续发布修复和改进。

SDK 58 是为 iOS 27 构建的,如果你现在就需要 iOS 27 支持,可以直接用 beta 版发版。SDK 58 beta 包含 React Native 0.88(Release Candidate):0.88 还没正式发布,所以 beta 用的是 RC;0.88 一正式发布,我们就会切到稳定版,并在之后不久发布 SDK 58。SDK 58 的完整 release notes 要等到稳定版才会出,但你现在就可以翻 expo/expo 仓库里的各个 changelog,了解这次发布的规模与破坏性变更。beta 结束时我们会把全部 changelog 合并进根目录的 CHANGELOG.md

SDK 58 的 Expo Go 目前只能通过 Expo CLI 安装,支持 Android 设备与模拟器、iOS 模拟器;iOS 真机走 eas go更多说明)。App Store 与 Google Play 上的 Expo Go 会在稳定版发布后不久更新到 SDK 58,所以你有时间在商店版砍掉 SDK 57 支持之前升级。

我们还会在 Discord 上开设 office hours,欢迎想帮忙测试这次发布的人参加。

SDK 58 为 iOS 27 构建

iOS 27 要求使用 UIKit 的 scene 生命周期,并让 iPhone 应用可缩放;用 iOS 27 SDK 构建的应用会自动获得这两点。Expo 应用现在改用 scene 生命周期,以便在 iOS 27 上正确启动(#46733)。这会改变 app delegate 回调的投递方式,如果你自定义了 AppDelegate.swift,请读scene 生命周期迁移指南。Expo 各个包不再从 UIScreen.main 读取几何信息(#48172#48315#48316#48170#48169),expo-modules-core 也提供了感知 scene 的几何工具(#48168)。

在 iOS 27 上,requireFullScreen 不再能让你的应用退出缩放,应用可缩放时 ScreenOrientation.lockAsync 可能完全不起作用。requireFullScreen 配置插件已为此更新(#48175)。参见 iOS 27 及之后的屏幕方向锁定。用 iOS 27 SDK 构建的应用里,expo-glass-effect 会把 isLiquidGlassAvailable 报为 true#49850)。

beta 期间我们还会持续改进,确保 iPhone Duo SDK 一开放给开发者,就能从第一天起做到深度集成。

带 Xcode 27 和 SDK 58 工具链的 EAS Build 镜像很快会推出,可用之后我们会更新这篇文章;在那之前,latest 这个 EAS Build 镜像带的是 Xcode 26.6。

支持 Xcode 27 的 Device Hub

Xcode 27 用 Device Hub 取代了 Simulator.app。Expo CLI 会识别 Device Hub,通过它启动模拟器,并用 devices:// 深链聚焦到指定设备(#46757#46809)。如果你不想离开编辑器,新的 expo-device-hub 开发工具插件能把浏览器变成一台本地设备面板:所有 iOS 模拟器和 Android 模拟器的实时画面,可以直接点按、滑动、输入,还带启动/关机控制、CPU/内存/网络曲线,以及外观、Liquid Glass、字号、无障碍设置等开关。装上它(npx expo install expo-device-hub)再跑 npx expo start,终端里就会打印链接。如果你想要同样的体验但本机没有 Xcode 或 Android Studio,可以关注 EAS Simulator——我们即将推出的云模拟器服务。

浏览器里的 expo-device-hub 面板:左侧列出 iOS 27 的 iPhone 17 Pro Max 模拟器和 Pixel 9 模拟器,中间是应用的实时画面,右侧是 CPU、内存、网络曲线以及外观、Liquid Glass、字号、无障碍等设备选项。
expo-device-hub 正在串流一台跑 iOS 27 的 iPhone 17 Pro Max 模拟器。来源:Nathan Schroeder 在 X 上的帖子。

App Intents:把应用暴露给 Siri 与 Apple Intelligence

expo-app-intents 让 Expo 应用可以声明 Apple App Intents(Siri、快捷指令、Spotlight 与 Apple Intelligence)(#47207)。App Intent 类型写在 app-intents 目录下的 Swift inline module 里,因为 Apple 在构建期提取元数据时只能看到 app target 内的代码。这个包会把调用投递给 JavaScript,并保存 entity 值。运行 npx expo-app-intents init 来创建该目录(#47223)。这个库还在 alpha,文档和示例随后补齐。

例子:用 Siri 完成一项任务

一个 onboarding 清单应用声明了「完成任务」这个 intent 和一个任务 entity。你对 Siri 说要完成某项任务,Siri 会列出应用里的任务并问你选哪个;选一个,intent 就在你的 JavaScript 里运行,应用把它标记为完成——全程不需要把应用拉到前台。

两张 iPhone 截图。左侧 Siri 问「Which task did you complete?」并列出应用里的 onboarding 任务,例如「Sign offer letter」「Upload ID documents」;右侧 Siri 在应用清单上方显示「Marking Upload ID documents as done」,该任务已被勾选。
从 Expo 应用暴露出来的 App Intent:Siri 问要完成哪项任务,然后在应用里运行该 intent。

Expo UI:iOS 上的原生导航、新的 Compose 组件,还有更多

每个组件在文档里都有预览图

Expo UI 参考文档现在在每个组件的 API 旁边放了一张截图,让你在读 props 之前就看清自己选的是什么。可以浏览文档里的 SwiftUIJetpack Compose 画廊。

文档里并排的 Expo UI 组件预览网格:左侧是 iOS 的 SwiftUI 组件,右侧是 Android 的 Jetpack Compose 组件。
Expo UI 文档里 SwiftUI 与 Jetpack Compose 组件画廊的一角。

iOS 导航。 @expo/ui 新增 NavigationStackToolbarNavigationLinkNavigationDestination 组件,navigationTitle 修饰符,以及 close 按钮角色(#49940#49991)。NavigationSplitView 增加了两栏和三栏布局(#50075)。

SwiftUI。 backgroundtintborderstrokeBordercontainerBackgroundpresentationBackgroundforegroundStyle 这些修饰符现在接受任意 ShapeStyle,所以视图可以用材质或渐变来上色(#48905#49621#49767#49838)。新增的还有 Background 组件(#48904),以及 scrollClipDisabled#49780)、geometryGroup#48838)、listRowSeparatorTint#48810)、alignmentGuide#49247)、menuStylemenuIndicator#48448)修饰符。

Jetpack Compose。 新增 Image#48521)、DateRangePickerDateRangePickerDialog#49788)和 VerticalSlider#49612)组件。DropdownMenu 增加 cornerRadiusshadowElevation#49515#49896),RadioButton 增加 enabledcolors#49852)。

通用组件。 BottomSheet 增加 contentPaddingcontainerColorcontentColorListItem 支持 colors#48902#49575)。Web 上,BottomSheet 去掉了不再维护的 vaul,改用自研的 HTML <dialog>#49509)。

托管 React Native 视图。 放在 <RNHostView> 里的视图现在按 SwiftUI 和 Jetpack Compose 摆放它们的位置来测量(#48969#48970)。这修好了点按丢失、手势被外层滚动容器抢走,以及 BottomSheetPopoverAlertDialogDropdownMenu 内部点不到的问题。现在点托管文本框外部会收起键盘(#48788)。关闭 SwiftUI Menu 的那一次点击也不再会按下它下面的 React Native 视图(#48463#49775)。

Expo 与 EAS Observe

EAS Observe 用来监控生产环境里应用的性能与错误,8 月 20 日起已正式可用。SDK 58 里 expo-observe 新增 Observe.registerIntegration#48245)、ObserveErrorBoundaryreportError#47341#47871)、errorHandlingEnabled 选项(#48506)、一个 expo-image 集成(#47145),以及 Observe.clientId——记在每个事件上的 EAS client ID(#49599)。AppMetrics 已废弃,改用 Observe——见废弃项

EAS Observe 概览面板:展示活跃用户、会话,以及三个版本的发布对比表,含可交互时间、首屏渲染时间、无崩溃会话率、无崩溃用户率、错误数与受影响用户数。
EAS Observe 概览:跨版本对比启动指标、无崩溃率与错误。

@expo/agent-cli:给 agent 设计的新 CLI

过去 agent 学 Expo 都是硬啃:启动 Expo Go,加一个 Expo Go 不支持的 native module 就撞运行时错误,然后自己猜该用 development build;还得知道什么时候该用 Expo CLI、什么时候该用 EAS CLI。@expo/agent-cli 是一个新的实验性 CLI,由 agent 构建、为 agent 设计。它架在 Expo CLI、EAS CLI 和 expo-doctor 之上,并且会回落到 Expo CLI,所以你可以直接让 agent 用它替代原来的工具。

可以试试几个有用的命令:status 不用启动应用就能回答 Expo Go 兼容性;dev 一条命令把应用跑起来,类似 web 框架同时起服务端和浏览器,它自己判断什么时候需要构建,并尝试用最快的方式让应用跑起来;命令会打印下一步该做什么,agent 就知道怎么往下走。smoke 等于 dev 加截图加停止,用来确认你这台机器上确实能开始开发。skills:sync 会把 node_modules 里同位置的 agent skills 装到你的项目里。

npx @expo/agent-cli@latest agents:setup 开始,然后让你的 agent 用 @expo/agent-cli 替代 Expo CLI。

想要更短的名字,expo-agent-cli 是一个别名。感谢 Kazutoyo Tokai 把这个包名转给我们。这个 CLI 还在积极开发中,之后会有一篇博客展开讲;在那之前,先试试,也欢迎告诉我们你的想法

主屏小组件来到 Android

expo-widgets 增加了 Android 实现:小组件在专用的 Hermes 运行时里跑自己的 JS bundle,支持交互和 Material Colors(#46961#47035#48454)。iOS 上,Live Activities 的 LiveActivity.start()update() 增加 staleDate 选项(#46343),ActivityKit 标识符变稳定(#48589),小组件配置支持运行时变更(#47533)。

Swift Package Manager 构建

React Native 0.87 加入了实验性的 Swift Package Manager 支持,作为 CocoaPods 之外的另一个选项,SDK 58 为 Expo 应用铺好了路。Expo 的 iOS 源码已经重构,Swift、Objective-C 和 C++ 会分别编译成独立的 SwiftPM target(#45906#49820#49821#49832),给 React Native npx react-native spm 流水线用的 Expo autolinking 插件正在 review 中(#49823),我们计划在 beta 期间以预览形式发布。CocoaPods 仍是默认且受支持的路径,预编译的 Expo module 在那里照常工作。

Expo Modules:更快的构建、更快的调用、更简单的写法

用预编译的 expo-modules-core 加速 Android 构建

expo-modules-core 现在为 Android 提供预编译好的原生库。以前每一次干净构建、每一次 CI、每一次 EAS Build 都要从源码编译 libexpo-modules-core.so 里的 C++,这是使用 Expo 的 Android 构建中最贵的一步。现在 npm 包里包含全部四个 ABI 的 .so 文件,debug 与 release 变体都有。我们在一个空白 SDK 58 项目上测:四个 ABI 的 Android debug 干净构建在 Apple M3 Pro 上约 80 秒,跳过 expo-modules-core 的 C++ 编译后降到约 39 秒,差不多一半。核数少的机器(比如 CI runner)省得更多。被省掉的编译工作量在四个 ABI 上累计超过 10 分钟,12 核机器靠并行跑很多文件把它隐藏了。

更快的 Expo 模块

一次 native module 调用不是免费的:跨进 Swift 或 Kotlin、再转换两个方向上的值,都有固定开销,而那些便宜的调用里大部分成本就花在这里。SDK 56 在两个平台上都动过这块:iOS 上去掉了 Objective-C++ 层,调用快了 1.6 到 2.3 倍;Android 上用 Kotlin 编译器插件取代反射Record 转换快了约 6 倍,首屏渲染时间缩短约 30%。

SDK 58 又在 iOS 这侧推了一轮。传递或返回简单值的调用更便宜了(#49761),两个方向上传递长字符串最多快 3.8 倍(#49678),async 函数返回的 promise 创建与 resolve 的开销也更低(#49718)。不需要你做任何接入:升到 SDK 58,所有 Expo module 都会变快,包括不是你写的那些。

Expo Modules 2.0 beta

另一半故事是你写代码时对着的那套 API。你现在不用在既有的 DSL 定义里描述 native module,而是可以直接写一个普通的 Swift 或 Kotlin 类,把想暴露给 JavaScript 的方法和属性加上注解。除了这几个注解没有新东西要学,对编码 agent 也更友好——不需要先解释一套自定义 DSL,就是 Swift 和 Kotlin,模型本来就很熟。

在以上改进之上它还更快:注解让我们在构建期生成最直接的 binding,而不是运行期现找。同一个 SDK 上,用 iPhone 16 Pro 的 Release 构建测量,同步调用比 DSL 快 2.5 到 5.6 倍。Expo Modules 2.0 抢先看里有基准数据,也更深入地讲了这套 API。

Android 上 Kotlin 侧呈现同样的模式,这次我们还拿 React Native 的 TurboModules 做了对照。十二项微基准里,Expo Modules 2.0 每一项都快过 Expo Modules 1.0,从传 100 个数字数组的 1.2 倍,到发一个带数字的事件快 39.9 倍。它同样每一项都快过 TurboModule:无参数调用 112 ns 对 2,837 ns,传 20 个对象数组 10.7 µs 对 149.8 µs,发一个带对象的事件 963 ns 对 8,080 ns。

十二项 Android 微基准对比 TurboModule、Expo Modules 1.0 与 Expo Modules 2.0:2.0 在每一项里条最短,从无参数函数调用到发一个带对象的事件。
Expo Modules 2.0 对 Expo Modules 1.0 与 TurboModule 的 Android 微基准。越短越好,绿色标签是 2.0 与 1.0 的对比。

SDK 57 把 iOS 宏作为实验发布;到 SDK 58 beta,Expo Modules 2.0 在 iOS 和 Android 上都进入 beta。文档会在 beta 期间补齐,在那之前抢先看那篇博客是最好的指引。

新的 fingerprint 默认值:少了不必要的原生重构建

改个版本号、或者动了 node_modules 里的文件,不再意味着 fingerprint 变化。SDK 58 把 fingerprint 的默认值改成 balanced 预设(#47668)。它会忽略更新 app.json 里的 version 这类常见情况,并且按包名和版本(而不是文件与目录)来为 native module 计算哈希。不需要额外配置,哈希就保持稳定。如果你想要不同的取舍,可以看fingerprint 预设

实验性:用 Rust 写的转换器把冷启动打包提速约 2 倍

Metro 的缓存让热打包很快,但冷打包——无论整个项目还是改动过的模块——大部分时间都花在 Babel 上。SDK 58 引入一个实验性替代品:“Noxcturnal”,一个用 Rust 写的 module transformer,基于 oxc,通过 napi-rs 暴露给 Node.js。在我们的内部测试里,单模块转换时间约快 3 倍,端到端冷打包约快 2 倍(#48443)。在我们最大的测试应用上,约 5,500 个文件的冷打包从 Babel 的 5.26 秒降到新转换器的 2.46 秒,其中仍有 443 个文件回落到 Babel。

同一个应用的两条转换时间线:启用 Noxcturnal 后 5,477 个文件在 2.46 秒内跑完,用 Babel 时 5,494 个文件要 5.26 秒。
我们最大测试应用冷打包时的转换 worker 活动:上方是新的转换器,下方是 Babel。来源:Phil Pluckthun 在 X 上的帖子。

在 app config 里设置 experiments.noxcturnalTransformWorker 就能试用。只有当你的项目没有自定义 transform worker 或 Babel 插件/预设时它才会生效,并且会跳过需要 Reanimated 或 Worklets Babel transform 的文件。这还是很早期的工作:实现和数字在稳定之前都可能变,我们计划加上配置项,让更多项目(包括带自定义 Babel transform 的)也能用上。

Expo Router:数据加载器与原生标签稳定,导航核心改进

数据加载器服务端渲染中间件现在都是稳定功能,不再需要实验开关。原生标签工具栏标准导航集成也已稳定。

Expo Router 的导航核心也重写了,导航状态变得确定、更容易推理,并且不再携带大部分 fork 出来的 React Navigation API。多数应用不会察觉。但如果你写过自定义 navigator,或者从 expo-router/react-navigation 导入,有些 API 已经迁移或移除;如果你需要的某一个不见了,请开 issue说明你想做什么。

其他改动列在下面,文档链接我们会陆续补上。

  • Navigator 迁移:JavaScript 的 TabsTopTabsDrawer 现在和 NativeTabs 使用同一套 standard-navigation 集成,行为更一致。

  • Loader 缓存:在 loader 里从 expo-server 调用 setResponseHeaders({ 'Cache-Control': 'private, max-age=60' }),就能让客户端把它的响应缓存 60 秒。

  • React transitions 与 Activity:导航使用 React transitions,在下一个屏幕加载时保持当前屏幕可见。在 navigator 或 screen 上设置 activityEnabled,或者用 NavigationAwareActivity 包住屏幕的一部分,就能在保留状态、清理 effect 的同时隐藏非活跃内容。

  • Web 上默认开启异步路由expo-router 配置插件现在自动为 web 启用 asyncRoutes。路由文件会被拆成独立的 JavaScript chunk,浏览器导航到该路由时再加载。设置 asyncRoutes: { web: false } 可以关掉。

  • 自定义 router API:用 extendRouter 覆盖内置 router 的一部分,或用 extendRouterActions 为自定义导航动作添加 handler。

  • 屏幕级错误边界:在 layout 里设置 unstable_settings.screenErrorBoundary,或者传 <Stack unstable_screenErrorBoundary={MyErrorBoundary} />,就能为抛错的屏幕显示兜底 UI,同时保持 navigator 挂载。

  • 可选依赖:Android 上,要用带 md prop 的 NativeTabs.Trigger.Icon 需要安装 expo-symbols,要用 Stack.Toolbar 需要 @expo/ui。这两个包现在是可选 peer 依赖。

升级时请读迁移指南,如果你用了自定义 navigator 或从 expo-router/react-navigation 导入,尤其要读。

通过代理和隧道连接 dev server

如果你的 dev server 跑在代理后面、远程机器上,或者通过隧道暴露,development build 现在应该能稳定连上它。以前 development build 启动时拉取的 manifest 会告诉它用哪个 bundle URL 和 debugger hostname,而当服务端在代理后面、或者通过 Bonjour 被发现时,那些地址可能是客户端根本连不到的。现在只要客户端支持,manifest 就用相对 URL(#47255#48997)。

RCT_METRO_PORT 在预编译的 React Native 里是一个编译期宏,被冻在 8081,所以没有 expo-dev-client 的 bare 应用永远只跟 8081 对话,两个这样的应用同时跑会互相响应对方的 reload 命令。现在 prebuild 会把端口写进 Info.plistRCTMetroPort 键,应用在启动时读取它(#48098)。Expo CLI 的端口选择也更一致了,非交互运行时不再直接失败,而是顺延到下一个空闲端口(#47771#48300)。

更快、更可靠的 Expo CLI 隧道

Expo CLI 有了基于 @expo/ws-tunnel 2.0 的新隧道实现(#46696)。它连接更快、连接更稳定,也不再需要 @expo/ngrok。这样试:

EXPO_UNSTABLE_TUNNEL_V2=1 expo start --tunnel

使用它需要登录你的 Expo 账号(expo login)。

EXPO_UNSTABLE_TUNNEL_V2 开关会在 SDK 58 beta 后期去掉,届时这会成为默认的隧道实现。

React Native 0.88(Release Candidate)

SDK 58 beta 把 React Native 从 0.86 升到 0.88 release candidate,所以它同时吸收了 React Native 0.87React Native 0.88 release candidate 的改动。0.88 的要点包括:

  • Swift Package Manager 工具:可选的 npx react-native spm 命令和 SwiftPM 包生成。CocoaPods 仍是默认且受支持的路径。

  • Text 上的 fontVariationSettings:用对象语法设置可变字体轴,和这个版本里 expo-font 加入的可变字体支持正好搭配。

  • TurboModules 里的 ArrayBuffer:JavaScript 的 ArrayBuffer 值现在在 Android 和 iOS 上都有原生表示,并带一份明确的字节所有权约定。

  • React Native DevTools:实验性的性能截图,以及 Network 面板里的 WebSocket 检查。

完整情况请看 React Native 0.87 release notesReact Native 0.88.0-rc.0 release notes。等 React Native 0.88 的博客发布后,我们会在这里补上链接。

PostHog 集成

现在一条命令就能在 Expo 应用里接好 PostHog,而且它捕获的每个事件都知道自己来自哪次 EAS update。运行 eas integrations:posthog:connect,EAS CLI 会创建或关联你的 PostHog 项目、安装 SDK 及其配置插件,并把环境变量写进你的项目和 EAS。PostHog 能识别 eas/update_ideas/build_ideas/channeleas/runtime_version 这些属性,并把它们关联回 expo.dev。这是 EAS CLI 的能力,所以任何 SDK 版本都能用。可以读 PostHog 集成 changelog使用 PostHog 指南

其他值得注意的改动

  • expo-camera:新增 CameraView.scanDocumentAsync,在 Android 和 iOS 上做多页文档扫描(#47362)。

  • expo-file-system:新增 File.digest(),支持 MD5/SHA-1/SHA-256/SHA-384/SHA-512 哈希(#48089),以及用于原生预览流程的 File.preview()File.canPreview()

  • expo-audio:新增带播放列表的锁屏控制(#46020),以及用 AudioStream.startFileRecordingAsync 录制 WAV/PCM 文件(#46771)。

  • expo-image:新增 transition.skipOnCacheHit,命中缓存时跳过转场(#48181);以及 svgVariables prop,为 SVG 里用 var() 引用的 CSS 自定义属性替换取值,于是同一份文档的不同部分可以给不同颜色,而图片仍然是矢量(#48663)。取值不限于颜色。用 var() 的 SVG 现在即使不传这个 prop,也会用回退值渲染。

  • expo-secure-store:Android 上新增 requireConfirmation,用于需要认证的读写(#48556)。

  • expo-dev-launcher:新增 disableFab=1disableAutoLaunch=1 两个 URL 参数,用来隐藏浮动按钮、并阻止 dev menu 在启动时自动打开(#49651)。

  • expoURLURLSearchParams 重写,支持 IDNA/TR-46(#47813),TextDecoder 为速度重写(#48877)。

  • expo-sqlite:自带一份同位置的 agent skill,把最佳实践分享给 agent。运行 npx @expo/agent-cli skills:sync 就能装进你的项目(#49867)。

  • expo-font:在 Android、iOS 和 web 上支持可变字体,一个字体文件就能提供一个包含多个字重或字形的 family。useFontsloadAsync 和配置插件都能用(#48129#48621#48432#49486#49487#49485)。了解更多

  • expo-notifications:iOS 上,通知中心的调用会转发给另一个库注册的 UNUserNotificationCenterDelegate,所以 expo-notifications 可以和别的推送库共存于同一个应用(#48313),通知也可以用 threadIdentifier 分组(#49429)。Android 上,日期与重复触发器新增 delivery: 'alarmClock' 选项,使用 AlarmManager.setAlarmClock()——OEM 的省电策略不会推迟它——用于对时间敏感闹钟(#49687),配置插件新增 largeIcon 属性(#49481)。了解更多

  • expo-location:我们正在围绕一层位置提供者抽象重写 expo-location,带来更简单的定位 API、位置监听、后台位置更新,以及请求 iOS 临时全精度等新权限选项(#49849#49972#49988)。这次重写会以可选预览的形式和现有 API 并存,所以这个 beta 里现有的 expo-location 代码什么都不用改。可以试的时候我们再细说。

  • @expo/cli:Android 虚拟设备(AVD)与 adb 管理重写,对失败更有韧性(#49258)。

废弃项

  • expo-file-systemFile.md5 废弃,改用 File.digest()#48089)。

  • expo-modules-coreNativeArrayBuffer 废弃,改用 ArrayBuffer#47106)。

  • expo-observeAppMetrics 导出废弃,改用 Observe#48901)。

  • expo-sqliteuseLibSQL 配置插件属性废弃,且不再有任何效果(#48543)。

  • @expo/ui:iOS 上 backgroundOverlay 废弃,改用 background#49621);borderstrokeBordercolor 参数废弃,改用 content#49838)。

值得注意的破坏性变更

  • React Native 严格 TypeScript API:React Native 0.87 把严格 TypeScript API 变成默认。从 react-native/Libraries/* 深层导入现在会报类型错误,部分类型形状也变了,最明显的是 ref,现在使用 ViewInstanceTextInputInstance 这类实例类型。可以按迁移指南做,也可以交给 agent,用 migrate-to-strict-api skill。想推迟迁移,就在 tsconfig.json 里设置 "customConditions": ["react-native", "react-native-legacy-deep-imports"](保留 "react-native"expo/tsconfig.base 已经设置过)。这个退出开关在 React Native 0.88 之后会被移除,所以计划在 SDK 58 周期内完成迁移。

  • React Native API 移除InteractionManager(改用 requestIdleCallback)、Touchable 根导出、NativeMethods 类型、Modalanimated prop,以及已废弃的 StatusBarbackgroundColortranslucentnetworkActivityIndicatorVisible 都被移除。ImageBackground 废弃,改用 View 里放一个绝对定位的 Image。完整列表见 0.870.88.0-rc.0 的 release notes。

  • iOS 的 scene 生命周期:iOS 27 SDK 要求 UIScene 生命周期,所以 npx expo prebuild 现在会生成 SceneDelegate.swiftInfo.plist 里的 UIApplicationSceneManifest 条目,UIWindow 由 scene delegate 创建,而不再在 didFinishLaunchingWithOptions 里(#46733#46734)。Expo 会把 URL、user activity、Handoff、生命周期和快捷动作事件转发给 ExpoAppDelegate 的覆写与订阅者,所以基于这些的配置插件和模块照常工作(#49925#50032)。如果你手工管理 ios 目录、用的是 bare React Native 应用,或者直接覆写 app delegate 方法,请看迁移指南

  • NODE_ENV 与环境文件:现在每条 Expo CLI 命令都会在加载 .env 文件和 app config 之前把 NODE_ENV 设为 developmentproduction,所以动态的 app.config.js.env 级联在模式上始终一致(#48554#48741#48839)。以前每条命令都会保留继承来的 NODE_ENV,而 expo config 干脆不设置,于是 NODE_ENV=test npx expo start 会加载 .env.test。现在继承来的值会被忽略,该命令加载的是 .env.development。Jest 在你的测试里仍然设置 NODE_ENV=test@expo/env 在那里仍然解析 .env.test.local.env.test.env。参见环境变量指南

  • Android 应用模板:release 构建现在默认通过 gradle.properties 里的 android.enableMinifyInReleaseBuilds=true 启用 R8#50108)。R8 会缩减、优化并混淆 Java/Kotlin 代码,从而减小包体、改善启动时间;应用使用 proguard-android-optimize.txt 预设优化。依赖反射的库可能需要 ProGuard keep 规则。想关掉,就用 expo-build-propertiesandroid.enableMinifyInReleaseBuilds 设为 false

  • expo-router导航核心的改动让导航状态和 route key 变得确定,把导航派发推迟到 commit 之后,并移除了相当一部分 fork 出来的 react-navigation API。@expo/uiexpo-symbols 现在是可选 peer 依赖。迁移指南逐条覆盖,完整列表在 expo-router changelog

  • expo-file-systemFile.write() 现在是异步的并返回 promise;想要原来的行为请用 File.writeSync()#45992)。

  • expo-sqlite:移除 libSQL 支持——syncLibSQL()libSQLOptions 都没了(#48543)。

  • expo-notifications:前台通知现在默认展示,除非你的 setNotificationHandler 另有指示;handler 慢也不再丢通知(#49072)。这次发布里 expo-notifications 的其他改动见其他值得注意的改动

  • @expo/fingerprint:默认预设现在是 balanced#47668)。

  • @expo/ui:iOS 上 <Host> 改为顶部对齐而非居中,于是 flex: 1 的 host 和 Android 一致(#47561)。HStackVStackGlassEffectContainer 现在把未设置的 spacing 作为 nil 转发给 SwiftUI,使用系统默认间距;传 spacing={0} 保持原来的布局(#48441)。Android 上 RNHostViewstyle prop 被移除,改用 modifiers#48970)。

  • expo-localization:iOS 上不再通过 supportsRTL 依据设备语言强制开启 RTL;布局方向跟随 I18nManager#48086)。

  • expo-media-library:iOS 上 Asset.getUri()AssetInfo.uri 现在解析视频在 Photos 里的当前版本;想要原来的行为请传 version: AssetUriVersion.ORIGINAL#48640)。

  • @expo/cliexpo login 现在默认走浏览器登录;想要原来的行为请用 --no-browser--username/--password#46832)。

工具版本要求

  • Node.js:Expo 工具链现在要求 Node.js 22 系列至少 22.13、24 系列至少 24.3,或者 Node.js 26 及以上。23、25 这类奇数版本不受支持(#47202)。

  • Android Gradle Plugin:Expo modules 工具链现在兼容 AGP 9(#46766#46769)。

已知回归

  • 目前没有报告。beta 期间有新的发现,我们会更新这一节。

怎么试用这个 beta 版

用 SDK 58 beta 初始化新项目

# npm
npx create-expo-app@latest --template default@next
# bun
bun create expo-app --template default@next
# pnpm
pnpm create expo-app --template default@next
# yarn
yarn create expo-app --template default@next

注意create-expo-app 会用你正在使用的包管理器安装依赖。比如用 npx 时就是 npm,用 yarn create 时就是 yarn。

升级已有项目

可以配合 Claude Code 用我们的 expo-upgrade skill 把应用升到 beta。你遇到任何问题都欢迎反馈,我们会在接下来几周继续打磨它。

下面是手动升级的步骤。

  • 把所有依赖升到与 SDK 58 匹配
npx expo install expo@next --fix

该测什么

  • 升级并测试:运行 npx expo install expo@next --fix,然后对照原生项目升级助手,并报告你遇到的问题

  • 原生构建:用 EAS Build 构建(带 Xcode 27 与 SDK 58 的镜像很快推出,见上文);如果你本地装了 Xcode 和 Android Studio,也可以试试 prebuild 再运行:npx expo prebuild --cleannpm run iosnpm run android。或者试试 npx expo run。遇到新问题?请报告给我们

  • 发现文档缺口?告诉我们

怎么报问题

  • 用对 issue 模板开 issue 时选对应模板,并附上一个最小可复现示例

  • 尽量定位根因:这总是非常有帮助,能加快修复。

  • 说明你在用 SDK 58 beta:我们会据此调整优先级。

感谢你测试 beta,非常感谢!

来源: Expo Changelog← 返回首页