解决WKWebView中的TypeError: undefined is not an object

13 次阅读

WKWebView是iOS应用中常用的网页加载组件,广泛应用于混合开发、H5页面嵌入以及App内Web功能实现。在实际开发过程中,开发者经常会遇到JavaScript运行异常,其中比较典型的问题就是:

TypeError: undefined is not an object

该错误表示JavaScript尝试访问一个未定义对象的属性或方法。例如:

JavaScript
user.name

如果user不存在,就会抛出:

TypeError: undefined is not an object (evaluating 'user.name')

在WKWebView环境中,这类问题不仅可能来自前端代码本身,还可能与iOS原生交互、加载时机、JS注入、缓存以及版本兼容性有关。下面详细分析常见原因和解决方案。

一、理解TypeError: undefined is not an object错误

JavaScript属于弱类型语言,在运行过程中不会提前检查对象是否存在。当代码访问不存在的变量或属性时,就可能出现类似错误:

JavaScript
var data;

console.log(data.title);

执行后会出现:

TypeError: undefined is not an object

常见触发场景包括:

  • 对象未初始化;

  • 异步数据还没有返回;

  • DOM元素尚未加载;

  • iOS与JavaScript通信对象不存在;

  • JS文件加载顺序错误;

  • WKWebView环境与浏览器环境存在差异。

在普通浏览器中运行正常,但放入WKWebView后出现异常,通常说明运行环境发生了变化。

二、检查JavaScript对象是否存在

最常见的解决方式是增加对象存在性判断。

错误写法:

JavaScript
var result = response.data.name;

如果response或者data不存在,就会导致异常。

推荐修改为:

JavaScript
if (response && response.data) {
    var result = response.data.name;
}

或者使用ES6可选链:

JavaScript
var result = response?.data?.name;

可选链能够避免因为空对象导致程序直接崩溃。

不过需要注意,部分旧版本iOS中的JavaScriptCore环境可能不支持最新语法,需要根据最低支持版本决定是否使用。

三、WKWebView中JS调用原生方法失败

WKWebView最容易出现该错误的地方,就是JavaScript调用iOS原生注入对象。

例如:

JavaScript
window.webkit.messageHandlers.nativeBridge.postMessage({
    action:"login"
});

如果没有正确注册nativeBridge,会出现:

TypeError: undefined is not an object

原因是:

JavaScript
window.webkit.messageHandlers.nativeBridge

实际不存在。

iOS端正确注册方式

Swift示例:

Swift
let configuration = WKWebViewConfiguration()

let controller = WKUserContentController()

controller.add(self, name: "nativeBridge")

configuration.userContentController = controller

let webView = WKWebView(
    frame: .zero,
    configuration: configuration
)

同时需要实现:

Swift
extension ViewController: WKScriptMessageHandler {

    func userContentController(
        _ userContentController: WKUserContentController,
        didReceive message: WKScriptMessage
    ) {

        if message.name == "nativeBridge" {
            print(message.body)
        }
    }
}

JavaScript调用前可以增加判断:

JavaScript
if (
    window.webkit &&
    window.webkit.messageHandlers &&
    window.webkit.messageHandlers.nativeBridge
) {

    window.webkit.messageHandlers.nativeBridge.postMessage({
        action:"login"
    });

}

这样即使原生没有注入对象,也不会导致页面报错。

四、检查WKWebView加载时机

很多问题来自页面加载顺序。

例如:

HTML:

HTML

initApp();


 src="app.js">

如果initApp()依赖app.js中的对象,就会出现:

undefined is not an object

推荐调整为:

HTML
 src="app.js">


document.addEventListener(
    "DOMContentLoaded",
    function(){
        initApp();
    }
);

或者:

JavaScript
window.onload = function(){

    initApp();

};

确保依赖资源加载完成后再执行代码。

五、处理异步接口返回为空的问题

移动端Web页面大量依赖接口请求,如果接口返回异常,也容易产生该错误。

例如:

JavaScript
fetch("/api/user")
.then(res => res.json())
.then(data => {

    document.title = data.user.name;

});

如果接口返回:

