OC · 记——浅谈JS与OC的交互

我们在开发中,经常会用webView来加载网页,有时候,H5那边给到iOS的网页,加载出来后发现,网页原生的导航栏、悬浮的按钮、底部“电脑版”这类文字没有去掉,让iOS自己来简单处理,那应该怎么办呢?这时候就需要通过JS注入到OC中来实现想要的效果。有三种方式:UIWebView、WKWebView、JavaScriptCore,下面一一介绍。

需要iOS来删除掉的地方
UIWebView

在注入JS之间,我们需要一个桥梁:webView的代理方法。
遵守<UIWebViewDelegate>,然后获取删除3个部分的JS代码,如下所示:

 //一.移除顶部导航栏
 //1.获取你要删除的标签,找到你要删除的标签的父标签/父节点,移除
 var headerTag = document.getElementsByTagName('header')[0];
 
 headerTag.parentNode.removeChild(headerTag);
 
 //二.移除底部悬浮按钮
 var footBtnTag = document.getElementByClassName('footer-btn-fix')[0];
 footerBtnTag.parentNode.removeChild(footerBtnTag);
 
 //三.移除网页 底部布局
 var footerTag = document.getElementByClassName('footer')[0];
 footerTag.parentNode.removeChile(footerTag);

创建webView,加载网页。

- (void)viewDidLoad {
    [super viewDidLoad];
    /*
     创建展示网页的控件
     */
    UIWebView * webV = [[UIWebView alloc] initWithFrame:[UIScreen mainScreen].bounds];
    webV.delegate = self;
    /*
     把展示网页的控件添加到根视图上面
     */
    [self.view addSubview:webV];
    /*
     使用webview加载网页,http和https的兼容问题,百度一下,添加两个key就可以了
     */
    NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL 
    URLWithString:@"http://m.dianping.com/tuan/deal/5501525"]];
    [webV loadRequest:request];
}

调用webView的代理方法,注入JS,实现想要的效果。

#pragma mark -- 网页加载完成之后会调用的代理方法
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    /*
     由于总共有三处修改,所以要拼接JS代码。
     webView直接提供了JS注入的方法
     */
    NSMutableString * StrM = [NSMutableString string];
    [StrM appendString:@"var headerTag = document.getElementsByTagName('header')[0];headerTag.parentNode.removeChild(headerTag);"];
    [StrM appendString:@"var footerBtnTag = document.getElementsByClassName('footer-btn-fix')[0];footerBtnTag.parentNode.removeChild(footerBtnTag);"];
    [StrM appendString:@"var footTag = document.getElementsByClassName('footer')[0];footTag.parentNode.removeChild(footTag);"];
    [webView stringByEvaluatingJavaScriptFromString:StrM];
}

效果如下,成功清理干净。

1.gif
WKWebView

iOS8以后,苹果推出了新框架Wekkit,提供了替换UIWebView的组件WKWebView。各种UIWebView的问题没有了,速度更快了,占用内存少了,一句话,WKWebView是App内部加载网页的最佳选择!
先看下WKWebView的特性:
1.在性能、稳定性、功能方面有很大提升(最直观的体现就是加载网页是占用的内存,模拟器加载百度与开源中国网站时,WKWebView占用23M,而UIWebView占用85M);
2.允许JavaScript的Nitro库加载并使用(UIWebView中限制);
支持了更多的HTML5特性;
3.高达60fps的滚动刷新率以及内置手势;
4.将UIWebViewDelegate与UIWebView重构成了14类与3个协议(查看苹果官方文档);
接下来,我要使用WKWebView来实现上面的效果。直接上代码:

#import "ViewController.h"
#import <WebKit/WebKit.h>
@interface ViewController ()<WKNavigationDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //创建WKWebView
    WKWebView * wkwebV = [[WKWebView alloc] initWithFrame:[UIScreen mainScreen].bounds];
    //添加到界面上
    [self.view addSubview:wkwebV];
    wkwebV.navigationDelegate = self;
    
    //加载网页
    NSURL * url = [NSURL URLWithString:@"http://m.dianping.com/tuan/deal/5501525"];
    NSURLRequest * request = [NSURLRequest requestWithURL:url];
    [wkwebV loadRequest:request];
}

#pragma mark--代理方法
//网页即将开始加载时调用:拦截请求
//拦截标签点击主动发送的请求
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
    NSString * urlStr = navigationAction.request.URL.absoluteString;
    NSLog(@"urlStr:%@",urlStr);
    
    if ([urlStr isEqualToString:@"hm://www.yaowoya.com"]) {
        NSLog(@"我点击了图片");
        //在此添加跳转的事件方法
        //......
    }
    
    //类似于UIWebView里面的那个返回Yes的功能
    decisionHandler(WKNavigationActionPolicyAllow);
}

