WKWebView高效传参指南:JS调用原生传对象 数组的解决方案
有没有遇到过这种情况?你在JS里辛辛苦苦组装了一个用户数据对象,想传给iOS原生代码处理,结果iOS那边死活收不到参数,或者收到一堆乱码。更气人的是,网上搜到的方法要么只教传字符串,要么代码写着写着就崩溃了——特别是新手如何快速涨粉这种热门话题下,居然还有人推荐用已经淘汰的UIWebView!今天咱们就来撕开这个技术黑洞,手把手教你怎么用WKWebView安全高效地传递对象和数组。
为什么要用WKWebView传参?
老有人问:“UIWebView用得好好的,为啥非要换WKWebView?”这么说吧,UIWebView就像个老式收音机,只能接收简单的信号,而WKWebView是智能音箱。举个例子:你用JS传个包含日期、地理位置的对象给UIWebView,大概率会丢失数据类型,但WKWebView能精准保留数据结构。更重要的是,??WKWebView的内存占用比UIWebView少60%??,这对手机应用来说就是生死线。
基础传参踩坑实录
刚开始学的时候,你是不是这样写的JS代码?
javascript复制// 错误示范! window.webkit.messageHandlers.myHandler.postMessage({name: "张三", age: 25});
然后在iOS端用message.body直接取字典?结果一运行就报类型错误。这是因为WKWebView的postMessage??不能直接传JS对象??,得先转成JSON字符串:
javascript复制// 正确姿势 const userInfo = JSON.stringify({name: "张三", age: 25}); window.webkit.messageHandlers.myHandler.postMessage(userInfo);
iOS端要这么接:
swift复制func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { if let jsonString = message.body as? String, let data = jsonString.data(using: .utf8), let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any] { print("收到用户信息:\(dict["name"] ?? "")") } }
数组传递的死亡陷阱
传单个对象还算简单,传数组才是真坑王。很多新手会犯这两个致命错误:
- 忘记给数组元素统一数据类型(比如混用字符串和数字)
- 直接传递多维数组不做特殊处理
来看个真实案例:JS要传一个商品规格数组
javascript复制// 错误写法导致iOS崩溃 const specs = [ {color: "红色", stock: 100}, {color: "蓝色", stock: 80} ]; window.webkit.messageHandlers.specHandler.postMessage(JSON.stringify(specs));
iOS端必须用NSArray接,而且每个元素要转成字典:
swift复制if let jsonString = message.body as? String, let data = jsonString.data(using: .utf8), let array = try? JSONSerialization.jsonObject(with: data) as? [[String: Any]] { for spec in array { print("颜色:\(spec["color"] ?? "") 库存:\(spec["stock"] ?? 0)") } }
特殊数据类型抢救方案
日期、二进制文件这些妖魔鬼怪怎么传?记住三大法则:
- ??日期统一转时间戳??(JS用Date.now(),iOS用Date(timeIntervalSince1970:))
- ??图片先转Base64??(iOS端用UIImage(data: Data)解码)
- ??循环引用对象要斩断??(用JSON.stringify的replacer参数过滤)
比如传用户头像+注册时间:
javascript复制// JS端处理 const userData = { avatar: canvas.toDataURL("image/png"), // Base64编码 registerTime: new Date().getTime() // 时间戳 }; window.webkit.messageHandlers.avatarHandler.postMessage(JSON.stringify(userData));
iOS端解码:
swift复制if let dict = parseJSON(message.body) { let avatarData = Data(base64Encoded: dict["avatar"]?.split(separator: ",").last ?? "") let registerDate = Date(timeIntervalSince1970: dict["registerTime"] as? TimeInterval ?? 0) }
灵魂拷问环节
??Q:为什么我按教程写了代码还是收不到参数???
A:检查三处死穴:
- WKWebViewConfiguration是否注册了消息处理器(addScriptMessageHandler)
- JS里的handlerName是否和iOS端注册的名字完全一致(区分大小写!)
- 网页是否完全加载完成再调postMessage(建议在window.onload里执行)
??Q:传参过程中最容易被忽略的安全问题是什么???
A:90%的开发者会忘记做这两件事:
- 在iOS端校验JSON格式(防止注入攻击)
- 在JS端过滤undefined值(会导致JSON.parse失败)
加固后的代码应该长这样:
javascript复制// JS安全写法 function safeStringify(obj) { return JSON.stringify(obj, (key, value) => { return value === undefined ? null : value; }); }
swift复制// iOS安全解析 func safeParse(_ jsonString: String) -> [String: Any]? { guard let data = jsonString.data(using: .utf8), let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any], dict.keys.contains("requiredKey") else { return nil } return dict }
小编观点
别再相信那些过时的UIWebView教程了,苹果早就在iOS 12把它判了死刑。WKWebView才是混合开发的未来,特别是处理复杂数据传参时,就像给你的App装上了高速公路ETC——又快又稳。新手记住这个口诀:??对象先转JSON,数组元素要统一,特殊类型转文本,安全校验不能弃??。按照这个思路走,保你三天内打通JS和原生的任督二脉!