iOS與HTML混編,最好的例子就是網(wǎng)易新聞詳情頁(yè)的實(shí)現(xiàn),圖片與文字可以根據(jù)服務(wù)器返回的數(shù)據(jù)隨意排版,很方便
本文主要講WKWebView,與UIWebView和JavaScriptCore孰優(yōu)孰劣我就不比較了,
網(wǎng)易新聞頁(yè)實(shí)現(xiàn)流程我就不重復(fù)寫了,還有其他好的文章放在最后,
但感覺大多說(shuō)的不細(xì),對(duì)沒有web開發(fā)經(jīng)驗(yàn)的來(lái)說(shuō)有點(diǎn)難懂,所以本文會(huì)把我寫的一些簡(jiǎn)單的js代碼拿出來(lái),對(duì)沒有web基礎(chǔ)的來(lái)說(shuō)更加清晰
本文的基礎(chǔ)知識(shí)主要為:
1.點(diǎn)擊html按鈕,oc的控制器dismiss掉
2.點(diǎn)擊oc按鈕,js切換頁(yè)面
3.點(diǎn)擊html按鈕,js切換頁(yè)面
4.點(diǎn)擊html的div標(biāo)簽,js調(diào)用oc來(lái)present一個(gè)新的controller,上面有個(gè)返回按鈕,點(diǎn)擊可以返回webView的控制器
點(diǎn)擊獲取源代碼
效果圖就不放了,創(chuàng)建幾個(gè)文件把代碼全部復(fù)制一下就可以看到效果了

