1. 主页 > 好文章

WebView混合开发指南:JS高效调用iOS功能的3种方案

(拍桌子)哎我说兄弟们!你们有没有被这个场景搞崩溃过?辛辛苦苦写的H5页面在WebView里跑得欢实,突然产品经理拍着桌子喊:"这个分享按钮必须调微信!那个指纹验证得用原生的!"...(摊手)今天咱们就唠唠,怎么在WebView里让JS和iOS原生功能"对上暗号"!


场景一:电商活动页的分享功能

痛点现场还原

"双11大促页面做好了,用户点分享却跳不出微信!" 运营小妹急得直跺脚。H5的微信JS-SDK在App的WebView里根本认不出环境!

保命方案:URL Scheme快速通道

(抄起键盘)这时候就得用老办法——URL Scheme传暗号:

javascript复制
// JS端发送分享指令
window.location.href = 'appscheme://share?type=wechat&title=双11攻略';

iOS这边得在WebView里截胡:

swift复制
func webView(_ webView: WKWebView, 
            decidePolicyFor navigationAction: WKNavigationAction, 
            decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    // 识别自家Scheme
    if navigationAction.request.url?.scheme == "appscheme" {
        handleShareRequest(url: navigationAction.request.url!)
        decisionHandler(.cancel) // 拦截请求
        return
    }
    decisionHandler(.allow)
}

(扶眼镜)去年某电商App用这法子,分享转化率直接涨了23%!不过要注意两点坑:

  1. ??参数编码??:中文必须用encodeURIComponent处理
  2. ??频率限制??:1秒内别发超过5次请求,iOS会当你在DoS攻击!

场景二:金融类App的指纹验证

痛点现场还原

用户正在H5页面输银行卡号,突然要调原生的指纹验证。这时候要是让用户跳转原生页面再回来——(摇头)用户流失率能上30%!

硬核方案:JavaScriptCore实时通信

(撸袖子)这时候就得架设双向通信专线:

swift复制
// iOS端架桥
let context = webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as! JSContext
let handler = NativeHandler()
context.setObject(handler, forKeyedSubscript: "nativeBridge" as NSCopying)

// 定义指纹验证接口
@objc protocol NativeBridgeProtocol: JSExport {
    func startBiometricAuth(_ callback: JSValue)
}

class NativeHandler: NSObject, NativeBridgeProtocol {
    func startBiometricAuth(_ callback: JSValue!) {
        LocalAuth.authenticate { success in
            callback.call(withArguments: [success])
        }
    }
}

JS这边直接呼叫:

javascript复制
// 调用指纹验证
nativeBridge.startBiometricAuth((result) => {
    if(result) {
        console.log("指纹验证通过!");
    }
});

(敲黑板)某银行App用这套方案,用户认证流程时长从8秒降到3秒!但有三条保命建议:

  1. ??内存管理??:JSContext容易内存泄漏,记得用JSManagedValue
  2. ??线程安全??:回调必须切到主线程
  3. ??异常处理??:加try-catch防止JS报错崩APP

场景三:社交平台的实时消息推送

痛点现场还原

用户正在H5聊天室吹水,突然要实时显示消息已读状态。WebSocket虽然能推消息,但没法联动App的角标和通知中心!

高端方案:WKWebView MessageHandler

(神秘一笑)苹果官方认证的MessageHandler这时候该出场了:

swift复制
// iOS注册消息处理器
webView.configuration.userContentController.add(self, name: "nativeAPI")

// 处理消息
func userContentController(_ controller: WKUserContentController, 
                          didReceive message: WKScriptMessage) {
    switch message.name {
    case "nativeAPI":
        guard let dict = message.body as? [String: Any] else { return }
        if dict["action"] as? String == "updateBadge" {
            updateAppIconBadge(count: dict["count"] as? Int ?? 0)
        }
    }
}

JS发消息像发微信:

javascript复制
// 更新App角标
window.webkit.messageHandlers.nativeAPI.postMessage({
    action: "updateBadge",
    count: unreadCount
});

(比大拇指)某社交App用这方案,消息到达率提升40%!不过要当心三个雷:

  1. ??数据校验??:必须校验参数类型,防止被注入攻击
  2. ??性能监控??:消息量大的时候要加节流阀
  3. ??版本兼容??:iOS 8以下系统不支持

个人踩坑经验包

(掏心窝子)干了五年混合开发,说点教科书上不写的:

  1. ??别迷信跨平台框架??:去年用Cordova调相机功能,结果iOS14.3版本全军覆没,最后还是得写Native
  2. ??安全比性能重要??:曾经有个金融项目没做参数校验,被人用JS注入了SQL语句...
  3. ??监控必须到位??:建议在JS和Native两端都埋点,记录通信成功率和耗时
  4. ??备胎方案必备??:比如用Promise封装通信方法,超时自动转H5兜底方案

(拍肩膀)最后说句大实话:这三种方案没有绝对的好坏,就像吃火锅选蘸料——看场景!需要快速实现选URL Scheme,要双向通信用JavaScriptCore,追求稳定安全就上MessageHandler。搞明白了这个,你在混合开发这潭水里就算会游泳了!

本文由嘻道妙招独家原创,未经允许,严禁转载