前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS小技能:WKWebView与JS的交互

iOS小技能:WKWebView与JS的交互

作者头像
公众号iOS逆向
发布2022-12-19 17:29:24
5.7K0
发布2022-12-19 17:29:24
举报
文章被收录于专栏:iOS逆向与安全iOS逆向与安全

前言

由于目前UIWebView 已经被抛弃了,因此推荐使用WKWebView的WKScriptMessageHandler实现iOS与JS交互

WKWebView是Apple在iOS8推出的Webkit框架中的负责网页的渲染与展示的类,相比UIWebView速度更快,占用内存更少,支持更多的HTML特性

I JS调用iOS

使用例子:点击页面图片,调用iOS方法进行图片放大显示

1.1 JS代码:

代码语言:javascript
复制
window.webkit.messageHandlers.openImage.postMessage($(this).attr("src"));

1.2 iOS侧代码

  • 遵守WKScriptMessageHandler协议
代码语言:javascript
复制
@interface QCTWebViewController ()<WKScriptMessageHandler>

  • 实现WKWebView收到ScriptMessage时的回调协议
代码语言:javascript
复制
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
    
    if ([message.name caseInsensitiveCompare:k_openImage4js] == NSOrderedSame) {
        
        NSLog(@"message.name:%@,message.body:%@",message.name,message.body);
        
        
//        [WKWebViewWKScriptMessageHandlerController showAlertWithTitle:message.name message:message.body cancelHandler:nil];
        
        
    }

    
    
}

1.2.1 使用configuration对象初始化webView

代码语言:javascript
复制
//! 为userContentController添加ScriptMessageHandler,并指明name
//WKUserContentController *userContentController = [[WKUserContentController alloc] init];
//[userContentController addScriptMessageHandler:self name:@"openImage"];

//! 使用添加了ScriptMessageHandler的userContentController配置configuration
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
//configuration.userContentController = userContentController;

//! 使用configuration对象初始化webView
_webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration];

1.2.1 监听消息

避免引起循环引用问题。:在-viewWillAppear:方法中执行add 监听,在-viewWillDisappear:方法中执行remove 监听。

代码语言:javascript
复制

NSString * const k_openImage4js = @"openImage";
extern NSString * _Nonnull const k_openImage4js;

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    
    
    [_webView.configuration.userContentController removeScriptMessageHandlerForName:k_openImage4js];
    
    
    
}

- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    
    //WKUserContentController *userContentController = [[WKUserContentController alloc] init];
    
    

    [_webView.configuration.userContentController addScriptMessageHandler:self name:k_openImage4js];
    
    
}
  • 放大图片
代码语言:javascript
复制
- (void)ImageZoomScaleWithUrl:(NSString*)url{
    
    
    
    CRMImageZoomScaleViewController *detail = [[CRMImageZoomScaleViewController alloc]init];
    
//        detail.maximumZoomScale = 4.8f;
    
    detail.imagePath = url;
    
    detail.type = @"yes";

    
    
    
    
    __weak __typeof__(self) weakSelf = self;

    [UIView transitionWithView:self.navigationController.view duration:0.25 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
        [weakSelf.navigationController pushViewController:detail animated:NO];
        
        
    } completion:nil];



}

II iOS执行JS

通过WKWebView的-evaluateJavaScript:completionHandler:方法来实现

WKWebView的-evaluateJavaScript:completionHandler:方法可以执行JS代码。但只有在整个webView加载完成之后调用此方法才会有响应

2.1 执行JS

  • iOS使用WKWebView的-evaluateJavaScript:completionHandler:方法执行拼接好的JS代码;
代码语言:javascript
复制
        [self.webView evaluateJavaScript:@"ocToJs('loginSucceed', 'tokenString')" completionHandler:^(id response, NSError *error) {}];

  • js
代码语言:javascript
复制
//! iOS调用JS数据显示框
<div id = "returnValue" style = "font-size: 18px; border: 1px dotted; height: 50px;"> </div>

//! iOS调用JS入口
function ocToJs(action, params) {
  document.getElementById("returnValue").innerHTML = action + '?' + params;
}

2.2 获取网页title

  • 获取网页title: 在加载请求完成才执行

