《融天AI-APP从0到1开发实录》

第二篇:React Native + Expo Android 真机/生产包踩坑记录:从接口代理、键盘到 ECharts 和弹窗滚动

最近在开发一个基于 React Native + Expo 的移动端 AI 管理项目,开发环境下功能基本正常,但是到了 Android 真机以及正式打包后的 APK,就陆续出现了一系列问题。

这些问题比较典型,很多都是:

Web / Expo 开发环境正常 → Android 真机异常 → Android Release 包更加异常

因此把这次遇到的问题统一整理下来,方便以后排查,也希望能给遇到类似问题的人提供一些参考。


一、Node.js 后端接口:Postman 正常,Node 请求却 500

1. 问题现象

后端接口开发完成以后,使用 Postman 请求接口:

复制代码
请求成功

但是 Node.js 服务中使用 Axios 请求同一个接口,却出现:

复制代码
500 Internal Server Error

当时已经确认:

  • URL 正确

  • Token 正确

  • 请求参数正确

  • 请求头正确

  • Postman 可以正常请求

所以一开始很容易怀疑是:

  • Token 转发问题

  • 请求参数格式问题

  • 后端接口问题

  • Axios 配置问题


2. 最终原因

最终发现:

Node.js 请求走了系统代理。

Axios 默认可能会读取环境变量中的代理配置,例如:

复制代码
HTTP_PROXY
HTTPS_PROXY
http_proxy
https_proxy

而 Postman 默认并不会按照完全相同的方式使用系统代理。

于是就出现了:

复制代码
Postman
    ↓
目标服务器
    ↓
正常

Node.js + Axios
    ↓
系统代理
    ↓
目标服务器
    ↓
500 / 请求异常

3. 尝试解决

最开始尝试在 Axios 中关闭代理:

复制代码
axios.create({
  proxy: false,
});

但是实际环境中仍然没有解决问题。

最终直接放弃 Axios 的这条请求链路,改成 Node.js 原生 fetch。

也就是说:

复制代码
Axios
    ↓
系统代理问题
    ↓
fetch
    ↓
正常

4. 经验总结

以后遇到:

Postman 正常,但 Node.js 请求异常

不要只盯着:

  • Token

  • 参数

  • Header

  • URL

还应该检查:

复制代码
HTTP_PROXY
HTTPS_PROXY
NO_PROXY

以及 Node.js 请求库是否自动读取代理环境变量。

尤其是公司网络、VPN、代理软件、科学上网环境下,这类问题非常容易出现。


二、Android 真机键盘:输入框没有自动顶上来

1. 问题现象

AI 聊天页面中,点击输入框以后:

开发环境:

复制代码
正常

Android 真机:

复制代码
键盘弹出
但是输入框没有跟着往上移动

结果就是:

键盘把输入框挡住了。

体验非常差。


2. 原因

Android 默认的软键盘布局行为和 Web / iOS 并不完全一样。

最终通过修改:

复制代码
android/app/src/main/AndroidManifest.xml

找到:

复制代码
<activity
    android:name=".MainActivity"

增加:

复制代码
android:windowSoftInputMode="adjustResize"

例如:

复制代码
<activity
    android:name=".MainActivity"
    android:windowSoftInputMode="adjustResize"
    ...>

3. Expo 配置

同时在 app.json 中配置:

复制代码
{
  "android": {
    "softwareKeyboardLayoutMode": "resize"
  }
}

这样可以让 Android 在键盘出现时重新调整窗口尺寸。


4. 经验

React Native 的键盘问题不能只看 React 组件本身。

尤其是:

复制代码
KeyboardAvoidingView
KeyboardAwareScrollView
FlatList
Modal
Android Manifest
Expo 配置

这些实际上是一个整体。

开发环境正常,并不意味着 Release APK 的软键盘行为一定正常。


三、ECharts:本地正常、Expo 真机正常,Android Release APK 却不显示

这是这次比较典型的问题之一。

1. 问题现象

