【iOS安全】JS 调用Objective-C中WKWebview Handler的三种方式

有三种实现途径

1. WKScriptMessageHandler

OC部分:注册并实现Handler

将OC中的方法"nativeMethod"注册为JavaScript Message Handler,从而WebView中的JavaScript代码可以调用该方法

c 复制代码
// Register in Objective-C code
- (void)setupWKWebView
{
    // [WKWebViewConfiguration alloc]返回一个被分配和初始化的WKWebViewConfiguration对象的指针
    // init方法是WKWebViewConfiguration类的实例方法
    WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
    
    configuration.userContentController = [[WKUserContentController alloc] init];
    
    // 将OC中的方法"nativeMethod"注册为JavaScript Message Handler,从而可以在WebView中执行JavaScript代码时调用该方法
    [configuration.userContentController 
        addScriptMessageHandler:self // addScriptMessageHandler是方法名,self是参数1
        name:@"nativeMethod"]; // name是参数2
    
    // 初始化WKWebView
    WKWebView *webView = 
        [[WKWebView alloc]
            initWithFrame:self.view.frame
            configuration:configuration];
}

// Handler method defined in WKScriptMessageHandler
- (void)userContentController:
    (WKUserContentController *)userContentController //userContentController是参数1
    didReceiveScriptMessage:(WKScriptMessage *)message //message是参数2
{
    if ([message.name isEqualToString:@"nativeMethod"]) // 当JS端调用的是nativeMethod时
    {
        ... //OC端的handler逻辑实现
    }
}

JS部分:调用Handler

调用"nativeMethod"

javascript 复制代码
// Invoke in JavaScript code
window.webkit.messageHandlers.nativeMethod.postMessage();

2. WebViewJavascriptBridge

OC部分:注册并实现Handler

注册名为"nativeMethod"的Handler

c 复制代码
// OC中 调用bridgeForWebView:方法,来初始化WebViewJavascriptBridge
// self.bridge将被设置为WKWebView的navigationDelegate属性
self.bridge = [WebViewJavascriptBridge bridgeForWebView:webView];

[self.bridge registerHandler:@"nativeMethod" //参数1,JS端以这个函数名调用该注册的native方法
    handler: //参数2的参数名,冒号后面跟着参数2的参数值,是一个block;当JS端调用nativeMethod方法时,OC端执行该block
    ^(id data, WVJBResponseCallback responseCallback) 
    // ^代表后面是一个block 
    // data是JS端传递过来的数据
    // responseCallback是 OC端的 block 执行完毕之后,往 JS 端传递的数据
    {
        ... // block中的代码,这些代码在JS端调用nativeMethod时被执行
    }
];

JS部分:调用Handler

js 复制代码
WebViewJavascriptBridge.callHandler('nativeMethod', data, function(responseData) {
    // 处理来自Objective-C的响应数据
    console.log(response); 
});

例如我们使用Frida分析出来,某app的wkwebview中有如下handler:

