首页
/ Expo SDK 核心包演进全解析:从 expo/fetch 到原生 Web 运行时(packages/expo CHANGELOG 深度解读)

Expo SDK 核心包演进全解析:从 expo/fetch 到原生 Web 运行时(packages/expo CHANGELOG 深度解读)

2026-09-09 18:17:25作者:裘晴惠Vivianne

packages/expo 是 Expo 开源仓库中承载 "The Expo SDK"(package.json 的自述)的元包——它聚合 expo-modules-core@expo/cli@expo/metro 等能力,并为 App 提供入口、运行时 polyfill 与原生宿主层。其 CHANGELOG.md 记录了从 SDK 45 到 57 近三年的完整演进:原生 Fetch API 的落地与成熟、Web 标准运行时(Winter Runtime)的持续补齐、iOS/Android 新架构宿主的迁移、DOM Components 的诞生,以及多次破坏性变更。读完本文,你将掌握这套版本档案的阅读方法、各能力引入的确切版本与底层实现,并能在升级 SDK 时准确评估影响面。

一、读懂这份版本档案:CHANGELOG 的结构与分类体系

1.1 变更记录的组织方式

这份 CHANGELOG 采用"倒序时间线 + 语义化分类"结构:顶部是 Unpublished(未发布变更,即当前 main 分支上已合入、尚未随版本号发布的改动),其下按版本号从新到旧排列。每个版本条目内部按统一图标体系分类:

分类 含义
🛠 Breaking changes 破坏性变更,升级前必须评估
🎉 New features 新功能
🐛 Bug fixes 缺陷修复
💡 Others 内部重构、依赖升级、API 再导出等
⚠️ Notices 兼容性公告(如新增 React Native 版本支持)
📚 3rd party library updates 三方库版本更新

大量补丁版本标注为 _This version does not introduce any user-facing changes._(无面向用户变更),表明这类版本仅包含构建或依赖层面的微调——例如 57.0.9、57.0.6、57.0.1 等。同时可以观察到发布节奏:SDK 57 时代以 57.0.x 补丁形式持续发布,大版本(55/56/57)则先经历 preview.0 ~ preview.N 预发布阶段再正式发版。

1.2 "Unpublished" 段:当前开发状态的窗口

Unpublished 段是评估仓库当前状态的第一手信息,它直接反映 main 分支上正在积累的变更。以本文写作时的仓库状态为例,Unpublished 段包含:

  • Breaking:Node.js 最低版本提升到 ^22.13.0(对应 package.jsonengines.node 字段 ^22.13.0 || ^24.3.0 || ^26.0.0 || >=27.0.0);
  • Bug fixes:一批围绕 expo/fetch 的流式传输竞态修复、Hermes JSI 重载崩溃修复、UIKit Scene 生命周期下的 deep link 修复、import.meta.url 在 web 端的空值修复、DOM 组件在 WebView 加载期间的 prop 更新丢失修复等;
  • OthersURL/URLSearchParams 升级到 IDNA/TR-46 规范实现、TextDecoder 性能重写、@expo/metro 升级至 56.1.0 等。

对开发者而言,跟踪 Unpublished 段可以提前感知下一版 SDK 的动向。

二、版本基线演进:平台目标与 React Native 支持矩阵

2.1 原生平台最低版本的一路抬升

CHANGELOG 清晰记录了部署目标的收紧轨迹:

  • SDK 47:iOS 部署目标提升至 13.0,弃用 iOS 12;
  • SDK 50:iOS 13.4;同时补上 Android 对 SDK 21/22 的放弃(SDK 50 alpha);
  • SDK 52:iOS/tvOS 部署目标提升至 15.1
  • SDK 56(56.0.0-preview.0):最低版本抬升为 iOS/tvOS 16.4、macOS 13.4——这是一次影响面较大的基线变更,意味着使用较旧系统设备的用户将无法运行 SDK 56+ 构建的应用。

2.2 React Native 版本支持节奏

每次新架构兼容都通过 ⚠️ Notices 或 🎉 New features 显式宣告,形成一条清晰的兼容线:

