
做React Native开发这几年我最大的感受是真正让项目进度卡壳的往往不是业务逻辑而是依赖选型这件事。尤其到了SDK 54这个节点新架构New Architecture已经从可选变成默认很多老教程里的装包就走已经失效了。导航、状态管理、存储、原生能力桥接每一类依赖都得重新评估一遍兼容性。这篇文章把我近期在SDK 54环境下做原生开发时沉淀的常用依赖清单、安装顺序、版本匹配逻辑以及启动白屏、安卓端回声消除这些高频问题的处理经验整理出来属于可以直接照着抄作业的那一类内容。1. SDK 54到底是个什么版本1.1 版本号背后的真实环境和物料先说清楚一件事项目标题里写的SDK 54不是Android的API Level也不是React Native传统语义里的0.x大版本号。它通常是社区里用来指代Expo SDK 54这一整套工具链的编号对应React Native 0.81这个版本。如果你用的是React Native社区版裸工程bare workflow你更熟悉的叫法是RN 0.81如果你用Expo的托管工作流SDK 54就是你在expo依赖里锁定的版本代号。不管走哪条路底层的原生侧变化是一致的新架构全面默认启用Fabric渲染器和TurboModule成为标准路径Hermes是默认的JavaScript引擎Android侧的targetSdk已经到35Gradle版本和AGP版本也都跟着抬了一截。这对依赖选型的影响是决定性的。以前我们可以随便装一个三年没更新的库反正旧的native模块走JSC、走Paper架构也能跑。现在不行了。凡是带有原生代码的依赖必须确认它支持Fabric和TurboModule否则轻则构建报错重则启动直接白屏。我自己就遇到过因为某个老版本的地图库在Fabric下没法挂载原生View导致整个RN页面渲染不出来的情况最后只能换库。所以理解SDK 54的版本含义本质上是理解这个时间点该用什么方式去验证依赖。1.2 为什么依赖选型在新架构下变得这么敏感新架构带来的第一个变化是原生模块的通信方式变了。老的Bridge是一份JSON消息在两个线程里来回传TurboModule则是直接通过JSI接口做同步/异步调用。这个改动让很多老的原生依赖能编译但不稳定尤其是那些直接操作UIManager、或者在Fabric接管视图层级之后还尝试手动插入原生View的库基本都会出问题。第二个变化是构建链路。RN 0.81默认启用新架构之后Android构建时会走Codegen生成C互操作代码这个过程对依赖的package.json、podspec、build.gradle的配置要求很严格。第三个变化是引擎层面的。Hermes对JSC时代的某些API做了裁剪一些依赖如果用了非标准的ES特性运行时就会抛异常。我整理了一个简单的选型判断逻辑给团队新人用第一去npm看这个库最近一次发版时间超过8个月没更新的直接存疑。第二看它是否明确在README或changelog里提到支持新架构。第三搜一下GitHub issues里有没有Fabric、TurboModule相关的问题如果有且长期没关闭说明维护方还没跟上。第四如果项目里有原生代码不要只看npm上的版本号还要看它是否发布了带原生module的对应版本。这套判断逻辑帮我避开了至少5个会在SDK 54环境下翻车的依赖。2. 常用依赖全景拆解一个真实项目的依赖清单2.1 导航与页面容器层导航是RN项目的骨架这一层我目前的标准配置是React Navigation 7.x配合react-native-screens和react-native-safe-area-context。React Navigation本身是纯JS状态的解决方案但页面切换的流畅度完全靠react-native-screens在原生侧接管视图层级所以这两个库必须一起上。react-native-screens目前最新的4.x版本已经完整支持Fabric安装之后在Android上能明显感觉到页面切换的帧率比纯JS方案稳得多。这里有个细节值得说react-native-safe-area-context的版本选择要看你的目标机型。现在的手机屏幕形态五花八门刘海、挖孔、灵动岛SafeArea处理不好页面顶部要么被摄像头区域挡住要么底部被Home Indicator吃掉。这个库在SDK 54环境下建议直接用5.x它对新架构的支持最完整特别是在Android edge-to-edge模式全面铺开之后老的SafeArea方案在Android 15上会变得不可靠。安装顺序也讲究先装react-native-screens和react-native-safe-area-context再装React Navigation最后在入口文件里调用enableScreens()来启用原生容器加速新版可能默认开启但显式调用更稳妥。启动白屏问题也和导航这层有直接关系。如果你用了react-native-bootsplash这类启动屏方案它本质上是让原生侧在JS bundle加载完成之前先展示一张图片避免用户看到白屏。在SDK 54下bootsplash的显示和隐藏时机非常关键我会在后面的实操部分专门讲这个排查过程。2.2 状态管理与服务端数据请求状态管理我现在的首选是Zustand没有之一。Redux Toolkit依然好用但它的样板代码和中间件体系对一个追求轻量的RN项目来说有点重。Zustand 5.x体积小、没有Provider包裹、API直观配合TypeScript使用体验很好而且它没有原生依赖完全不受新架构影响属于闭眼装的那一类。项目里还有一个Jotai也在用适合处理原子化的局部状态但它和Zustand的边界需要团队约定清楚否则会出现同一个状态既用Zustand又用Jotai的混乱局面。服务端数据请求这一块我强烈建议把TanStack Query就是以前的React Query纳入标配。RN项目的服务端状态管理和Web端有区别核心在于缓存失效、请求去重、分页加载这些能力。TanStack Query 5.x把请求状态、缓存、重试、窗口聚焦重新请求这些逻辑全部封装好了。配合axios做HTTP请求整体网络层就非常干净。也许你会问直接用axios自己写请求函数不就行了行但一旦涉及到你的页面要对同一份数据进行多个组件共享刷新、下拉刷新、失败重试、乐观更新自己写的代码会膨胀得很快。TanStack Query的意义是把这些状态机的复杂性收拢到一个库里面长期维护成本低很多。2.3 UI组件库与样式方案UI层是SDK 54下变化最大的一块。以前很多人用NativeBase但这几年维护节奏变慢新架构支持一直不明朗。我现在的建议是分两派如果你需要一套完整组件库看Tamagui或Gluestack如果你只是要个轻量的样式方案Tailwind React Native或直接用StyleSheet也行。Tamagui的核心优势是它把样式系统和组件系统做在一起并且支持跨平台编译优化主题定制能力很强和Reanimated、Gesture Handler配合做动画很顺手。Gluestack则是NativeBase的官方继任者如果你已经有NativeBase的使用习惯迁移到Gluestack的曲线平缓很多。样式方案这里要提一句styled-components。如果你还在用比较老的版本在SDK 54下建议留意一下和Reanimated的兼容性。styled-components v6和React Native新架构的配合目前没有大问题但它会引入额外的运行时开销。相比之下Tailwind风格的原子化类名方案如NativeWind在开发效率上优势明显特别是团队里设计师习惯用Tailwind的语法表达样式时沟通成本会降低。但NativeWind还需要Babel插件和PostCSS链路配置起来比StyleSheet复杂取舍需要你自己权衡。2.4 数据存储与安全加固本地存储我推荐直接上MMKV。它基于腾讯早期开源的MMKV内存映射方案读写性能比AsyncStorage高出不少而且支持加密存储。react-native-mmkv 3.x已经完全适配新架构这在SDK 54环境下是个安心牌。对于不敏感的业务数据比如用户偏好设置、缓存配置用它非常顺手。AsyncStorage依然可以用但它在处理大体积数据时有性能瓶颈尤其是频繁写入的场景所以我现在的新项目基本都直接MMKV起步。敏感信息这层要单独说。Token、密钥、用户隐私数据不要直接放MMKV的未加密空间更不要用明文写进AsyncStorage。我的习惯是用react-native-keychain它在iOS用的是KeychainAndroid用的是Keystore能力上足够安全。如果想在MMKV加密字段和Keychain存储之间做个折中也可以用react-native-encrypted-storage它内部会做AES加密对业务代码的改动更小。安全这块没有装了就完事你还需要在代码层做好防调试、防抓包的配套措施依赖只是最后一公里的加固。3. 高版本兼容性这些依赖必须注意的配置细节3.1 新架构兼容性检查清单SDK 54默认开启新架构这意味着每一个依赖都要过一遍兼容性检查。我通常会在android/app/build.gradle和ios/Podfile里确认新架构开关的状态然后在RNDoctor或者npx react-native config的输出里检查原生模块列表。对于第三方原生依赖最好的验证方式不是看README而是直接跑一遍Android构建看有没有codegen相关任务报错。我自己维护了一份检查清单第一package.json里的peerDependencies是否声明了RN 0.81支持第二Android侧是否有build.gradle里正确配置了autolinkLibrariesWithApp第三iOS侧是否提供兼容新架构的podspec旧的静态库或需要手动pod install --deployment才会暴露问题第四运行时是否依赖旧的原生事件机制DeviceEventEmitter在新架构里通过TurboModule订阅事件的方式已经不一样。只要有一项不满足这个依赖就值得被替换。3.2 Android原生模块中的特殊节点回声消除热词里那个安卓原生开发回声消除其实很容易被忽略但它在语音通话、直播连麦、语聊房场景下是绕不开的需求。回声消除AECAcoustic Echo Cancellation解决的问题是扬声器放出的声音会被麦克风重新采集导致对端听到自己的声音。在Android原生开发中系统从API 16开始提供了AcousticEchoCanceler你可以用它来控制硬件层面的回声消除。在RN里做语音相关功能我一般分两步能复用WebRTC能力就复用。react-native-webrtc这个库内部集成了WebRTC的音频处理模块自带AEC、噪声抑制NS、自动增益AGC在语音通话场景下直接用它最省事。如果业务只是录音播放这种轻量需求不想引入这么重的依赖就需要自己写原生模块去调用AcousticEchoCanceler。原生侧的Kotlin代码思路大概是先用AcousticEchoCanceler.isAvailable()判断设备是否支持再用AudioManager.getProperty(com.android.echo.cancel.supported)做二次确认最后通过AcousticEchoCanceler.create(audioSessionId)创建并启用实例。这块内容在周会的技术分享里我展开讲过结论就是别指望纯JS解决回声问题一定得走原生层。3.3 依赖版本锁定与升级策略SDK 54项目初始化完成之后第一件事就是把package.json里的版本号全部锁死。RN生态对版本漂移非常敏感一个minor版本的变化可能引发原生依赖的连锁反应。我的习惯是精确写版本号不用^前缀或者用package-lock.json配合yarn.lock固定住整棵依赖树。每次升级依赖之前先看react-native官方发布的依赖兼容表再对照第三方依赖的changelog确认没有破坏性变更再动。升级策略我推荐小步快跑不要憋几个月升一次大版本那样的话一旦出问题你根本分不清是哪个依赖引入的。每两周左右做一次依赖扫描使用npx react-native upgrade或Expo的版本升级工具逐步把依赖推到最新稳定版。SDK 54对Node版本有要求Node 18JDK也要到17这些环境问题在升级前就要处理好否则构建日志里全是看不懂的底层报错。4. 实操过程从零初始化SDK 54项目并安装依赖4.1 初始化项目与环境确认初始化这一步本身就是依赖管理的第一关。我用的是React Native社区版的初始化命令跑npx react-native-community/clilatest init MyApp这一步拉下来的是最新的稳定模板也就是0.81。如果你想用Expo工具链则直接npx create-expo-applatest它会明确提示你当前SDK的版本号。初始化完成后进到项目目录确认三个关键信息package.json里react-native版本android/build.gradle里的SDK版本配置以及iOS工程的deployment target。然后跑一次npx react-native doctor它会检查JDK、Android SDK、Node版本是否匹配。这一步很关键很多白屏问题在开发早期就是环境不匹配埋下的雷。确认完毕之后不要急着装业务依赖先把npm install或者yarn跑通再执行一次./gradlew assembleDebug。我见过太多团队跳过这一步直接装了一堆依赖之后才来排查构建错误最后根本分不清是环境问题还是依赖冲突。4.2 依赖安装序列与构建验证装依赖不是一把梭哈而是有顺序的。我的惯例是分成五到六个批次每个批次装完立刻跑一次Android构建确保问题能精准定位到具体依赖批次。第一批发导航三件套react-navigation/native、react-navigation/native-stack、react-native-screens、react-native-safe-area-context。第二批发状态管理和请求层zustand、tanstack/react-query、axios。第三批发存储react-native-mmkv、react-native-keychain。第四批发UI相关react-native-reanimated、react-native-gesture-handler、react-native-bootsplash。第五批发原生能力react-native-permissions、react-native-device-info。最后是音频和多媒体相关react-native-track-player、如果涉及通话再加react-native-webrtc。每次批处理都用yarn add安装装完直接跑构建。这里有个经验react-native-reanimated和react-native-gesture-handler这类带Babel插件的依赖装完还要额外检查babel.config.js在plugins里加入react-native-reanimated/plugin并且这个插件必须放在最后一位否则会报错。react-native-mmkv装完之后要检查Android的ProGuard配置release版本如果没把mmkv的keep规则加上会出现运行时空指针。这些细节写在官方文档里但实际开发中经常被跳过最后成了为什么我的依赖列表和教程一样但就是跑不起来的原因。4.3 启动白屏问题排查实录启动白屏是React Native开发里最折磨人的问题之一。它的典型表现是应用冷启动后原生启动画面一闪而过然后整个屏幕白着要等好几秒甚至十几秒才渲染出首页。我在SDK 54环境下遇到过三次这种问题排查思路基本一致。第一次是因为入口注册名不一致导致JS层根本没有渲染。App原生端调用getMainComponentName()返回一个字符串而JS端用AppRegistry.registerComponent()注册的名字必须和它完全一致。我那次就是因为团队里有人改了原生端的名字但没同步改JS端结果bundle加载完了但组件始终挂不上页面就一直白屏。排查方法是看adb logcat里有没有ReactNative: AppRegistry.registerComponent相关的报错以及检查Metro终端是否有渲染日志。第二次是Hermes导致的。SDK 54默认Hermes但如果某个依赖调用了Hermes不支持的API运行时虽然不会崩溃但会让渲染流程卡在某个阶段。这类问题比较隐蔽我的排查办法是渐进式关闭Hermes做对照实验确认问题是否由引擎引起。第三次是启动屏和React根视图的时序问题。如果用了react-native-bootsplash入口处调用SplashScreen.hide()的时机太早JS侧还没准备好也会出现白屏闪烁。正确的做法是在根组件挂载完成之后再隐藏启动屏或者在原生MainActivity里控制启动屏的show和hide顺序确保JS bundle加载完成前用户始终看到的是启动图而不是白屏。5. 常见问题速查表与避坑指南5.1 依赖冲突与版本地狱这一类是我收到咨询最多的内容。症状通常是Android构建时Namespace not specified、iOS执行pod install时版本冲突或者安装依赖后出现A problem occurred configuring project :app。原因大概率是多个依赖要求了同一个原生模块的不同版本或者是某个依赖的传递性依赖和主项目的react-native版本不匹配。我建议先用npx react-native doctor和npm ls检查依赖树再逐级锁定版本。如果问题出在原生模块的Gradle配置上可以用Gradle的resolutionStrategy强制指定版本但要慎重因为原生代码编译期和运行期的版本不一致会引发更难排查的问题。5.2 启动白屏的快速定位清单我把白屏问题整理成了一个速查表收到反馈时按顺序过一遍。第一看JS bundle加载Metro终端有没有成功打包的日志。第二看原生日志adb logcat -s ReactNativeJS里有没有JS异常。第三看入口注册是否匹配原生端和JS端名字一致。第四看Hermes关掉Hermes对照测试。第五看依赖是否阻塞主线程在Debug模式用Profiler看有没有长时间运行的原生任务。第六看启动屏时序bootsplash的hide时机是否过早。大部分白屏问题到第二步就能定位如果走到第六步还没找到原因那就是多个因素叠加建议二分法逐步禁用依赖来缩小范围。5.3 依赖体积与性能调优SDK 54新架构下依赖体积会直接影响启动时间。我常用的两个工具是npx depcheck和React Native自带的bundle分析。depcheck能找出package.json里声明了但从未被引用的依赖这种依赖在原生侧如果还注册了模块会白白增加构建体积和启动耗时。bundle分析则可以用来观测JS包的最终大小react-native-reanimated、react-native-vision-camera这类功能强大的库都会显著增大包体积如果你只是用到很小一部分能力建议寻找更轻量的替代方案。我见过一个比较极端的例子一个仅用于二维码扫描的功能团队引入了一个完整的相机库体积增加了几MB实际上用社区版轻量扫描库甚至调用原生Intent就能解决。依赖选型的底层逻辑永远是够用就好。在新架构全面铺开的阶段维持一份干净、可控、每个依赖都被验证过的依赖清单比追逐堆叠更多功能库要重要得多。最后说一句个人体会在SDK 54这个节点上维护依赖不再只是npm install一把梭这么简单。新架构是默认值不是选项这意味着你的每一项依赖都要经过Fabric、TurboModule、Hermes这三重考验。我现在的常用配置是React Navigation Zustand TanStack Query MMKV react-native-screens加上Reanimated做动画、react-native-bootsplash解决启动体验覆盖了90%的业务场景。这套组合在多个项目里都验证过启动速度、构建稳定性、新架构兼容性都过关。如果你正准备在这个版本环境下起步照着这套依赖清单走至少不会在起步阶段被版本兼容问题折磨。