ViewController中有個(gè)按鈕,點(diǎn)擊即可跳轉(zhuǎn)到WebVC.
WebVC的.m文件,其中值得注意的是WKDelegate,是解決WKWebView循環(huán)引用問(wèn)題的代理
#import "WebVC.h"
#import <WebKit/WebKit.h>
#import "WKDelegateController.h"
@interface WebVC ()<WKUIDelegate,WKNavigationDelegate,WKDelegate>
@property (strong, nonatomic) WKWebView *webView;
@property (strong, nonatomic) WKUserContentController *userContent;
@property (weak, nonatomic) UIButton *backBtn;
@end
@implementation WebVC
- (void)dealloc
{
NSLog(@"無(wú)循環(huán)引用");
//這里需要注意,前面增加過(guò)的方法一定要remove掉。
//addScriptMessageHandler要和removeScriptMessageHandlerForName配套出現(xiàn),否則會(huì)造成內(nèi)存泄漏。
[self.userContent removeScriptMessageHandlerForName:@"ocMethod"];
[self.userContent removeScriptMessageHandlerForName:@"presentMethod"];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor lightGrayColor];
//創(chuàng)建配置
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
//創(chuàng)建UserContentController(提供javaScript向webView發(fā)送消息的方法)
self.userContent = [[WKUserContentController alloc] init];
//添加消息處理,
//注意: addScriptMessageHandler后面的參數(shù)指代的是需要遵守WKScriptMessageHandler協(xié)議,結(jié)束時(shí)需要移除
//但無(wú)論在哪里移除都會(huì)發(fā)現(xiàn)dealloc并不會(huì)執(zhí)行,這樣肯定是不行的,會(huì)造成內(nèi)存泄漏
//試了下用weak指針還是不能釋放,不知道是什么原因
//因此參考百度上的寫法是用一個(gè)新的controller來(lái)處理,新的controller再繞用delegate繞回來(lái),即使沒移除也會(huì)走dealloc了
WKDelegateController * delegateController = [[WKDelegateController alloc]init];
delegateController.delegate = self;
[self.userContent addScriptMessageHandler:delegateController name:@"ocMethod"];
[self.userContent addScriptMessageHandler:delegateController name:@"presentMethod"];
//將UserContent設(shè)置到配置文件中
config.userContentController = self.userContent;
//配置webView
self.webView = [[WKWebView alloc]initWithFrame:self.view.bounds configuration:config];
self.webView.UIDelegate = self;
self.webView.navigationDelegate = self;
[self.view addSubview:self.webView];
//加載本地html
NSURL *url = [[NSBundle mainBundle] URLForResource:@"index" withExtension:@"html"];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:urlRequest];
//添加一個(gè)返回按鈕
UIButton *backBtn = [[UIButton alloc]initWithFrame:CGRectMake(10, 35, 50, 50)];
[backBtn setTitle:@"返回" forState:UIControlStateNormal];
[backBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[backBtn addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside];
self.backBtn = backBtn;
[self.webView addSubview:backBtn];
}
//這里就是使用高端配置,js調(diào)用oc的處理地方。我們可以根據(jù)name和body,進(jìn)行橋協(xié)議的處理。
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
NSString *messageName = message.name;
if ([@"ocMethod" isEqualToString:messageName])
{
id messageBody = message.body;
NSLog(@"%@",messageBody);
//點(diǎn)擊html按鈕,讓當(dāng)前webView頁(yè)面dismiss掉
[self dismissViewControllerAnimated:YES completion:nil];
}
else if([@"presentMethod" isEqualToString:messageName])
{
id messageBody = message.body;
NSLog(@"%@",messageBody);
//彈出一個(gè)新的紅色背景的控制器
UIViewController *newVC = [[UIViewController alloc]init];
newVC.view.backgroundColor = [UIColor redColor];
//添加一個(gè)返回按鈕,返回webView
CGRect rect = CGRectMake(100,100,100,50);
UIButton *button = [[UIButton alloc]initWithFrame:rect];
[button setTitle:@"返回" forState:UIControlStateNormal];
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
button.titleLabel.font = [UIFont systemFontOfSize:20];
[button addTarget:self action:@selector(dismissNewVC) forControlEvents:UIControlEventTouchUpInside];
[newVC.view addSubview:button];
[self presentViewController:newVC animated:YES completion:nil];
}
}
//返回方法
-(void)dismissNewVC
{
[self dismissViewControllerAnimated:YES completion:nil];
}
//點(diǎn)擊oc按鈕,調(diào)用js方法
-(void)back
{
//第一種:直接調(diào)用
//無(wú)論web頁(yè)面跳轉(zhuǎn)多少次,只要按鈕存在,js都可以生效
[self.webView evaluateJavaScript:@"function sayHello(){ \
alert('jack') \
} \
sayHello()"
completionHandler:^(id _Nullable result, NSError * _Nullable error) {
}];
//第二種:直接調(diào)用html文件中的js代碼
//注意:這種方式只有在第一個(gè)web頁(yè)面js才能生效,跳轉(zhuǎn)到第二個(gè)web頁(yè)面就無(wú)效了
//因?yàn)轫?yè)面跳轉(zhuǎn)后,就不是我們引入的本地的html頁(yè)面了,自然也就引入不了我們本地的js代碼
//不過(guò)也正常,我們一般只需要在第一個(gè)頁(yè)面添加一個(gè)返回按鈕,dismiss掉這個(gè)webView,其他的功能都可以用html的按鈕實(shí)現(xiàn)
[self.webView evaluateJavaScript:@"hello()"completionHandler:^(id _Nullable result, NSError * _Nullable error) {
}];
//第三種:調(diào)用html文件中引入的js文件的js代碼
//注意:js效果與第二種相同
[self.webView evaluateJavaScript:@"back()"completionHandler:^(id _Nullable result, NSError * _Nullable error) {
}];
}
//wkWebView直接調(diào)用js的彈窗是無(wú)效的,需要攔截js中的alert,用oc的方式展現(xiàn)出來(lái)
//該方法中的message參數(shù)就是我們JS代碼中alert函數(shù)里面的參數(shù)內(nèi)容
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
{
NSLog(@"----------%@",message);
UIAlertController *alertView = [UIAlertController alertControllerWithTitle:@"js的彈窗" message:message preferredStyle:UIAlertControllerStyleAlert];
[alertView addAction:[UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
//一定要調(diào)用下這個(gè)block,否則會(huì)崩
//API說(shuō)明:The completion handler to call after the alert panel has been dismissed
completionHandler();
}]];
[self presentViewController:alertView animated:YES completion:nil];
}
@end
WKDelegateController.h文件:
#import <UIKit/UIKit.h>
#import <WebKit/WebKit.h>
@class WKDelegateController;
@protocol WKDelegate <NSObject>
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;
@end
@interface WKDelegateController : UIViewController <WKScriptMessageHandler>
@property (weak , nonatomic) id<WKDelegate> delegate;
@end
WKDelegateController.m文件
#import "WKDelegateController.h"
@interface WKDelegateController ()
@end
@implementation WKDelegateController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
if ([self.delegate respondsToSelector:@selector(userContentController:didReceiveScriptMessage:)])
{
[self.delegate userContentController:userContentController didReceiveScriptMessage:message];
}
}
index.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>js與oc互調(diào)</title>
<link href="index.css" rel="stylesheet">
</head>
<body>
<button onclick="clickBtn()"> 點(diǎn)擊按鈕跳轉(zhuǎn)到baidu </button>
<br>
<button onclick="dismiss()"> 點(diǎn)擊按鈕dismiss回去 </button>
<!--導(dǎo)航-->
<div >
<ul>
<div class="time" onclick="clickTime()">點(diǎn)擊我present一個(gè)新的controller</div>
<li><a >baidu</a></li>
<li><a href="#" >about</a></li>
<li><a href="#" >services</a></li>
<li><a href="#" >gallery</a></li>
<li><a href="#" >contact</a></li>
</ul>
</div>
<!--引入的js函數(shù)文件-->
<script src="index.js" type="text/javascript"></script>
<!--直接寫的js函數(shù)-->
<script type="text/javascript">
function hello(){
alert("你好!");
}
</script>
</body>
</html>
index.js文件
//確認(rèn)js加載成功
window.onload = function (){
alert(0);
}
//點(diǎn)擊html按鈕,調(diào)用js方法
function clickBtn(){
window.location.;
}
//點(diǎn)擊html按鈕,調(diào)用oc方法
function dismiss(){
window.webkit.messageHandlers.ocMethod.postMessage("我點(diǎn)擊html按鈕,調(diào)用oc的方法,讓webView消失");
}
//點(diǎn)擊html的div標(biāo)簽,調(diào)用oc方法
function clickTime(){
window.webkit.messageHandlers.presentMethod.postMessage("我點(diǎn)擊div標(biāo)簽,調(diào)用oc的方法,彈出一個(gè)控制器");
}
//點(diǎn)擊oc按鈕,要調(diào)用的js方法
function back() {
window.location.;
}
最后是無(wú)關(guān)緊要的index.css文件
*{
padding = 0;
margin = 0;
}
body{
padding:100px 0 0 0;
text-align:center;
background-color:lightgray;
font-size:40px;
}
button{
font-size:50px;
}
li{
list-style-type:none
}
a{
font-size:50px;
}
比較好的鏈接,也介紹了一些第三方框架:
這個(gè)實(shí)現(xiàn)網(wǎng)易新聞詳情頁(yè)寫的很詳細(xì),所以我就不寫了.但是注意這里遺漏了解決循環(huán)引用問(wèn)題,練習(xí)的時(shí)候要注意:<a href="http://www.itdecent.cn/p/75f3abd40cc1">iOS-使用WKWebview實(shí)現(xiàn)新聞詳情頁(yè)</a>
<a href="http://www.itdecent.cn/p/1f2dc3d3090a">iOS WKWebView導(dǎo)致ViewController不調(diào)用dealloc方法</a>
WKWebView并不會(huì)去NSHTTPCookieStorage中讀取cookie,因此導(dǎo)致cookie丟失解決辦法:<a href="http://www.itdecent.cn/p/4fa8c4eb1316">IOS進(jìn)階之WKWebView</a>
講UIWebView與JavaScriptCore細(xì)的文章:
<a href="http://www.itdecent.cn/p/d19689e0ed83">iOS下JS與原生OC互相調(diào)用(總結(jié))</a>
<a >iOS JavaScriptCore使用</a>
<a href="http://www.itdecent.cn/p/84a6b1ac974a">iOS H5容器的一些探究(一):UIWebView和WKWebView的比較和選擇</a>