RN 0.69(SDK 46)→ 0.70(SDK 47)→ 0.71/0.72/0.73(SDK 48~50)→ 0.74/0.75/0.76(SDK 51~52)→ 0.77/0.78(SDK 53)→ 0.80(SDK 54)→ 0.82/0.83(SDK 55)→ 0.84(SDK 56)→ 0.87+(Unpublished,移除旧架构 bridge 的 RCTRootViewFactoryConfiguration 装配)。

SDK 51 起正式放弃 RN 0.73 及更低版本(51.0.0-beta.0);SDK 53 将 React Native 升级至 0.78,并默认启用新架构(newArchEnabled 未指定时视为 true)。当前仓库 devDependencies 中的 react-native 为 0.87.1(package.json),与 Unpublished 段"针对 RN 0.87+ 修复 iOS 构建"的变更互相印证。

2.3 工具链基线

除平台与 RN 之外,仓库还持续跟进工具链:SDK 56 将项目模板升级到 TypeScript v6;SDK 54 默认启用 React Native Strict TypeScript API typings;SDK 53 的 expo/tsconfig.base 切换到 moduleResolution: "bundler";Node.js 最低版本在 Unpublished 段提升到 22.13.0。

三、expo/fetch:原生 Fetch API 的完整落地与成熟

3.1 从零到一:fetch 的引入与转正

expo/fetch 是这份 CHANGELOG 中出现频率最高的主题,其演进本身就是一部"从实验特性到默认运行时"的完整案例:

  • SDK 52(52.0.0-preview.0):引入 Fetch API 支持(原始实现合并自多个 PR),同时加入 file:// 本地文件请求支持;
  • SDK 52.0.19:为 expo/fetch 加入 Blob 支持,并让 FormData 支持 Blob 字段;
  • SDK 56(56.0.0-preview.0)expo/fetch 成为默认 fetch——这是一个 Breaking change,意味着原生端 fetch() 不再走 react-native 自带的 whatwg-fetch,而是直接命中 Expo 的原生实现。源码层面,这一实现的入口位于 src/winter/fetch/fetch.ts:它把输入归一化(区分字符串 URL、URL 对象与 Request 对象)、处理 credentials: 'same-origin'(等价映射为 include)、归一化 HTTP method、在 signal.aborted 时抛出 AbortError,最终交给 ExpoFetchModule.NativeRequest 发起原生请求。

3.2 流式传输与取消语义的持续打磨

fetch 的流式能力经历了大量修补,这从侧面说明"真流式"在移动端的复杂度:

  • 52.0.8 起"懒启动"流式传输(Started expo/fetch streaming lazily);
  • 52.0.19 修复 AbortController 流式请求不工作、流式请求不完成的问题;
  • 52.0.36 修复 Android 的 cancelStreaming 问题;
  • 56.0.8 修复 bodyUsed 在 Response 被 clone 两次后在兄弟对象间泄漏的问题;
  • Unpublished 段密集修复:URLSession 回调与 startStreaming() 之间的竞态(可能导致 200 响应空 body、丢块或流未关闭)、AbortSignal 中止时在途 read 应 reject 为 AbortError 而非永久挂起、请求失败后 Response.text()/.arrayBuffer() 永不 settle 等。

源码中可见对应的健壮性设计:fetch.ts 在启动前检查 signal 是否已中止,并为中止订阅了清理回调——先中止 body 流再取消原生请求,避免迟到的原生事件触及已废弃的 controller。

3.3 响应体语义与压缩解码

  • SDK 56(56.0.0):Android 端新增 brotligzipzstd 解压支持(CompressionInterceptor.kt 在 56.0.5 被进一步精修)——即使调用方自定义了 Accept-Encoding 头,也会解压(56.0.8 修复);
  • 56.0.0-preview.12:实现 Response.clone(),并按规范在 body 被二次读取时抛出 TypeError
  • 56.0.0-preview.0:为 Response 添加 Symbol.toStringTag,使其能被识别为标准 Response 对象;
  • 57.0.0-preview.0 时代以来的修复Response.blob() 在全局 Blob 为 react-native 实现时抛错(57.0.5 修复);Android 上无 body 的 POST/PUT/PATCH 会误发单个 0x00 字节(56.0.10 修复)。

