最近,我在更新自己的 FinTech 应用 TransferIQ 时遇到了一个非常典型、也非常折磨人的问题:
AAB 可以正常构建。
Google Play 可以正常上传。
应用也可以完成更新。
但是——
更新后的应用一打开就无法正常启动。
最麻烦的是,表面上看不出明显原因。
一开始,我怀疑过很多东西:
- AsyncStorage 中保留了旧版本数据
- 新旧版本状态结构不兼容
- Expo / React Native 缓存问题
- API 初始化失败
- Supabase 配置异常
- 更新后的 JavaScript Bundle 冲突
这些猜测听起来都合理。
但最后证明,真正的问题完全不在 JavaScript 层。
一、第一步:不要继续猜,先看设备日志
我的项目使用:
- React Native
- Expo SDK 54
- Android AAB
- Google Play
- react-native-google-mobile-ads
首先通过 USB 连接 Android 手机,然后运行:
adb devices
一开始设备状态是:
unauthorized
这意味着电脑已经识别到手机,但手机还没有授权 ADB 调试。
在手机上重新允许 USB debugging 后,状态变成:
device
到这里,才真正具备读取设备日志的条件。
二、清理旧日志,再复现问题
为了避免系统日志太多,我先清空 Logcat:
adb logcat -c
然后强制停止应用:
adb shell am force-stop com.jkim1285.TransferIQMobile
接下来:
- 在手机上重新打开应用
- 复现启动失败
- 等待几秒
- 导出当前日志
使用:
adb logcat -d > transferiq-fresh.txt
这一步对我非常重要。
与其一直盯着实时 Logcat,不如先复现问题,再一次性导出日志。这样不需要一直保持终端运行,也更容易分析。
三、最终找到真正的错误
日志中出现了:
FATAL EXCEPTION: main
以及:
Unable to get provider
com.google.android.gms.ads.MobileAdsInitProvider
更关键的是:
Invalid application ID
看到这里,问题终于清楚了。
应用甚至还没有真正进入 React Native 的 JavaScript 逻辑。
它在 Android 原生初始化阶段就已经崩溃了。
真正的问题是:
AdMob Application ID 配置错误。
四、一个非常容易混淆的细节:App ID 和 Ad Unit ID 不是一回事
这是这次问题里最容易踩坑的地方。
AdMob App ID 通常类似:
ca-app-pub-xxxxxxxxxxxxxxxx~xxxxxxxxxx
注意中间是:
~
而 Banner Ad Unit ID 通常类似:
ca-app-pub-xxxxxxxxxxxxxxxx/xxxxxxxxxx
注意中间是:
/
两者看起来很像,但用途完全不同。
App ID 用于应用级别的 AdMob 初始化。
Ad Unit ID 用于具体广告位,例如:
- Banner
- Interstitial
- Rewarded Ad
在我的项目代码里,Banner Ad Unit ID 本身没有问题。
真正的问题出现在 Native Config。
也就是说,广告组件代码可以是正确的,但如果 Android 原生层没有正确配置 Application ID,应用仍然可能在启动阶段直接崩溃。
五、React Native / Expo 项目不能只修改 App.js
这是我这次学到的另一个关键点。
对于 Expo 项目,AdMob 初始化涉及 Android 原生配置。
不能只修改:
App.js
还需要在 Expo config 中正确设置类似:
[
"react-native-google-mobile-ads",
{
"androidAppId": "ca-app-pub-xxxxxxxxxxxxxxxx~xxxxxxxxxx"
}
]
然后重新构建新的 Android AAB。
换句话说:
App.js 修改
≠
Native Config 修改
很多移动端问题,尤其是下面这些功能:
- Ads
- Notifications
- Permissions
- Deep Links
- Native SDK
- Android Providers
都不能只从 JavaScript 层思考。
六、为什么这个问题特别容易误判?
因为整个发布流程表面上都可能是正常的。
例如:
- npm install 成功
- Expo build 成功
- EAS Build 成功
- AAB 文件成功生成
- Google Play 上传成功
- Google Play 更新成功
- 用户完成安装成功
但应用依然可以在启动瞬间崩溃。
也就是说:
Build Success
≠
Runtime Success
Store Upload Success
≠
Native Configuration Correct
这对 AI-assisted development 尤其重要。
AI 很容易告诉你:
“可能是缓存问题”
“可能是 AsyncStorage”
“可能是状态迁移”
“可能是 API”
“可能是 Expo”
“可能是旧版本数据”
这些可能性都不是完全错误。
但真正的问题必须通过证据确认。
七、我这次最大的教训
这次问题让我重新确认了一件事:
当 Android 应用出现“更新后启动即崩溃”时,不要长时间依赖猜测。
更有效的顺序是:
- 确认设备连接
- 确认 adb devices 显示 device
- 清理旧日志
- 强制停止应用
- 重新打开并复现问题
- 导出 Logcat
- 搜索 FATAL EXCEPTION
- 判断问题发生在 JS 层还是 Native 层
- 再修改代码或配置
我前面花了不少时间怀疑:
- 缓存
- 状态迁移
- 旧数据
- JavaScript Bundle
- API 初始化
但真实日志最终只用了几行就告诉我:
Invalid application ID
问题其实非常直接。
八、对 AI 辅助开发的另一个提醒
我不是传统软件工程师。
我的主要背景是 8 年以上的 FinTech、Crypto、Operations 和 Product 经验。
目前我通过 AI 辅助方式独立开发 TransferIQ。
AI 可以:
- 快速生成代码
- 修改 UI
- 分析错误
- 提供命令
- 提出可能原因
- 帮助非工程背景的人完成真实产品
但这次经历再次说明:
AI 给出的“可能性”很多,
而真正的工程问题最终还是要依靠:
- 日志
- 复现
- 证据
- 配置检查
- 实际运行结果
尤其在移动端,下面几个层次经常混在一起:
JavaScript
Native Android
Build Config
Expo Config
Third-party SDK
Google Play Update
只看 App.js,很容易找错方向。
九、最终结论
这次真正的问题不是:
- AAB 构建失败
- Google Play 上传失败
- React Native 页面错误
- AsyncStorage 冲突
- Supabase 错误
- API 错误
而是:
AdMob Native Initialization
Invalid Application ID
App crashes before JavaScript starts
如果你也遇到 Android 应用更新后无法启动,我非常建议先看 ADB Logcat,而不是继续猜。
有时候,一行真实日志,比几十个“可能原因”更有价值。
我正在继续开发 TransferIQ,一个用于比较跨境汇款、FX、Crypto、Stablecoin 和本地收款路径的独立平台。
TransferIQ 不托管用户资金,也不执行支付。
产品的目标是帮助用户在正式发送资金之前,比较不同路线的预估接收金额、费用、FX spread 和路径差异,再前往官方 provider 或 exchange 确认最终报价。
这次故障排查,也是我一个人构建、发布和维护真实产品过程中的一部分。
对我来说,这可能不是最后一次遇到这种问题。
但至少下一次,我会先打开日志,而不是先猜。