同一份代码:

浏览器开发环境

复制代码
ECharts 正常

Expo 手机开发环境

复制代码
ECharts 正常

Android 打包后的 APK

复制代码
页面正常
ECharts 容器正常
Y 轴正常
X 轴正常
但是曲线完全没有

也就是说:

不是整个页面崩溃,而是图表数据/渲染链路在 Release 环境出现了差异。


2. 排查方向

这类问题不能简单认为是 ECharts 本身的问题。

应该依次检查:

复制代码
API 数据
    ↓
数据转换
    ↓
ECharts option
    ↓
WebView / Native 渲染
    ↓
Android Release 环境

重点检查:

  • Release 包中 API 是否真的返回数据

  • 数据是否存在 undefined / null

  • 时间字段格式是否一致

  • option 是否完整

  • WebView / ECharts 是否正确加载

  • 是否存在开发环境和 Release 环境差异

  • 是否有 Android Release 下的资源加载问题

  • 是否存在异步数据初始化时机问题


3. 一个非常重要的经验

开发环境能够正常运行,只能证明:

当前开发环境下的运行链路是正常的。

不能证明:

Android Release 环境下的运行链路也是正常的。

所以以后遇到:

复制代码
Dev 正常
Expo Go 正常
APK 异常

第一反应应该是:

检查 Release 环境差异,而不是马上重写业务代码。


四、Android Release 登录失败:接口本身没问题,却请求不到

1. 问题现象

登录接口:

浏览器

复制代码
成功

Expo 手机

复制代码
成功

Android APK

复制代码
登录失败

但是后端接口本身没有问题。


2. 原因

最终发现 Android Release 对 HTTP 明文请求有限制。

项目接口使用的是:

复制代码
http://...

而不是:

复制代码
https://...

Android 默认会限制明文 HTTP 流量。


3. AndroidManifest.xml

在:

复制代码
android/app/src/main/AndroidManifest.xml

的 <application> 中增加:

复制代码
android:usesCleartextTraffic="true"

例如:

复制代码
<application
    android:usesCleartextTraffic="true"
    ...>

4. Expo 配置

同时在:

复制代码
app.json

中:

复制代码
{
  "android": {
    "usesCleartextTraffic": true
  }
}

这样 Expo/EAS 构建出来的 Android 项目也会带上对应配置。


5. 经验

如果 Android APK 请求的是:

复制代码
http://192.168.x.x

或者:

复制代码
http://服务器IP

而不是 HTTPS:

一定要检查 Android 的明文流量配置。

不过从长期来看:

生产环境还是应该尽量使用 HTTPS,而不是长期依赖 usesCleartextTraffic=true**。**

这个配置更适合作为当前项目阶段的解决方案。


五、Android Release 进入首页直接闪退

1. 问题现象

登录成功之后:

复制代码
进入首页
↓
立即闪退

开发环境却没有问题。


2. 原因

最终定位到部分第三方库的引入方式存在问题。

例如:

复制代码
sm-crypto

某些模块的导入方式在开发环境能够工作,但是到了 React Native Android Release 环境后,会因为模块打包、动态加载等差异产生问题。


3. 经验

React Native 项目中:

"开发环境能 import" ≠ "Release APK 一定能 import"。

尤其需要注意:

  • Node.js 专用模块

  • 浏览器专用 API

  • 动态 import

  • CommonJS / ESM 混用

  • crypto 相关库

  • 依赖 Node.js 原生能力的第三方包

因为 React Native 并不是完整的 Node.js 环境。


1. 问题现象

AI 弹窗设置成:

复制代码
height: 100%

以后,Modal 会直接覆盖整个手机屏幕。

但是 Android 手机顶部还有:

复制代码
时间
电量
网络
状态栏

结果:

复制代码
右上角操作按钮
        ↓
被状态栏覆盖
        ↓
无法点击

2. 解决方案

使用:

复制代码
react-native-safe-area-context

获取安全区域。

