我们在开发中,经常会用webView来加载网页,有时候,H5那边给到iOS的网页,加载出来后发现,网页原生的导航栏、悬浮的按钮、底部“电脑版”这类文字没有去掉,让iOS自己来简单处理,那应该怎么办呢?这时候就需要通过JS注入到OC中来实现想要的效果。有三种方式:
UIWebView、WKWebView、JavaScriptCore
,下面一一介绍。
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];
}
效果如下,成功清理干净。
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
JavaScriptCore
是webkit
的一个重要组成部分,主要是对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];
}