//页面加载完成之后调用 : js注入
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
    NSMutableString * StrM = [NSMutableString string];
    [StrM appendString:@"var headerTag = document.getElementsByTagName('header')[0];headerTag.parentNode.removeChild(headerTag);"];
    [StrM appendString:@"var footerBtnTag = document.getElementsByClassName('footer-btn-fix')[0];footerBtnTag.parentNode.removeChild(footerBtnTag);"];
    [StrM appendString:@"var footTag = document.getElementsByClassName('footer')[0];footTag.parentNode.removeChild(footTag);"];
//点击顶部图片实现点击事件
    [StrM appendString:@"var imgTag = document.getElementsByTagName('figure')[0].children[0];imgTag.onclick = function imgClick(){window.location.href='hm://www.yaowoya.com'};"];
    //注入JS方法
    [webView evaluateJavaScript:StrM completionHandler:nil];
}

在使用WKWebView的代理方法decidePolicyForNavigationAction,会遇到一个常见的崩溃问题:
解决办法: 在webView:decidePolicyForNavigationAction:decisionHandler函数里需执行decisionHandler的block

崩溃问题: Terminating app due to uncaught exception 
‘NSInternalInconsistencyException’ reason: 
‘Completion handler passed to - [ViewController webView: 
decidePolicyForNavigationAction: decisionHandler:] was not called’
JavaScriptCore

JavaScriptCorewebkit的一个重要组成部分,主要是对JS进行解析和提供执行环境。它必须依赖于UIWebView或者WKWebView。我通过JavaScriptCore来实现上面的效果,直接上代码:

#import "ViewController.h"
#import <JavaScriptCore/JavaScriptCore.h>
@interface ViewController ()<UIWebViewDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    /*
     创建展示网页的控件
     */
    UIWebView * webV = [[UIWebView alloc] initWithFrame:[UIScreen mainScreen].bounds];
    webV.delegate = self;
    /*
     把展示网页的控件添加到根视图上面
     */
    [self.view addSubview:webV];
    
    /*
     使用webview加载网页
     */
    NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://m.dianping.com/tuan/deal/5501525"]];
    [webV loadRequest:request];
    
    //获取上下文
    //1.获取JS上下文
    JSContext * context = [webV valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

    //2.准备触发标签点击事件之后要执行的代码块
    context[@"share"] = ^(){
        NSLog(@"我点击了图片标签");
        //
        /*回到主线程刷新UI:在实际开发中,绝对不要在子线程里面刷新UI,不然会出现这种错误:
        This application is modifying the autolayout engine from a 
        background thread after the engine was accessed from the main 
        thread. This can lead to engine corruption and weird crashes.*/

        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            TestTableViewController * vc = [TestTableViewController new];
            [self.navigationController pushViewController:vc animated:YES];
        }];
    };
}

#pragma mark -- 网页加载完成之后会调用的代理方法
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    /*
     由于总共有三处修改,所以要拼接JS代码。
     webView直接提供了JS注入的方法
     */
    NSMutableString * StrM = [NSMutableString string];
    [StrM appendString:@"var headerTag = document.getElementsByTagName('header')[0];headerTag.parentNode.removeChild(headerTag);"];
    [StrM appendString:@"var footerBtnTag = document.getElementsByClassName('footer-btn-fix')[0];footerBtnTag.parentNode.removeChild(footerBtnTag);"];
    [StrM appendString:@"var footTag = document.getElementsByClassName('footer')[0];footTag.parentNode.removeChild(footTag);"];
    //给图片点击点击事件:‘share()’就是标签点击时间的标记(类似于自定义的URL)
    [StrM appendString:@"var imgTag = document.getElementsByTagName('figure')[0].children[0];imgTag.onclick = function imgClick(){share()};"];
    
//    [webView stringByEvaluatingJavaScriptFromString:StrM];
    /*
     1.获取JS上下文
     2.JS注入
     */
    JSContext * context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    [context evaluateScript:StrM];
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容

  • 虽然WKWebView是在Apple的WWDC 2014随iOS 8和OS X 10.10出来的,是为了解决UIW...
    winann阅读 135,236评论 196 641
  • 前言 关于UIWebView的介绍,相信看过上文的小伙伴们,已经大概清楚了吧,如果有问题,欢迎提问。 本文是本系列...
    CoderLF阅读 8,941评论 2 12
  • 随着H5技术的兴起,在iOS开发过程中,难免会遇到原生应用需要和H5页面交互的问题。其中会涉及方法调用及参数传值等...
    Chris_js阅读 3,053评论 1 8
  • 一、WebView WebView就是一个内嵌浏览器控件,在iOS中主要有两种WebView:UIWebView和...
    iOS祎阅读 1,068评论 0 2
  • 通过学习,你将会学习以下几个方面的内容: **什么是WKWebView以及它和UIWebView的区别是什么 **...
    SOI阅读 11,591评论 18 42