3.4 输入兼容性

expo/fetch 对输入类型的兼容也在持续收紧:56.0.0-preview.13 修复其不尊重自身 NativeRequest 作为 RequestInit 输入的问题;56.0.0 修复 whatwg-fetchRequest#body 未正确透传的问题。这保证了从 react-native 默认 fetch 迁移到 expo/fetch 时,既有代码的行为尽量一致。

四、Winter Runtime:原生端 Web 标准运行时的系统性补齐

CHANGELOG 中大量"Add ... to native platforms"类条目,指向 expo 包内置的 Winter Runtime(源码集中在 src/winter),目标是让原生端的全局对象向浏览器看齐:

4.1 URL 与 URLSearchParams

  • SDK 50 alpha:加入标准 URL API(随后为规避 SharedArrayBuffer 问题迁移到 whatwg-url-without-unicode),之后一度回退再恢复;
  • SDK 55 preview:用 whatwg-url-minimum 替换整个 URL/URLSearchParams 实现;
  • SDK 56 preview.7:升级到 whatwg-url-minimum@0.1.2,修复 URL/URLSearchParams 缺失 Symbol.toStringTag 的问题;
  • Unpublished 段:升级到 IDNA/TR-46 规范实现并提升性能,"与浏览器的差距已很小"。

配套能力包括 SDK 52 的 URL.canParseURL.createObjectURL 对 Blob 的编码支持(SDK 50 alpha)。

4.2 异步 API 与错误类型

  • SDK 56(56.0.0):新增 AbortSignal.timeoutAbortSignal.anyDOMException(源码见 src/winter/AbortSignal.tssrc/winter/DOMException.ts,均配有 native 平台测试用例);
  • SDK 54 preview.7:新增 structuredClone 内建(源码位于 src/winter,测试见 structuredClone.test.ios.ts);
  • SDK 54 preview.0:新增 TextDecoderStreamTextEncoderStream(对应 src/winter/TextDecoderStream.ts);
  • SDK 52 preview.0:为原生端补充最小 TextDecoder;Unpublished 段对其做了性能重写(Rewrite the TextDecoder implementation to increase decoding performance);
  • SDK 52 preview.0:polyfill Symbol.asyncIterator,并为全局 FormData 补充 set/delete/get/has/forEach/entries/keys/values/[Symbol.iterator] 原型方法。

4.3 模块级与导入相关

  • import.meta.url:Unpublished 段修复其开启 transform.inlineRequires 后为 null 的问题(此前 57.0.7 已修复同步执行后读取为 null 的问题);
  • globalThis.__ExpoImportMetaRegistry(SDK 53 preview.1)与 src/winter/ImportMetaRegistry.ts 对应;
  • Unpublished 段新增 expo/internal/bundle-origingetBundleOrigin)与 getBundleUrl 内部工具,并从 bundle URL 推导 getDevServer
  • 全局类型链在 SDK 55 preview.9 被修正为 expo -> expo-modules-core/types -> ./build/global,不再依赖 types="node",并修复缺失 @types/node 时的 module 类型声明。

这些能力共同支撑了"同一份 JS 代码在 iOS/Android/Web 行为一致"的目标,也是 SDK 52 起 useEvent/useEventListener hooks(面向 EventEmitter 对象)得以提供的基础之一。

五、iOS 原生层演进:Factory 化与 UIKit Scene 生命周期

5.1 从 AppDelegate 到 ReactNativeFactory

SDK 53~56 期间,iOS 宿主层经历了一次结构性重组:

  • SDK 53 preview:将 AppDelegate 集成从 expo-modules-core 迁入 expo 包;
  • SDK 55 preview.0(Breaking):移除 EXAppDelegateWrapper 类(弃用提示在 54.0.3 已加入);移除 bindReactNativeFactory 函数;不再要求继承 ExpoAppDelegate 即可使用 ExpoReactNativeFactory
  • SDK 56 preview.0ExpoReactNativeFactory 切换到新的 AppContext.setRuntime API;
  • Unpublished 段:新增 ExpoBundleConfiguration 以从归一化 bundle URL 推导 RCTBundleConfiguration,并让 dev server 端口在运行时从 RCTMetroPort Info.plist 键解析——使未安装 expo-dev-client 的 bare 项目能连上自己的 Metro 实例而非默认 8081。

