uni-app如何实现App端内的全局异常捕获 uni-app错误日志上传系统【实战】需要先看清适用场景和关键步骤,避免只记结论却忽略实际限制。
App端需用uni.onError和uni.onUnhandledRejection捕获JS异常,二者须在App.vue的onLaunch中注册;原生崩溃需接入UMeng、Bugly等SDK,通过插件市场引入原生插件;上报日志须结构化携带上下文,加锁防死循环,并脱敏敏感信息。
uni-app在App端(iOS/Android)无法直接用window.onerror或Promise.catch兜住所有错误,因为原生容器运行环境与Web不同。真正有效的入口是uni.onError和uni.onUnhandledRejection,它们由uni-app框架在App端主动桥接了原生异常通道。
注意:这两个API必须在App.vue的onLaunch中注册,延迟注册(比如放到某个页面里)会漏掉冷启动阶段的异常。
uni.onError能捕获同步执行错误、throw语句、生命周期钩子内抛出的异常uni.onUnhandledRejection捕获未被catch的Promise拒绝(包括async/await中未try的reject)config.errorHandler(仅H5/小程序生效,App端无效)JS层异常只是冰山一角。App端真正致命的是原生崩溃(如iOS EXC_BAD_ACCESS、Android NullPointerException),这些完全绕过JS事件系统,uni.onError根本收不到。
解决方案是接入原生SDK:iOS用UMeng+ crash或Firebase Crashlytics,Android用bugly或firebase-crashlytics-ndk。uni-app本身不提供原生崩溃采集能力,必须通过uni-app插件市场引入已封装好的原生插件(如uni-crash-report),或自己写原生模块桥接。
manifest.json → App模块配置中勾选对应SDK,否则打包后无效果直接把err.message和err.stack发上去意义有限。真实线上问题往往依赖上下文:用户当前页面、vuex状态、网络类型、设备型号、uni-app版本、是否登录等。
推荐在上报前拼装一个最小但完整的上下文对象,例如:
{ "timestamp": Date.now(), "page": getCurrentPages()[0]?.$route?.path || "", "platform": uni.getSystemInfoSync().platform, "appVersion": uni.getSystemInfoSync().version, "uniVersion": uni.getSystemInfoSync().uniCompileVersion, "userInfo": uni.getStorageSync('userInfo') || null, "networkType": uni.getNetworkTypeSync?.() || "unknown", "error": { "message": err.message, "stack": err.stack, "type": "js_error" // 或 "promise_reject" }}
uni.onError回调里调用异步API(如uni.getStorage),可能触发竞态或失败;应提前缓存关键字段上报接口挂了、网络超时、JSON序列化失败……这些都可能触发新的错误,进而再次进入uni.onError,形成上报风暴。
if (uploading) return; uploading = true;,成功或超时后重置uni.request时设置timeout: 3000,并始终监听fail回调,失败时不重试console.error等副作用操作——它们在某些低端Android机上可能引发额外异常最麻烦的不是捕获不到错误,而是捕获到了却传不上去,或者传上去的日志缺关键字段。设备信息、页面路径、堆栈这三项,少一个就大概率要多花两小时翻日志找线索。