c 复制代码
{
    callNavigationSelectView = "<__NSMallocBlock__: 0x281d4a440>";
    checkNotificationPermission = "<__NSMallocBlock__: 0x281d4b240>";
    clickControlToShare = "<__NSMallocBlock__: 0x281d4bf00>";
    couponPaySuccess = "<__NSMallocBlock__: 0x281d4a780>";
    doQRScan = "<__NSMallocBlock__: 0x281d4bf80>";
    faceDetect = "<__NSMallocBlock__: 0x281d4bcc0>";
    getDeviceAlipay = "<__NSMallocBlock__: 0x281d4a4c0>";
    getDeviceId = "<__NSMallocBlock__: 0x281d4a800>";
    getDeviceInfo = "<__NSMallocBlock__: 0x281d4a680>";
    getLocation = "<__NSMallocBlock__: 0x281d4a600>";
    getNetworkStatus = "<__NSMallocBlock__: 0x281d4b0c0>";
    getOtherDeviceInfo = "<__NSMallocBlock__: 0x281d4b540>";
    getSMDeviceId = "<__NSMallocBlock__: 0x281d4a2c0>";
    getTripEmail = "<__NSMallocBlock__: 0x281db04c0>";
    getUserInfo = "<__NSMallocBlock__: 0x281d4a540>";
    goToKF = "<__NSMallocBlock__: 0x281d4a340>";
    goToVideoPlayer = "<__NSMallocBlock__: 0x281d4a700>";
    hideLoadingDialog = "<__NSMallocBlock__: 0x281d4b3c0>";
    jdPayHandle = "<__NSMallocBlock__: 0x281d4b900>";
    jumpToMiniPro = "<__NSMallocBlock__: 0x281d4a380>";
    requestNotificationPermission = "<__NSMallocBlock__: 0x281d4af00>";
    saveImage = "<__NSMallocBlock__: 0x281d4a500>";
    sendMsg = "<__NSMallocBlock__: 0x281d4a5c0>";
    shareOnTheWebviewPage = "<__NSMallocBlock__: 0x281d4a640>";
    shareWxImages = "<__NSMallocBlock__: 0x281d4b4c0>";
    shareWxMinipg = "<__NSMallocBlock__: 0x281d4a580>";
    startAuthoritySetting = "<__NSMallocBlock__: 0x281d4a300>";
    startNetworkSetting = "<__NSMallocBlock__: 0x281d4a7c0>";
    statusBarShare = "<__NSMallocBlock__: 0x281d4ad40>";
    uploadTripEmail = "<__NSMallocBlock__: 0x281d49b40>";
    webviewClose = "<__NSMallocBlock__: 0x281d4a740>";
    webviewGoBack = "<__NSMallocBlock__: 0x281d4a480>";
}

这时候在JS端就可以这么调用:

c 复制代码
WebViewJavascriptBridge.callHandler('getLocation', function(response) {
  console.log(response); 
});

确实能调用起来

3. DSBridge

这个不是很常见

OC部分:

c 复制代码
@implementation JsObject
- (NSString *) nativeMethod:(NSString *) msg
{
    ...
}
@end

DWKWebView* dwebview = [[DWKWebView alloc] initWithFrame:bounds];
[dwebview addJavascriptObject:[[JsObject alloc] init] namespace:nil];

JS部分:

js 复制代码
var dsBridge=require("dsbridge");
var str=dsBridge.call("nativeMethod","arg");

参考:

Medusa Attack: Exploring Security Hazards of {In-App}{QR} Code ScanningC//32nd USENIX Security Symposium (USENIX Security 23). 2023: 4607-4624.

相关推荐
daols883 小时前
vxe-table 渲染器教程一:实现金额输入控件
javascript·vue.js·vxe-table
触底反弹3 小时前
🔥 React 零基础入门(中):500 行屎山代码到组件化的蜕变
前端·javascript·react.js
张元清7 小时前
React useResizeObserver Hook:追踪元素尺寸变化(2026)
javascript·react.js
瑞瑞小同学10 小时前
处理echarts x轴内容过多,重叠问题
前端·javascript·echarts
像我这样帅的人丶你还11 小时前
MCP + npm:给五年前的老系统接上AI
前端·javascript·agent
一个写前端的12 小时前
基于 Vue 3 的大文件分片上传组件,支持断点续传、并发上传、失败重试等功能
前端·javascript·vue.js
猫头_12 小时前
AI 流式传输工程指南:有了 EventSource 为何还要 Fetch?
javascript·http·llm
良木林13 小时前
滑动窗口 - LeetCode hot 100
javascript·算法·leetcode·双指针·滑动窗口
末代iOS程序员华仔14 小时前
Cursor + GitOps:自动化运维新姿势
flutter·ios·swift
不简说15 小时前
# JS 代码技巧 vol.7 — 20 个浏览器 API 实战,自带 API 能干的事别自己封装
前端·javascript·面试