1# 错误管理开发指导 2 3## 场景介绍 4 5当应用的代码存在规范问题或错误时,会在运行中产生异常和错误,如应用未捕获异常等。在错误产生后,应用会异常退出。错误日志通常会保存在用户本地存储设备中,不方便开发者定位问题。所以,应用开发者可以使用错误管理的接口,在应用退出前,及时将相关错误及日志上报到开发者的服务平台来定位问题。 6 7使用errormanager接口监听异常和错误后,应用不会退出,建议在回调函数执行完后,增加同步退出操作,如果只是为了获取错误日志,建议使用[hiappevent](hiappevent-watcher-crash-events-arkts.md)。 8 9## 接口说明 10 11应用错误管理接口由[errorManager](../reference/apis-ability-kit/js-apis-app-ability-errorManager.md)模块提供,开发者可以通过import引入,详见[开发示例](#开发示例)。 12 13**错误管理接口功能介绍:** 14 15| 接口名称 | 说明 | 16| ------------------------------------------------------------ | ---------------------------------------------------- | 17| on(type: "error", observer: ErrorObserver): number | 注册错误监听接口,当系统监测到应用异常时会回调该监听。该接口为同步接口,返回值为注册的监听对象对应的序号。 | 18| off(type: "error", observerId: number, callback: AsyncCallback\<void\>): void | 以callback的形式解除注册监听,传入的number为之前注册监听时返回的序号。 | 19| off(type: "error", observerId: number): Promise\<void\> | 以Promise的形式解除注册监听,传入的number为之前注册监听时返回的序号。 | 20| on(type: 'globalErrorOccurred', observer: GlobalObserver): void | 注册进程错误监听接口,当系统监测到应用异常时会回调该监听,该接口为同步接口,即一次注册,全局监听。(**推荐使用**) | 21| off(type: 'globalErrorOccurred', observer?: GlobalObserver): void | 以callback的形式解除注册监听。(**推荐使用**) | 22| on(type: 'globalUnhandledRejectionDetected', observer: GlobalObserver): void | 注册进程错误监听接口,当系统监测到应用promise异常时会回调该监听,该接口为同步接口,即一次注册,全局监听。(**推荐使用**) | 23| off(type: 'globalUnhandledRejectionDetected', observer?: GlobalObserver): void | 以callback的形式解除注册监听。(**推荐使用**) | 24| on(type: 'loopObserver', timeout: number, observer: LoopObserver): void<sup>12+</sup> | 注册主线程消息处理耗时监听器,当系统监测到应用主线程事件处理超时时会回调该监听。<br/>只能在主线程调用,多次注册后,后一次的注册会覆盖前一次的。 | 25| off(type: 'loopObserver', observer?: LoopObserver): void<sup>12+</sup> | 以LoopObserver的形式解除应用主线程消息处理耗时监听。 | 26| on(type: 'freeze', observer: FreezeObserver): void<sup>18+</sup> | 注册应用主线程freeze监听。只能在主线程调用,多次注册后,后一次的注册会覆盖前一次的。 | 27| off(type: 'freeze', observer?: FreezeObserver): void<sup>18+</sup> | 以FreezeObserver的形式解除应用主线程消息处理耗时监听。 | 28 29当采用callback作为异步回调时,可以在callback中进行下一步处理。当采用Promise对象返回时,可以在Promise对象中类似地处理接口返回值。具体结果码说明见[解除注册结果码](#解除注册结果码)。 30 31**错误监听(ErrorObserver)接口功能介绍:** 32 33| 接口名称 | 说明 | 34| ------------------------------ | ------------------------------------------------------------ | 35| onUnhandledException(errMsg: string): void | 系统回调接口,应用注册后,当应用产生未捕获的异常时的回调。 | 36| onException?(errObject: Error): void | 系统回调接口,应用注册后,当应用产生异常上报js层时的回调。 | 37 38**应用主线程监听(LoopObserver)接口功能介绍:** 39 40| 接口名称 | 说明 | 41| ------------------------------ | ------------------------------------------------------------ | 42| onLoopTimeOut?(timeout: number): void<sup>12+</sup> | 系统回调接口,应用注册后,当应用主线程处理事件超时的回调。 | 43 44### 解除注册结果码 45 46| 结果码 | 原因 | 47| ------ | --------------------------- | 48| 0 | 正常返回。 | 49| -1 | 传入的number不存在。 | 50| -2 | 参数错误。 | 51 52## 开发示例 53 54> **注意:** 55> 56> 建议在异常回调函数处理的最后,增加同步退出操作,否则可能出现多次异常回调的现象。 57 58### 单线程监听场景 59 60```ts 61import { AbilityConstant, errorManager, UIAbility, Want } from '@kit.AbilityKit'; 62import { window } from '@kit.ArkUI'; 63import process from '@ohos.process'; 64 65let registerId = -1; 66let callback: errorManager.ErrorObserver = { 67 onUnhandledException: (errMsg) => { 68 console.info(errMsg); 69 }, 70 onException: (errorObj) => { 71 console.info('onException, name: ', errorObj.name); 72 console.info('onException, message: ', errorObj.message); 73 if (typeof(errorObj.stack) === 'string') { 74 console.info('onException, stack: ', errorObj.stack); 75 } 76 //回调函数执行完,采用同步退出方式,避免多次触发异常 77 let pro = new process.ProcessManager(); 78 pro.exit(0); 79 } 80} 81 82let abilityWant: Want; 83 84export default class EntryAbility extends UIAbility { 85 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { 86 console.info("[Demo] EntryAbility onCreate"); 87 registerId = errorManager.on("error", callback); 88 abilityWant = want; 89 } 90 91 onDestroy() { 92 console.info("[Demo] EntryAbility onDestroy"); 93 errorManager.off("error", registerId, (result) => { 94 console.info("[Demo] result " + result.code + ";" + result.message); 95 }); 96 } 97 98 onWindowStageCreate(windowStage: window.WindowStage) { 99 // Main window is created, set main page for this ability 100 console.info("[Demo] EntryAbility onWindowStageCreate"); 101 102 windowStage.loadContent("pages/index", (err, data) => { 103 if (err.code) { 104 console.error('Failed to load the content. Cause:' + JSON.stringify(err)); 105 return; 106 } 107 console.info('Succeeded in loading the content. Data: ' + JSON.stringify(data)); 108 }); 109 } 110 111 onWindowStageDestroy() { 112 // Main window is destroyed, release UI related resources 113 console.info("[Demo] EntryAbility onWindowStageDestroy"); 114 } 115 116 onForeground() { 117 // Ability has brought to foreground 118 console.info("[Demo] EntryAbility onForeground"); 119 } 120 121 onBackground() { 122 // Ability has back to background 123 console.info("[Demo] EntryAbility onBackground"); 124 } 125}; 126``` 127 128### 进程监听异常场景 129 130```ts 131import { AbilityConstant, errorManager, UIAbility, Want } from '@kit.AbilityKit'; 132import { window } from '@kit.ArkUI'; 133import process from '@ohos.process'; 134 135function errorFunc(observer: errorManager.GlobalError) { 136 console.info("[Demo] result name :" + observer.name); 137 console.info("[Demo] result message :" + observer.message); 138 console.info("[Demo] result stack :" + observer.stack); 139 console.info("[Demo] result instanceName :" + observer.instanceName); 140 console.info("[Demo] result instaceType :" + observer.instanceType); 141 //回调函数执行完,采用同步退出方式,避免多次触发异常 142 let pro = new process.ProcessManager(); 143 pro.exit(0); 144} 145 146let abilityWant: Want; 147 148export default class EntryAbility extends UIAbility { 149 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { 150 console.info("[Demo] EntryAbility onCreate"); 151 errorManager.on("globalErrorOccurred", errorFunc); 152 abilityWant = want; 153 } 154 155 onDestroy() { 156 console.info("[Demo] EntryAbility onDestroy"); 157 errorManager.off("globalErrorOccurred", errorFunc); 158 } 159 160 onWindowStageCreate(windowStage: window.WindowStage) { 161 // Main window is created, set main page for this ability 162 console.info("[Demo] EntryAbility onWindowStageCreate"); 163 164 windowStage.loadContent("pages/index", (err, data) => { 165 if (err.code) { 166 console.error('Failed to load the content. Cause:' + JSON.stringify(err)); 167 return; 168 } 169 console.info('Succeeded in loading the content. Data: ' + JSON.stringify(data)); 170 }); 171 } 172 173 onWindowStageDestroy() { 174 // Main window is destroyed, release UI related resources 175 console.info("[Demo] EntryAbility onWindowStageDestroy"); 176 } 177 178 onForeground() { 179 // Ability has brought to foreground 180 console.info("[Demo] EntryAbility onForeground"); 181 } 182 183 onBackground() { 184 // Ability has back to background 185 console.info("[Demo] EntryAbility onBackground"); 186 } 187}; 188``` 189 190### 进程监听promise异常场景 191 192```ts 193import { AbilityConstant, errorManager, UIAbility, Want } from '@kit.AbilityKit'; 194import { window } from '@kit.ArkUI'; 195import process from '@ohos.process'; 196 197function promiseFunc(observer: errorManager.GlobalError) { 198 console.info("[Demo] result name :" + observer.name); 199 console.info("[Demo] result message :" + observer.message); 200 console.info("[Demo] result stack :" + observer.stack); 201 console.info("[Demo] result instanceName :" + observer.instanceName); 202 console.info("[Demo] result instaceType :" + observer.instanceType); 203 //回调函数执行完,采用同步退出方式,避免多次触发异常 204 let pro = new process.ProcessManager(); 205 pro.exit(0); 206} 207 208 209let abilityWant: Want; 210 211export default class EntryAbility extends UIAbility { 212 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { 213 console.info("[Demo] EntryAbility onCreate"); 214 errorManager.on("globalUnhandledRejectionDetected", promiseFunc); 215 abilityWant = want; 216 } 217 218 onDestroy() { 219 console.info("[Demo] EntryAbility onDestroy"); 220 errorManager.off("globalUnhandledRejectionDetected", promiseFunc); 221 } 222 223 onWindowStageCreate(windowStage: window.WindowStage) { 224 // Main window is created, set main page for this ability 225 console.info("[Demo] EntryAbility onWindowStageCreate"); 226 227 windowStage.loadContent("pages/index", (err, data) => { 228 if (err.code) { 229 console.error('Failed to load the content. Cause:' + JSON.stringify(err)); 230 return; 231 } 232 console.info('Succeeded in loading the content. Data: ' + JSON.stringify(data)); 233 }); 234 } 235 236 onWindowStageDestroy() { 237 // Main window is destroyed, release UI related resources 238 console.info("[Demo] EntryAbility onWindowStageDestroy"); 239 } 240 241 onForeground() { 242 // Ability has brought to foreground 243 console.info("[Demo] EntryAbility onForeground"); 244 } 245 246 onBackground() { 247 // Ability has back to background 248 console.info("[Demo] EntryAbility onBackground"); 249 } 250}; 251``` 252 253### 主线程监听freeze 254 255```ts 256import { AbilityConstant, errorManager, UIAbility, Want } from '@kit.AbilityKit'; 257import { window } from '@kit.ArkUI'; 258import process from '@ohos.process'; 259 260// Define freezeCallback 261function freezeCallback() { 262 console.info("freezecallback"); 263} 264 265 266let abilityWant: Want; 267 268export default class EntryAbility extends UIAbility { 269 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { 270 console.info("[Demo] EntryAbility onCreate"); 271 errorManager.on("freeze", freezeCallback); 272 abilityWant = want; 273 } 274 275 onDestroy() { 276 console.info("[Demo] EntryAbility onDestroy"); 277 errorManager.off("freeze", freezeCallback); 278 } 279 280 onWindowStageCreate(windowStage: window.WindowStage) { 281 // Main window is created, set main page for this ability 282 console.info("[Demo] EntryAbility onWindowStageCreate"); 283 284 windowStage.loadContent("pages/index", (err, data) => { 285 if (err.code) { 286 console.error('Failed to load the content. Cause:' + JSON.stringify(err)); 287 return; 288 } 289 console.info('Succeeded in loading the content. Data: ' + JSON.stringify(data)); 290 }); 291 } 292 293 onWindowStageDestroy() { 294 // Main window is destroyed, release UI related resources 295 console.info("[Demo] EntryAbility onWindowStageDestroy"); 296 } 297 298 onForeground() { 299 // Ability has brought to foreground 300 console.info("[Demo] EntryAbility onForeground"); 301 } 302 303 onBackground() { 304 // Ability has back to background 305 console.info("[Demo] EntryAbility onBackground"); 306 } 307}; 308```