Native 错误处理

游戏程序运行中会出现多种多样的问题,比如网络异常,JavaScript代码错误。

Egret Native 为了开发者方便提供了多种异常处理的接口和方式,本文就讲诉一下。

Egret Native 可以在 原生端javascript端 处理异常

  • 原生端是指 iOS(Objective-C)/Android(Java) 端。
  • javascript端 是指游戏的javascript执行环境内部。

启动异常

在 index.html 加载时,或者解析 index.html 中的 <script> 标签时,可能会出现文件无法加载的情况。

这一般都会是在 javascript 执行之前,这部分的错误只能由 原生端 处理

原生端 监听 @onError 事件来处理启动异常

  • 注册对error事件的监听,请在 native 初始化调用之前注册事件回调

message 为 json 串,属性如下

属性类型说明
errorstring错误类型 目前 只有 "load"
urlstring发生错误的地址
codestring发生的错误码
nativeAndroid.setExternalInterface("@onError", new INativePlayer.INativeInterface() {
@Override
public void callback(String message) {
Log.e(TAG, "Native get onError message: " + message);
}
});
[native setExternalInterface:@"@onError" Callback:^(NSString *message) {
NSLog(@"Get @onError: %@", message);
}];

处理 javascript 运行异常

在 javascript 执行时,可能会由于代码的语法问题、数据的错误、状态的不同步等导致代码执行出错

这样的错误会有如下特点:

  • 是 javascript 执行异常:包括语法错误,数组访问越界,null 对象访问等,网络错误不算
  • 全局未捕获异常:既没有通过 try catch 捕获。注:异步回调的异常需要单独捕获否则就会产生全局未捕获异常

通过 javascript端 window.onerror 处理

window.onerror = function(message, source, lineno, colno, error) {
console.error("Uncaught", message);
}

原生端 监听 @onJSError 事件来处理启动异常

所有需要 window.onerror 处理的错误,有可能就执行错乱了,所以 汇报到原生端处理,用户无论是否注册了 window.onerror 都会发起

nativeAndroid.setExternalInterface("@onJSError", new INativePlayer.INativeInterface() {
@Override
public void callback(String message) {
Log.e(TAG, "Get @onJSError: " + message);
}
});
[native setExternalInterface:@"@onJSError" Callback:^(NSString *message) {
NSLog(@"Get @onJSError: %@", message);
}];

处理 javascript Promise 异步异常

在使用 Promise 进行异步处理时,可能由于多种情况导致 Promisereject,在 Promisereject 时 如果不及时进行捕获,则会产生未处理的 reject

即使是 Promise 执行中抛出的 javascript 执行异常,如语法错误,数组访问越界,null 对象访问、也会被作为 reject 而不会触发 window.onerror

这部分异常只能通过 javascript 处理

通过 promise.then 第二个参数处理

promise.then(null, e => {
console.error("Then error (in promise)", e);
});

通过 promise.catch 处理

promise.catch(e => {
console.error("Catch (in promise)", e);
});

通过 window.onunhandledrejection 处理

注意:即使触发了 window.onunhandledrejection 也不是说明 这个 Promisereject 没人处理,可能在之后又有人通过上面的 promise.then 或 promise.catch 处理了这个 Promisereject

window.onunhandledrejection(e => {
console.error("Uncaught (in promise)", e);
});

HTML节点错误

HTMLImageElement, HTMLScriptElement 等HTML节点的加载是通过这些节点的 onerror 处理函数处理

// image 类型
var img = new Image();
img.src = "nothisfile.jpg";
img.onerror = function(e) {
console.error("image load error", e);
}
// script 类型
var script = document.createElement('script');
script.src = "nothisfile.js";
script.onerror = function(e) {
console.error("script load error", e);
}
document.body.appendChild(script);

XMLHttpRequest 请求的错误

如果是网络错误、解析域名、url格式问题等错误,使用 xhr.onerror 处理错误

如果是服务器返回 404 等状态码,不会触发 onerror 事件,需要在代码中通过 xhr.status 判定

var xhr = new XMLHttpRequest();
xhr.open('GET', 'nothisfile.txt', true);
xhr.onerror = function () {
console.error("xhr load error", e);
}
xhr.onload = function () {
console.log("load", xhr.status);
};

例:

白鹭引擎中 manifest.json 的下载是由xhr发起的 用此方案处理