同时针对 Android / iOS 设置顶部距离。

例如:

复制代码
top: Platform.OS === "ios" ? 50 : 16

这样可以让顶部操作区域避开系统状态栏。


3. 经验

在 React Native 中:

复制代码
100% 高度

不一定等于:

复制代码
用户真正可以安全使用的屏幕区域

特别是:

  • Android 状态栏

  • iPhone 刘海

  • Dynamic Island

  • 底部手势区域

都需要考虑 Safe Area。

所以全屏 Modal、Bottom Sheet、Drawer、Chat 面板等组件,最好从一开始就考虑:

复制代码
react-native-safe-area-context

七、React Native 样式:文字内部出现发白 / 光晕

1. 问题现象

部分文字看起来不是正常的纯色,而是:

复制代码
文字边缘发白
出现类似阴影/光晕

看起来很奇怪。


2. 原因

检查 CSS / RN Style 后发现存在:

复制代码
shadowColor
shadowOpacity
shadowRadius
elevation

这些属性。

尤其是在 Android 中:

复制代码
elevation

可能会产生比较明显的阴影效果。

如果这些样式被错误地应用到了文字容器或者 Text 本身,就可能出现:

复制代码
文字 + 阴影

从视觉上表现为:

复制代码
文字发白 / 模糊 / 有光晕

3. 解决

将不必要的:

复制代码
shadowColor
shadowOpacity
shadowRadius
elevation

从文字相关样式中移除。

阴影只应用在真正需要产生阴影的:

复制代码
Card
Panel
Modal
Button

等容器上。


八、Modal / 弹窗:开发工具正常,真机偶尔滚动失效

这是目前比较麻烦的一类问题。

1. 问题现象

开发环境:

复制代码
Modal
↓
内容正常滚动

Android 真机:

复制代码
偶尔无法滚动

尤其是复杂弹窗中同时存在:

复制代码
Modal
KeyboardAvoidingView
ScrollView
FlatList
Touchable / Pressable

时更容易出现。


2. 原因方向

React Native Android 的 Modal 滚动问题通常不是单一组件导致。

复杂层级可能类似:

复制代码
Modal
 └── Overlay
      └── KeyboardAvoidingView
           └── View
                └── ScrollView
                     └── Content

如果外层存在:

复制代码
pointerEvents

或者:

复制代码
Pressable

覆盖层,再加上:

复制代码
KeyboardAvoidingView

动态改变布局,就可能出现:

页面看起来正常,但触摸事件没有正确传递给 ScrollView。


3. 排查方向

以后遇到这种问题,应该重点检查:

复制代码
① Modal 层级
② pointerEvents
③ Pressable / Touchable 覆盖范围
④ ScrollView flex
⑤ contentContainerStyle
⑥ nestedScrollEnabled
⑦ KeyboardAvoidingView
⑧ Android window resize
⑨ 手势事件是否被父节点拦截

尤其是:

开发者工具正常、真机偶发异常

这种情况,很可能属于真实 Android 触摸事件和开发环境行为之间的差异。


九、这次问题的整体规律

把这几个问题放在一起,会发现其实不是单独的几个 Bug。

它们都指向同一个问题:

React Native 项目的"开发环境"和"Android Release 真机环境"存在明显差异。

可以简单总结成:

复制代码
Web / Expo 开发环境
        ↓
功能正常
        ↓
Expo 真机
        ↓
大部分正常
        ↓
Android Release APK
        ↓
开始暴露环境差异

主要差异来自:

1. 网络环境

复制代码
HTTP / HTTPS
系统代理
Android 明文流量
局域网 IP

2. JavaScript 运行环境

复制代码
Node.js
Web
React Native
Hermes

它们并不是同一个运行环境。

3. Android 原生窗口行为

复制代码
键盘
Status Bar
Safe Area
Modal
Window Resize
触摸事件

4. Release 构建

开发环境:

复制代码
Metro
Dev Mode
Source Map

Release:

复制代码
Bundle
Hermes
Minify
ProGuard / R8
Native Android

所以很多问题只有在:

复制代码
eas build
→ APK
→ 真机

之后才会暴露。


十、最终形成一套排查思路

以后做 React Native + Expo 项目,我认为可以按照下面的顺序排查:

复制代码
                 ┌──────────────┐
                 │  功能开发完成  │
                 └──────┬───────┘
                        ↓
               ┌─────────────────┐
               │ 浏览器开发环境   │
               └────────┬────────┘
                        ↓
               ┌─────────────────┐
               │ Expo 真机测试    │
               └────────┬────────┘
                        ↓
                是否存在异常?
                  ↙           ↘
                否             是
                ↓               ↓
         继续 Release      检查 RN 代码
                ↓
        ┌─────────────────┐
        │ Android Release │
        │      APK        │
        └────────┬────────┘
                 ↓
          出现开发环境没有的 Bug
                 ↓
        优先检查 Android 环境差异
                 ↓
 ┌────────┬────────┬────────┬────────┐
 │ 网络   │ 键盘   │ Modal  │ 第三方库│
 │ HTTP   │ Resize │ Safe   │ Release │
 │ Proxy  │        │ Area   │ Bundle  │
 └────────┴────────┴────────┴────────┘

十一、总结

这次项目踩的坑,表面上看分别是:

  • Node.js 接口 500

  • Android 键盘不顶起

  • ECharts Release 不显示

  • Android 登录失败

  • Release 首页闪退

  • Modal 顶部按钮被遮挡

  • 文字出现阴影发白

  • 真机 Modal 滚动失效

但本质上可以归纳成三个方面:

后端

不要假设 Postman 和 Node.js 的网络环境完全一致。

尤其需要关注:

复制代码
系统代理
HTTP_PROXY
HTTPS_PROXY
Axios
fetch

React Native

不要只在开发环境验证 UI。

尤其是:

复制代码
Keyboard
Modal
ScrollView
FlatList
SafeArea
Android Window

这些都需要真机测试。

Android Release

Expo Go 正常 ≠ 最终 APK 正常。

正式发布前至少应该完整测试:

复制代码
登录
API 请求
HTTP / HTTPS
键盘
Modal
滚动
ECharts
动画
第三方库
页面跳转
返回键
状态栏
刘海 / Safe Area

最终比较重要的一条经验就是:

React Native 项目真正的"完成",不是在电脑上跑通,也不是 Expo Go 跑通,而是 Android Release APK 在真实设备上完整跑通。

这也是这次项目从 Web / Expo 开发环境走到 Android 真机过程中,最大的一个经验。

相关推荐
OpenAnolis小助手3 小时前
PHP 两个严重漏洞曝光,龙蜥社区 24 小时完成 3 版本修复
开发语言·操作系统·php·龙蜥社区
阿尼卡~3 小时前
VS Code 配置 C 语言开发环境(Windows 10/11):从 GCC 安装到运行、断点调试,一篇搞定
c语言·开发语言·windows
hhhjhl5 小时前
Undici 跨端三方库仓颉适配全流程
java·开发语言·ubuntu
染指11105 小时前
158.Agent-LangGraph-子图(共享状态和不共享状态模式)
开发语言·人工智能·python·ui·agent·agents
wangchunyu1145 小时前
JAVA JVM内存结构与运行时数据区
java·开发语言·jvm
slongzhang_5 小时前
linux 递归删除源码文件|递归删除目录下 *.js,但排除 *.min.js
linux·开发语言·javascript
云和数据.ChenGuang6 小时前
Python 常见特殊方法详解:__new__、__init__、__del__、__str__、__repr__ 与 __getattribute__
开发语言·人工智能·python·1024程序员节
xyouyuweizhu6 小时前
字节流与字符流:Java IO 的两条主线该怎么选
java·开发语言·python
多弗朗皮卡丘7 小时前
C++的IO流
开发语言·c++·io流·文件io流