5.2 UIKit Scene 生命周期(iOS 27 SDK 兼容)

Unpublished 段引入了一组面向 iOS 27 SDK 的变更:应用改用 UIKit scene-based 生命周期启动;ExpoAppDelegate 在扩展(extensions/widgets)中被标记为不可用(ExpoAppSceneDelegate);修复 scene 生命周期下冷启动 URL 时 Linking.getInitialURL() 返回 null、deep link 被丢弃的问题。

5.3 稳定性修复与 Swift 6

  • Hermes JSI 重载崩溃:Unpublished 段修复了重载时两个重叠的 RCTHost runtime 回调共享 EXReactNativeFactory 的 app context ivar、导致一个回调在另一个 runtime 上装饰对象的问题;
  • 调度器生命周期:57.0.5 将 React runtime scheduler 通过 weak handle 传给 ExpoModulesCore,避免重载期间向已销毁的 scheduler 派发任务;
  • Swift 6:SDK 55 preview.0 全面采纳 Swift 6;
  • macOS:SDK 54 preview.13 为 macOS 增加 ExpoAppDelegate 与 AppDelegate subscribers 支持(55 preview 起移除 react-native-macos 0.79 的 workarounds)。

六、Android 原生层演进:Host 包装类退场与 New Architecture 对齐

Android 侧的主线与 iOS 对称,核心是移除旧架构时期的包装类、向 React Native 新架构的宿主 API 对齐:

  • SDK 55 preview.0(Breaking):删除 ReactNativeHostWrapper 类;55.0.0 移除遗留 autolinking 集成;SDK 53 起改用 Expo Modules Gradle Plugin;
  • ReactActivityDelegateWrapper:从生命周期原子性(53.0.19)、Android 10 的 onWindowFocusChanged NPE(53.0.18)、低内存重建 Activity 时 onActivityResult 的传播(46.0.0-alpha.0)、onPauseAssertionError(52.0.14)到 54.0.21 移除 edge-to-edge 逻辑——这一包装类被反复修补,最终在新架构下逐步退场;
  • Edge-to-edge 兼容:54.0.19 修复 enableMinifyInReleaseBuilds 为 true 时 edge-to-edge 失效的问题;54.0.0-preview.0 修复 RN 的 enableEdgeToEdge Gradle 属性被忽略的问题;
  • bridgeless 模式:SDK 51 起为 ReactNativeHostHandler 增加 bridgeless 支持、onReactInstanceException() 等钩子,供 expo-updates 处理异常与错误恢复(onDidCreateDevSupportManager);
  • R8 混淆兼容:51.0.0-beta.0 修复 R8 开启时 getReactHostNoSuchMethodException 的问题。

七、DOM Components 与 expo/dom:WebView 内运行 Web 组件

7.1 诞生与默认化

  • SDK 52(52.0.0-preview.0):引入 DOM Components 初始版本与 expo/dom 模块,同时提供 useDOMImperativeHandlematchContents prop、useExpoDOMWebView 等能力;
  • SDK 56(56.0.0-preview.0,Breaking)@expo/dom-webview 成为 DOM 组件的默认 WebView 实现(配套修复其 initialProps 不稳定与重载问题);
  • Unpublished 段:修复 expo/domexpo/dom/internal 子路径导出的平台解析。

7.2 能力补全

DOM Components 在 SDK 52 周期内快速成型:52.0.0-preview.5 加入 router 支持;52.0.0-preview.19 加入 EAS Updates 支持;52.0.37 修复 EAS Update 下 DOM Components 的支持;52.0.30 增加 debug 期零高度 DOM 组件的告警样式;process.env.EXPO_DOM_HOST_OS(SDK 55 preview.0)用于在 DOM 组件内检测其原始宿主平台;$$EXPO_INITIAL_PROPS(54.0.5)用于判断是否运行在 DOM 组件内;Unpublished 段修复 DOM 组件在 WebView 加载期间丢弃 prop 更新的问题。