JSON
{
}

则:

JavaScript
data.user.name

会报错。

优化:

JavaScript
fetch("/api/user")
.then(res => res.json())
.then(data => {

    if(data.user){

        document.title = data.user.name;

    }

});

同时建议对接口返回结构进行统一校验:

JavaScript
function checkResponse(data){

    return data &&
           data.code === 200 &&
           data.result;

}

避免业务代码中大量出现空判断。

六、检查WKWebView与Safari行为差异

很多开发者发现:

“网页在Safari中正常,在WKWebView中报错。”

这是因为WKWebView和Safari虽然使用相同WebKit内核,但运行环境并不完全一致。

常见差异包括:

1. User-Agent不同

部分页面会根据User-Agent加载不同代码。

可以查看:

Swift
webView.evaluateJavaScript(
    "navigator.userAgent"
)

确认当前环境。

2. Cookie不同步

如果依赖登录状态:

JavaScript
userInfo.name

可能因为Cookie没有同步导致数据为空。

3. LocalStorage隔离

Safari中的:

JavaScript
localStorage.user

并不一定存在于WKWebView。

需要重新初始化数据。

七、调试WKWebView中的JavaScript错误

解决这类问题,调试信息非常重要。

开启Safari远程调试

iPhone:

设置
→ Safari
→ 高级
→ Web检查器

Mac:

Safari
→ 开发
→ iPhone设备
→ WKWebView页面

可以直接查看:

  • Console错误;

  • 网络请求;

  • JavaScript变量;

  • DOM结构。

iOS打印JavaScript异常

Swift中:

Swift
webView.evaluateJavaScript(
    "yourFunction()"
) { result, error in

    if let error = error {

        print(error.localizedDescription)

    }

}

可以捕获JS执行失败原因。

八、避免第三方JS库兼容问题

一些H5页面依赖第三方库,例如:

  • jQuery;

  • Vue;

  • React;

  • Axios;

  • SDK脚本。

如果加载失败:

JavaScript
axios.get()

可能变成:

undefined is not an object

建议检查:

网络资源是否加载成功

例如:

HTML
 src="https://xxx.com/sdk.js">

如果WKWebView网络限制导致加载失败,需要处理。

检查加载顺序

错误:

JavaScript
new Vue()

但是Vue还没有加载。

正确:

HTML
 src="vue.js">
 src="app.js">

九、增加全局异常捕获

为了快速定位线上问题,可以增加JavaScript异常监听:

JavaScript
window.onerror = function(
    message,
    source,
    line,
    column,
    error
){

    console.log({
        message,
        source,
        line,
        column
    });

};

对于移动端应用,还可以将错误信息发送给服务器:

JavaScript
window.onerror = function(message){

    fetch("/log",{
        method:"POST",
        body:JSON.stringify({
            error:message
        })
    });

};

方便分析真实用户环境中的问题。

十、推荐排查流程

遇到WKWebView中的:

TypeError: undefined is not an object

可以按照以下顺序排查:

第一步:定位具体对象

查看错误:

undefined is not an object (evaluating 'xxx.xxx')

确认哪个对象为空。

第二步:增加安全判断

例如:

JavaScript
if(obj){
    obj.method();
}

第三步:检查iOS注入对象

确认:

JavaScript
window.webkit.messageHandlers

是否存在。

第四步:检查加载顺序

确认:

  • JS文件是否加载完成;

  • DOM是否初始化;

  • 异步请求是否返回。

第五步:使用Safari调试工具

查看真实运行环境。

总结

WKWebView中的TypeError: undefined is not an object问题,本质上是JavaScript访问了不存在的数据或对象。造成该问题的原因不仅包括普通前端代码错误,还涉及iOS与H5交互、资源加载顺序、异步请求、缓存隔离以及WebKit兼容性等多个方面。

解决这类问题时,应避免简单地添加空判断,而应该从对象来源、生命周期、通信机制和运行环境几个方向进行分析。通过完善JavaScript防御式编程、规范WKWebView桥接方式,并结合Safari远程调试工具,可以快速定位并解决此类异常,提高混合应用的稳定性。