//! WKWebView在每次加载请求完成后会调用此方法

  • (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
代码语言:javascript
复制


#if AX_WEB_VIEW_CONTROLLER_USING_WEBKIT
    title = title.length>0 ? title: [_webView title];
#else
    title = title.length>0 ? title: [_webView stringByEvaluatingJavaScriptFromString:@"document.title"];
#endif

III 加载本地HTML文件

  • loadHTMLString4WkWebView源码
代码语言:javascript
复制
#pragma mark - ******** 加载本地HTML
//NSString * const k_localHtml4csdn = @"csdn21.html";

- (void)localHtmlClicked{
    NSString *path = [[NSBundle mainBundle] pathForResource:k_localHtml4csdn ofType:nil];
    NSString *htmlString = [[NSString alloc]initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
    [_webView loadHTMLString:htmlString baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]];
}

IV 防抓包

防抓包

使Thor,Charles,Burp等代理抓包方式全部失效

代码语言:javascript
复制
        configuration.connectionProxyDictionary = @{};


但是无法避免如Wireshark这类直接通过网卡抓包的工具 若您的请求协议很重要,请务必对请求进行验签或加密,并尽量避免明文声明AES加密key,详情可参照iOS安全规范指南之参数签名:参数按照ASCII码从小到大排序、拼接、加密(采用递归的方式进行实现)【案例:条码支付综合前置平台申请退款】 丨蓄力计划从CSDN下载demo地址:https://download.csdn.net/download/u011018979/15483107规则:1、demo 数组用[]表示,对象(字典)用{} 表示进行排序拼接。2、数组排序可选,数组内部,只对字符串元素进行排序,并不与字典key参与排序。字典和数组独立排序 原文:https://blog.csdn.net/z929118967/article/details/115669856应用场景:防止请求参数被恶意修改;比如在对接第三方支付的时候,第三方会要求参数按照ASCII码从小到大排序。

see also

iOS利用JSExport协议实现与JS的交互 & android 和js的交互

https://blog.csdn.net/z929118967/article/details/77963082

大图浏览器

  • ImageZoomScale:iOS 利用UIScrollView实现 图片放大预览,并支持缩小
  • iOS查看大图浏览器(应用场景:查看风险商户证明材料时图片支持滑动切换)

[video(video-farK5uUD-1616404131406)(type-csdn)(url-https://live.csdn.net/v/embed/157526)(image-https://vedu.csdnimg.cn/0beb4886dda54d37a9d7a80878e4e62e/snapshots/c62b152a163e44f8bfd8f1cf616bed51-00001.jpg)(title-iOS查看大图浏览器)]

从CSDN下载Demo源码:https://download.csdn.net/download/u011018979/16039540

  • 应用场景:查看多张大图,比如查看风险商户的证明材料,图片支持滑动切换
  • 文章:https://blog.csdn.net/z929118967/article/details/115077471
  • 主要功能:进入查看器之后,可左右滑动查看上/下张,并支持下滑视图退出查看器

「同层渲染」原理

微信小程序在 iOS 端使用 WKWebView 进行渲染的,WKWebView 在内部采用的是分层的方式进行渲染,它会将 WebKit 内核生成的 Compositing Layer(合成层)渲染成 iOS 上的一个 WKCompositingView,这是一个客户端原生的 View,不过可惜的是,内核一般会将多个 DOM 节点渲染到一个 Compositing Layer 上,因此合成层与 DOM 节点之间不存在一对一的映射关系。不过发现,当把一个 DOM 节点的 CSS 属性设置为 overflow: scroll (低版本需同时设置 -webkit-overflow-scrolling: touch)之后,WKWebView 会为其生成一个 WKChildScrollView,与 DOM 节点存在映射关系,这是一个原生的 UIScrollView 的子类,也就是说 WebView 里的滚动实际上是由真正的原生滚动组件来承载的。WKWebView 这么做是为了可以让 iOS 上的 WebView 滚动有更流畅的体验。虽说 WKChildScrollView 也是原生组件,但 WebKit 内核已经处理了它与其他 DOM 节点之间的层级关系,因此你可以直接使用 WXSS 控制层级而不必担心遮挡的问题。

小程序 iOS 端的「同层渲染」也正是基于 WKChildScrollView 实现的,原生组件在 attached 之后会直接挂载到预先创建好的 WKChildScrollView 容器下,大致的流程如下:

  1. 创建一个 DOM 节点并设置其 CSS 属性为 overflow: scroll 且 -webkit-overflow-scrolling: touch;
  2. 通知客户端查找到该 DOM 节点对应的原生 WKChildScrollView 组件;
  3. 将原生组件挂载到该 WKChildScrollView 节点上作为其子 View。

通过上述流程,小程序的原生组件就被插入到 WKChildScrollView 了,也即是在 步骤1 创建的那个 DOM 节点对应的原生 ScrollView 的子节点。此时,修改这个 DOM 节点的样式属性同样也会应用到原生组件上。因此,「同层渲染」的原生组件与普通的内置组件表现并无二致。

同层渲染不仅解决了原生组件的层级问题,同时也让原生组件有了更丰富的展示和交互的能力。

下表列出的原生组件都已经支持了「同层渲染」,其他组件( textarea、camera、webgl 及 input)也会在近期逐步上线。现在你就可以试试用「同层渲染」来优化你的小程序了。

支持同层渲染的原生组件

最低版本

video

v2.4.0

map

v2.7.0

canvas 2d(新接口)

v2.9.0

live-player

v2.9.1

live-pusher

v2.9.1

WKNavigationDelegate 代理方法的调用流程

UIProcess、WebContent、NetworkProcess 三大进程间的通信关系

NetworkProcess进程:

主要负责网络请求加载,所有的网页共享这一进程。与原生网络请求开发一致,NetworkProcess 也是通过封装的 NSURLSession 发起并管理网络请求的。但不同的是,这一过程中有较多的网络进度的回调工作以及各类网络协议管理,比如资源缓存协议、HSTS 协议、cookie 管理协议等。

WebContent进程:主要负责页面资源的管理,包含前进后退历史,pageCache,页面资源的解析、渲染。并把该进程中的各类事件通过代理方式通知给 UIProcess。

UIProcess进程:主要负责与 WebContent 进行交互,与 APP 在同一进程中,可以进行 WebView 的功能配置,并接收来自 WebContent 进程的各类消息,配合业务代码执行任务的决策,例如是否发起请求,是否接受响应等。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-12-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 iOS逆向 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • I JS调用iOS
    • 1.1 JS代码:
      • 1.2 iOS侧代码
        • 1.2.1 使用configuration对象初始化webView
        • 1.2.1 监听消息
    • II iOS执行JS
      • 2.1 执行JS
        • 2.2 获取网页title
        • III 加载本地HTML文件
        • IV 防抓包
        • see also
          • 大图浏览器
            • 「同层渲染」原理
              • WKNavigationDelegate 代理方法的调用流程
                • UIProcess、WebContent、NetworkProcess 三大进程间的通信关系
                相关产品与服务
                云开发 CloudBase
                云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档