八、异步模块(async-require)与 Metro 集成

  • SDK 54(54.0.0-preview.0):默认启用 async requires(Enable async requires by default),配合 expo/internal/async-require-module(54.0.21)作为 @expo/metro-configasyncRequireModulePath
  • SDK 55 preview.0async-require 增加 unstable_createWorker helper;56.0.10 让 async require 返回带同步 bailout 的 thenable;
  • Unpublished 段:修复 async imports 返回的不是完整 promise 形状的 thenable 问题;修复 Metro 断开后 async chunk 加载时误调 window.location 的问题;
  • Metro 版本:自 SDK 54 起切换到 @expo/metro 封装包,后续持续升级(54.1.0 → 56.0.0 → 56.1.0,对应 metro 0.83.x → 0.84.x)。

九、破坏性变更汇总与升级注意点

将 CHANGELOG 中所有 🛠 Breaking changes 归纳如下,升级前建议逐条核对:

版本 破坏性变更
Unpublished Node.js 最低版本提升至 ^22.13.0
56.0.0-preview.10 expo 依赖中移除 @expo/vector-icons(仅影响依赖它被间接带入的项目)
56.0.0-preview.0 iOS/tvOS 最低 16.4、macOS 13.4;expo/fetch 成为默认 fetch;DOM 组件默认用 @expo/dom-webview
55.0.0-preview.0 移除 iOS EXAppDelegateWrapper;移除 Android ReactNativeHostWrapper
54.0.0-preview.5 默认启用 RN Strict TypeScript API typings(除非使用内部 API,否则非破坏)
53.0.0-preview.0 升级 RN 至 0.78;expo/types 导出变更;移除 DevToolsPluginClient 的 protected eventEmitter 与 fbemitter
51.0.0-beta.0 放弃 RN 0.73 及更低版本
50.0.0-alpha.2 放弃 Android SDK 21/22;移除遗留 hashAssetFiles
50.0.0-alpha.1 移除 Logs 模块导出与 logUrl 端点
47.0.0-alpha.1 移除 expo-error-recoveryexp.errorRecovery 根组件 props;iOS 13.0 起弃用 iOS 12
49.0.0-alpha.1 移除 EXPO_USE_LOCAL_CLI,本地 CLI 统一走 expo

配套源码佐证:当前包的 exports 映射expo-source 条件指向 src/(对应 SDK 52 起"以 src 目录作为 Metro 目标"的变更),Expo.ts 则集中展示了核心导出面——registerRootComponentexpo-modules-core 各类重导出、useEvent/useEventListener 等 hooks,以及 reloadAppAsync(SDK 51 preview.11 引入)。

十、如何将 CHANGELOG 用于日常研发

  1. 升级评估:先扫 Unpublished 与目标版本的 Breaking changes 与 Notices,再核对 RN 支持版本与平台最低版本,最后检查自己使用的 API 是否在移除列表(如 EXAppDelegateWrapper@expo/vector-icons 间接依赖)。
  2. 能力溯源:想确认某个 Web API 在当前 SDK 是否可用,直接检索 CHANGELOG 中对应的 "Add ... to native platforms" 条目与 src/winter 目录,源码与测试(如 AbortSignal.test.native.tsDOMException.test.native.tsstructuredClone.test.ios.tsTextDecoderStream.test.ios.ts)即可给出确定性答案。
  3. 行为变更追踪expo/fetch 这类高频模块,其行为(如流式取消、压缩解码、Response.clone)的每一次调整都能在 CHANGELOG 中找到对应条目,配合 fetch.ts 的实现阅读,可快速定位升级后行为差异的原因。

这份 CHANGELOG 既是历史档案,也是当前仓库开发状态的实时窗口——持续关注其 Unpublished 段,就能始终领先版本发布一步。

热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
docsdocs
暂无描述
Markdown
900
5.83 K
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.76 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.35 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
927
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.94 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
603
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
396
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.04 K
527