雖然
WKWebView
是在Apple
的WWDC 2014
隨iOS 8
和OS X 10.10
出來的,是為了解決UIWebView
加載速度慢俊戳、占用內(nèi)存大的問題。但是由于之前還要適配iOS7
,又不想做兩套加載頁面(主要是因?yàn)閼校┌ッ模跃蜎]有使用∽馄現(xiàn)在項(xiàng)目都適配iOS 8
以上了阶女,所以就開始使用WKWebView
了,但是發(fā)現(xiàn)在使用的時(shí)候有好多坑哩治,希望這篇文章能帶大家繞過坑秃踩,更好的使用WKWebView
。
這篇文章主要介紹了以下問題业筏,方便小伙伴們查閱:
- WKWebView的基本介紹和使用
- WKWebView和JavaScript的交互
- 解決WKWebView加載POST請(qǐng)求無法發(fā)送參數(shù)問題
WKWebView的基本介紹和使用
WKWebView的幾個(gè)代理方法
WKWebView
是蘋果在iOS 8
中引入的新組件憔杨,目的是給出一個(gè)新的高性能的WebView
解決方案,擺脫過去UIWebView
的老蒜胖、舊消别、笨重,特別是內(nèi)存占用量巨大的問題翠勉,它使用Nitro JavaScript
引擎妖啥,這意味著所有第三方瀏覽器運(yùn)行JavaScript
將會(huì)跟safari
一樣快。
看到我這篇文章的小伙伴对碌,對(duì)iOS
的開發(fā)應(yīng)該有一定的了解荆虱,肯定用過UIWebView
,現(xiàn)在就用UIWebView
和WKWebView
的代理方法做一個(gè)對(duì)比朽们。
-
加載狀態(tài)的回調(diào)
(用來跟蹤頁面加載的過程(頁面開始加載怀读、加載完成、加載失敗的方法)骑脱,還可以決定是否跳轉(zhuǎn))
:- 準(zhǔn)備加載頁面
UIWebViewDelegate: - webView:shouldStartLoadWithRequest:navigationType
WKNavigationDelegate: - webView:didStartProvisionalNavigation:
2. **內(nèi)容開始加載**`(view的過渡動(dòng)畫可在此方法中加載)`
UIWebViewDelegate: - webViewDidStartLoad:
WKNavigationDelegate: - webView:didCommitNavigation:
3. **頁面加載完成**`(view的過渡動(dòng)畫的移除可在此方法中進(jìn)行)`
UIWebViewDelegate: - webViewDidFinishLoad:
WKNavigationDelegate: - webView:didFinishNavigation:
4. **頁面加載失敗**
UIWebViewDelegate: - webView:didFailLoadWithError:
WKNavigationDelegate: - webView:didFailNavigation:withError:
WKNavigationDelegate: - webView:didFailProvisionalNavigation:withError:
此外菜枷,WKWebKit還有三個(gè)頁面跳轉(zhuǎn)
的代理方法:
- 頁面跳轉(zhuǎn)的代理
- 接收到服務(wù)器跳轉(zhuǎn)請(qǐng)求的代理
WKNavigationDelegate: - webView:didReceiveServerRedirectForProvisionalNavigation:
2. **在收到響應(yīng)后,決定是否跳轉(zhuǎn)的代理**
WKNavigationDelegate: - webView:decidePolicyForNavigationResponse:decisionHandler:
3. **在發(fā)送請(qǐng)求之前叁丧,決定是否跳轉(zhuǎn)的代理**
WKNavigationDelegate: - webView:decidePolicyForNavigationAction:decisionHandler:
WKWebView增加的屬性
- WKWebViewConfiguration *configuration:初始化WKWebView的時(shí)候的配置啤誊,后面會(huì)用到
- WKBackForwardList *backForwardList:相當(dāng)于訪問歷史的一個(gè)列表
- double estimatedProgress:進(jìn)度岳瞭,有這個(gè)之后就不用自己寫假的進(jìn)度條了
WKWebView的使用
OC代碼:
// 創(chuàng)建WKWebView
WKWebView *webView = [[WKWebView alloc] initWithFrame:[UIScreen mainScreen].bounds];
// 設(shè)置訪問的URL
NSURL *url = [NSURL URLWithString:@"http://www.reibang.com"];
// 根據(jù)URL創(chuàng)建請(qǐng)求
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// WKWebView加載請(qǐng)求
[webView loadRequest:request];
// 將WKWebView添加到視圖
[self.view addSubview:webView];
Swift代碼:
// 創(chuàng)建WKWebView
let webView = WKWebView(frame: UIScreen.mainScreen().bounds)
// 設(shè)置訪問的URL
let url = NSURL(string: "http://www.reibang.com")
// 根據(jù)URL創(chuàng)建請(qǐng)求
let requst = NSURLRequest(URL: url!)
// WKWebView加載請(qǐng)求
webView.loadRequest(requst)
// 將WKWebView添加到視圖
view.addSubview(webView)
可以看到很簡(jiǎn)單,和UIWebView并沒有多少差別蚊锹,然而性能就刷刷刷的提上去了瞳筏,是不是很爽呢?如果你只是簡(jiǎn)單的集成個(gè)Web頁到App牡昆,這些已經(jīng)夠了姚炕。不過很多時(shí)候并沒有那么簡(jiǎn)單,還需要處理各種東西丢烘,那么接著往后看柱宦。
WKWebView和JavaScript的交互
在
WebKit
框架中,有WKWebView
可以替換UIKit
的UIWebView
和AppKit
的WebView
播瞳,而且提供了在兩個(gè)平臺(tái)可以一致使用的接口掸刊。WebKit
框架使得開發(fā)者可以在原生App中使用Nitro
來提高網(wǎng)頁的性能和表現(xiàn),Nitro
就是Safari
的JavaScript
引擎,WKWebView
不支持JavaScriptCore
的方式但提供message handler
的方式為JavaScript
與Native通信狐史。(這個(gè)引自天狐博客痒给,更多的與UIWebView
或者WKWebView
的交互方法可以在這里看到。下面部分代碼(例如JS)也是竊取這個(gè)作者的骏全,尊重原著苍柏,所以把原博客地址放這里,與JS交互寫的比我好多了姜贡。)
Native調(diào)用JavaScript
方法
原生調(diào)用JavaScript的代碼需要在頁面加載完成之后试吁,就是在 - webView:didFinishNavigation:
代理方法里面
OC代碼:
[webView evaluateJavaScript:@"showAlert('奏是一個(gè)彈框')" completionHandler:^(id item, NSError * _Nullable error) {
// Block中處理是否通過了或者執(zhí)行JS錯(cuò)誤的代碼
}];
Swift代碼:
webView.evaluateJavaScript("showAlert('奏是一個(gè)彈框')") { (item, error) in
// 閉包中處理是否通過了或者執(zhí)行JS錯(cuò)誤的代碼
}
大家可以看到這段JS代碼是最簡(jiǎn)單的彈出一個(gè)Alert的代碼,后面WKWebView加載POST請(qǐng)求參數(shù)問題
中還會(huì)有一個(gè)加載POST請(qǐng)求的JS代碼楼咳,先不要管它了熄捍,請(qǐng)各位看官繼續(xù)往后翻,看看JavaScript
怎么調(diào)用Native的方法母怜。
JavaScript
調(diào)用Native方法
-
JavaScript的配置
JavaScript
調(diào)用Native的方法就需要前端和Native的小伙伴們配合了余耽,需要前端的小伙伴在JS的方法中調(diào)用:window.webkit.messageHandlers.NativeMethod.postMessage("就是一個(gè)消息啊");
這行代碼。請(qǐng)注意苹熏,這個(gè)
NativeMethod
是和App中要統(tǒng)一的碟贾,配置方法將在下面的Native中書寫。 -
Native App的代碼配置
下面該Native的代碼的配置了轨域,細(xì)心的小伙伴可能已經(jīng)發(fā)現(xiàn)了袱耽,創(chuàng)建
WKWebView
的時(shí)候,除了有- initWithFrame:
方法外干发,還有一個(gè)高端的方法:- initWithFrame:configuration:
方法朱巨。那句名言是誰說的來著:普通玩家選擇推薦配置,高端玩家選擇自定義配置
枉长,就當(dāng)是我說的吧(那個(gè)拿鞋的把鞋穿上吧冀续,我承認(rèn)不是我說的??)琼讽。這個(gè)方法就是用來自定義配置的,具體怎么自定義呢沥阳,童鞋們接著往下看吧跨琳。OC代碼:
// 創(chuàng)建配置 WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init]; // 創(chuàng)建UserContentController(提供JavaScript向webView發(fā)送消息的方法) WKUserContentController* userContent = [[WKUserContentController alloc] init]; // 添加消息處理,注意:self指代的對(duì)象需要遵守WKScriptMessageHandler協(xié)議桐罕,結(jié)束時(shí)需要移除 [userContent addScriptMessageHandler:self name:@"NativeMethod"]; // 將UserConttentController設(shè)置到配置文件 config.userContentController = userContent; // 高端的自定義配置創(chuàng)建WKWebView WKWebView *webView = [[WKWebView alloc] initWithFrame:[UIScreen mainScreen].bounds configuration:config]; // 設(shè)置訪問的URL NSURL *url = [NSURL URLWithString:@"http://www.reibang.com"]; // 根據(jù)URL創(chuàng)建請(qǐng)求 NSURLRequest *request = [NSURLRequest requestWithURL:url]; // WKWebView加載請(qǐng)求 [webView loadRequest:request]; // 將WKWebView添加到視圖 [self.view addSubview:webView];
Swift代碼:
// 創(chuàng)建配置 let config = WKWebViewConfiguration() // 創(chuàng)建UserContentController(提供JavaScript向webView發(fā)送消息的方法) let userContent = WKUserContentController() // 添加消息處理,注意:self指代的對(duì)象需要遵守WKScriptMessageHandler協(xié)議桂敛,結(jié)束時(shí)需要移除 userContent.addScriptMessageHandler(self, name: "NativeMethod") // 將UserConttentController設(shè)置到配置文件 config.userContentController = userContent // 高端的自定義配置創(chuàng)建WKWebView let webView = WKWebView(frame: UIScreen.mainScreen().bounds, configuration: config) // 設(shè)置訪問的URL let url = NSURL(string: "http://www.reibang.com") // 根據(jù)URL創(chuàng)建請(qǐng)求 let requst = NSURLRequest(URL: url!) // 設(shè)置代理 webView.navigationDelegate = self // WKWebView加載請(qǐng)求 webView.loadRequest(requst) // 將WebView添加到當(dāng)前view view.addSubview(webView)
可以看到功炮,添加消息處理的
handler
的name
,就是JavaScript
中調(diào)用時(shí)候的NativeMethod
术唬,這兩個(gè)要保持一致薪伏。請(qǐng)把URL換成你自己的。請(qǐng)注意第
6
行的代碼配置當(dāng)前ViewController
為MessageHandler
粗仓,需要服從WKScriptMessageHandler
協(xié)議嫁怀,如果出現(xiàn)警告??,請(qǐng)檢查是否服從了這個(gè)協(xié)議借浊。注意塘淑!注意!注意:上面將當(dāng)前
ViewController
設(shè)置為MessageHandler
之后需要在當(dāng)前ViewController
銷毀前將其移除蚂斤,否則會(huì)造成內(nèi)存泄漏存捺。移除的代碼如下:
OC代碼:
[webView.configuration.userContentController removeScriptMessageHandlerForName:@"NativeMethod"];
Swift代碼:
webView.configuration.userContentController.removeScriptMessageHandlerForName("NativeMethod")
請(qǐng)注意這個(gè)
Name
和上面創(chuàng)建WKWebView
的配置中注冊(cè)的名字是一樣的,要保持對(duì)應(yīng)曙蒸。好了捌治,現(xiàn)在萬事俱備,只欠東風(fēng)了纽窟。東風(fēng)是什么呢肖油,就是該在哪兒處理”鄹郏可以看到
WKScriptMessageHandler
的協(xié)議里面只有一個(gè)方法森枪,就是:- userContentController:didReceiveScriptMessage:
相信聰明的你已經(jīng)猜到了。是的趋艘,就是在這個(gè)代理方法里面操作:如果
JavaScript
執(zhí)行已經(jīng)寫好的:window.webkit.messageHandlers.NativeMethod.postMessage("就是一個(gè)消息啊");
這行代碼疲恢,這個(gè)代理方法就會(huì)走,并且會(huì)有個(gè)WKScriptMessage
的對(duì)象瓷胧,這個(gè)WKScriptMessage
對(duì)象有個(gè)name
屬性显拳,拿到之后你會(huì)發(fā)現(xiàn),就是我們注冊(cè)的NativeMethod
這個(gè)字符串搓萧,這時(shí)候你就可以手動(dòng)調(diào)用Native的方法了杂数。如果有多個(gè)方法需要調(diào)用的話怎么辦宛畦,看到JavaScript
中postMessage()
方法有一個(gè)參數(shù)了沒有,可以根據(jù)這里的參數(shù)來區(qū)分調(diào)用原生App的哪個(gè)方法揍移。
代碼很簡(jiǎn)單次和,就不寫了。什么那伐?你說你還需要寫踏施?好吧,那我還是貼出來吧:OC代碼:
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message { // 判斷是否是調(diào)用原生的 if ([@"NativeMethod" isEqualToString:message.name]) { // 判斷message的內(nèi)容罕邀,然后做相應(yīng)的操作 if ([@"close" isEqualToString:message.body]) { } } }
Swift代碼:
func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) { // 判斷是否是調(diào)用原生的 if "NativeMethod" == message.name { // 判斷message的內(nèi)容畅形,然后做相應(yīng)的操作 if "close" == message.body as! String { } } }
上面的方法就可以獲取到
JavaScript
發(fā)送的Message了,JavaScript
可以這樣調(diào)用:window.webkit.messageHandlers.NativeMethod.postMessage("close");
诉探,這時(shí)候上面的代理方法的兩個(gè)if
判斷都能通過日熬,不同的操作可增加里面的if
語句的分支判斷message的內(nèi)容來進(jìn)行不同的Native代碼的調(diào)用,也就是JavaScript
的postMessage
方法的參數(shù)的不同來區(qū)分不同的操作肾胯。好了竖席,現(xiàn)在
WKWebView
和JavaScript
的簡(jiǎn)單交互你也會(huì)了。用WKWebView
的時(shí)候貌似也還算開心敬肚。但是不要高興的太早毕荐,下面就要有坑了。
解決WKWebView加載POST請(qǐng)求無法發(fā)送參數(shù)問題
也許你用
UIWebView
加載過POST請(qǐng)求的頁面帘皿,感覺并沒有什么難點(diǎn)或者需要注意的地方东跪,那真的是圖樣圖森破了,因?yàn)槲乙策@樣天真過鹰溜。直到我踩了很多坑之后虽填,我才發(fā)現(xiàn)夢(mèng)想與現(xiàn)實(shí)之間的差別,不過沒關(guān)系曹动,我又要說另一句名言了:沒有挖不到的墻角...斋日,咳咳咳,說錯(cuò)了墓陈,請(qǐng)重新來BGM恶守,跟我一起說:沒有解決不了的Bug,只有不努力的碼農(nóng)贡必!
(各位架構(gòu)師兔港、高級(jí)開發(fā)工程師請(qǐng)手下留情,我說的碼農(nóng)是我??)
來來來仔拟,先來一發(fā)POST
請(qǐng)求加載WebView
衫樊。你會(huì)說,這還不easy?下面就來一個(gè)科侈,走起:
OC代碼:
// 創(chuàng)建WKWebView
WKWebView *webView = [[WKWebView alloc] initWithFrame:[UIScreen mainScreen].bounds];
// 設(shè)置訪問的URL
NSURL *url = [NSURL URLWithString:@"http://www.example.com"];
// 根據(jù)URL創(chuàng)建請(qǐng)求
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 設(shè)置請(qǐng)求方法為POST
[request setHTTPMethod:@"POST"];
// WKWebView加載請(qǐng)求
[webView loadRequest:request];
// 將WKWebView添加到視圖
[self.view addSubview:webView];
Swift代碼:
// 創(chuàng)建WKWebView
let webView = WKWebView(frame: UIScreen.mainScreen().bounds)
// 設(shè)置訪問的URL
let url = NSURL(string: "http://www.example.com")
// 根據(jù)URL創(chuàng)建請(qǐng)求
let requst = NSMutableURLRequest(URL: url!)
// 設(shè)置請(qǐng)求方法為POST
requst.HTTPMethod = "POST"
// WKWebView加載請(qǐng)求
webView.loadRequest(requst)
// 將WKWebView添加到視圖
view.addSubview(webView)
這樣確實(shí)加載POST
請(qǐng)求的網(wǎng)頁成功了(注意請(qǐng)把鏈接換成自己的)载佳,你一定露出了得意的笑容。但是騷年臀栈,不要高興的太早蔫慧,這只是一個(gè)簡(jiǎn)單的POST請(qǐng)求,還沒有添加參數(shù)呢权薯。于是乎姑躲,你又說:那更簡(jiǎn)單,在第9
行插入如下代碼即可(比方說這個(gè)接口是登錄):
OC代碼:
// 設(shè)置請(qǐng)求參數(shù)
[request setHTTPBody:[@"username=aaa&password=123" dataUsingEncoding:NSUTF8StringEncoding]];
Swift代碼:
// 設(shè)置請(qǐng)求參數(shù)
requst.HTTPBody = "username=aaa&password=123".dataUsingEncoding(NSUTF8StringEncoding)
這種方法在UIWebView
里面是沒有問題的崭闲,所以你認(rèn)為在這里也應(yīng)該是沒有問題的肋联。從理論上講應(yīng)該是這樣的,但是我要恭喜你了刁俭,這是WKWebView
的Bug,讓你給碰到了韧涨。這里寫的POST
請(qǐng)求沒有問題牍戚,但是就是不會(huì)把這兩個(gè)參數(shù)傳上去的,不信你可以試試(截止我發(fā)表這篇博客的日期虑粥,iOS 9.3
并沒有修復(fù)此問題)如孝。
好了,不廢話了(其實(shí)已經(jīng)說了很多廢話了)娩贷,下面看解決辦法(如果你需要適配iOS 8
請(qǐng)直接使用方法2
):
- 使用
NSURLSession
發(fā)送一個(gè)請(qǐng)求第晰,然后把請(qǐng)求下來的數(shù)據(jù)當(dāng)作本地HTML
加載 - 使用
JavaScript
解決WKWebView
無法發(fā)送POST
參數(shù)問題
1. 使用NSURLSession
解決WKWebView
無法POST
參數(shù)的問題(性能和結(jié)果都可能有問題,不推薦使用)
當(dāng)發(fā)現(xiàn)POST
無法傳遞參數(shù)的時(shí)候彬祖,我首先想到的是換個(gè)方法來茁瘦,就是用一般的請(qǐng)求方式:NSURLSession
發(fā)送請(qǐng)求,然后把接收到的數(shù)據(jù)轉(zhuǎn)化成字符串储笑,然后再用WKWebView
加載甜熔。大家可能已經(jīng)看出來了,需要把整個(gè)網(wǎng)頁放到內(nèi)存中或著放到本地然后再加載突倍,所以肯定消耗內(nèi)存呀腔稀。下面貼代碼吧:
OC代碼:
// 創(chuàng)建WKWebView
WKWebView *webView = [[WKWebView alloc] initWithFrame:[UIScreen mainScreen].bounds];
// 將WKWebView添加到當(dāng)前View
[self.view addSubview:webView];
// 設(shè)置訪問的URL
NSURL *url = [NSURL URLWithString:@"http://www.example.com"];
// 根據(jù)URL創(chuàng)建請(qǐng)求
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 設(shè)置請(qǐng)求方法為POST
[request setHTTPMethod:@"POST"];
// 設(shè)置請(qǐng)求參數(shù)
[request setHTTPBody:[@"username=aaa&password=123" dataUsingEncoding:NSUTF8StringEncoding]];
// 實(shí)例化網(wǎng)絡(luò)會(huì)話
NSURLSession *session = [NSURLSession sharedSession];
// 創(chuàng)建請(qǐng)求Task
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// 將請(qǐng)求到的網(wǎng)頁數(shù)據(jù)用loadHTMLString 的方法加載
NSString *htmlStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[webView loadHTMLString:htmlStr baseURL:nil];
}];
// 開啟網(wǎng)絡(luò)任務(wù)
[task resume];
Swift代碼:
// 創(chuàng)建WKWebView
let webView = WKWebView(frame: UIScreen.mainScreen().bounds)
// 設(shè)置訪問的URL
let url = NSURL(string: "http://www.example.com")
// 根據(jù)URL創(chuàng)建請(qǐng)求
let requst = NSMutableURLRequest(URL: url!)
// 設(shè)置請(qǐng)求方法為POST
requst.HTTPMethod = "POST"
// 設(shè)置請(qǐng)求參數(shù)
requst.HTTPBody = "username=aaa&password=123".dataUsingEncoding(NSUTF8StringEncoding)
// 將WKWebView添加到視圖
view.addSubview(webView)
// 實(shí)例化網(wǎng)絡(luò)會(huì)話
let session = NSURLSession.sharedSession()
// 創(chuàng)建請(qǐng)求Task
let task = session.dataTaskWithRequest(requst) { (data, response, error) in
webView.loadHTMLString(String(data: data!, encoding: NSUTF8StringEncoding)!, baseURL: nil)
}
task.resume()
當(dāng)你用iOS 9
以上的設(shè)備的時(shí)候,貌似完全沒有一點(diǎn)問題羽历,只是需要請(qǐng)求下來再放而已焊虏。但是注意前提條件:iOS 9
,當(dāng)你用iOS 8
的時(shí)候秕磷,發(fā)現(xiàn)你的網(wǎng)頁的樣式和JavaScript
事件全部沒有了诵闭。是不是有一種呵呵的沖動(dòng),那你就盡情呵呵吧跳夭。如果你要適配iOS 8
涂圆,那么這個(gè)方法也不符合你的氣質(zhì)们镜。
其實(shí)這個(gè)東西和加載本地網(wǎng)頁無法加載CSS樣式和JS一樣,如果你也加載本地HTML文件出現(xiàn)問題润歉,請(qǐng)查看Jay神
的WKWebView使用遇到的坑模狭。盡給別人打廣告了,呵呵踩衩,聲明一下敖鲤摹:我跟這些人木有關(guān)系,只是為了方便大家查閱而已驱富,誰讓我那么的大公無私呢??锚赤。
好了,好了褐鸥,來看一個(gè)更好的解決辦法吧:
2. 使用JavaScript
解決WKWebView
無法發(fā)送POST
參數(shù)問題
開始之前我先說一下實(shí)現(xiàn)思路线脚,方便大家理解,如果出錯(cuò)了也能知道錯(cuò)誤的地方:
- 將一個(gè)包含
JavaScript
的POST
請(qǐng)求的HTML
代碼放到工程目錄中- 加載這個(gè)包含
JavaScript
的POST
請(qǐng)求的代碼到WKWebView
- 加載完成之后叫榕,用Native調(diào)用
JavaScript
的POST
方法并傳入?yún)?shù)來完成請(qǐng)求
-
創(chuàng)建包含
JavaScript
的POST
請(qǐng)求的HTML
代碼相關(guān)代碼:
<html> <head> <script> //調(diào)用格式: post('URL', {"key": "value"}); function post(path, params) { var method = "post"; var form = document.createElement("form"); form.setAttribute("method", method); form.setAttribute("action", path); for(var key in params) { if(params.hasOwnProperty(key)) { var hiddenField = document.createElement("input"); hiddenField.setAttribute("type", "hidden"); hiddenField.setAttribute("name", key); hiddenField.setAttribute("value", params[key]); form.appendChild(hiddenField); } } document.body.appendChild(form); form.submit(); } </script> </head> <body> </body>
</html>
```
將這段代碼拷貝下來浑侥,然后粘貼到文本編輯器中,名字可以隨意起晰绎,比方說保存為:JSPOST.html
寓落,然后拷貝到工程目錄中,記得選擇對(duì)應(yīng)的Target和勾選Copy items if needed
(默認(rèn)應(yīng)該是勾選的)荞下。這時(shí)候伶选,就可以用這段JavaScript
代碼來發(fā)送帶參數(shù)的POST
請(qǐng)求了。
-
將對(duì)應(yīng)的
JavaScript
代碼通過加載本地網(wǎng)頁的形式加載到WKWebView
OC代碼:
// JS發(fā)送POST的Flag尖昏,為真的時(shí)候會(huì)調(diào)用JS的POST方法(僅當(dāng)?shù)谝淮蔚臅r(shí)候加載本地JS) self.needLoadJSPOST = YES; // 創(chuàng)建WKWebView self.webView = [[WKWebView alloc] initWithFrame:[UIScreen mainScreen].bounds]; //設(shè)置代理 self.webView.navigationDelegate = self; // 獲取JS所在的路徑 NSString *path = [[NSBundle mainBundle] pathForResource:@"JSPOST" ofType:@"html"]; // 獲得html內(nèi)容 NSString *html = [[NSString alloc] initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]; // 加載js [self.webView loadHTMLString:html baseURL:[[NSBundle mainBundle] bundleURL]]; // 將WKWebView添加到當(dāng)前View [self.view addSubview:self.webView];
Swift代碼:
// JS發(fā)送POST的Flag仰税,為真的時(shí)候會(huì)調(diào)用JS的POST方法(僅當(dāng)?shù)谝淮蔚臅r(shí)候加載本地JS) needLoadJSPOST = true // 創(chuàng)建WKWebView webView = WKWebView(frame: UIScreen.mainScreen().bounds) //設(shè)置代理 webView.navigationDelegate = self // 獲取JS路徑 let path = NSBundle.mainBundle().pathForResource("JSPOST", ofType: "html") // 獲得html內(nèi)容 do { let html = try String(contentsOfFile: path!, encoding: NSUTF8StringEncoding) // 加載js webView.loadHTMLString(html, baseURL: NSBundle.mainBundle().bundleURL) } catch { } // 將WKWebView添加到當(dāng)前View view.addSubview(webView)
這段代碼就相當(dāng)于把工程中的
JavaScript
腳本加載到WKWebView
中了,后面就是看怎么用了会宪。(請(qǐng)注意換成您的文件名) -
Native調(diào)用
JavaScript
腳本并傳入?yún)?shù)來完成POST
請(qǐng)求還記得
WKWebView和JavaScript的交互
這一節(jié)嘛肖卧?現(xiàn)在該Native調(diào)用JavaScript
了,如果忘記了掸鹅,請(qǐng)往前翻溫故一下:- webView:didFinishNavigation:
代理表明頁面已經(jīng)加載完成塞帐,我們?cè)谶@里操作,下面上代碼:OC代碼:
// 加載完成的代理方法 - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { // 判斷是否需要加載(僅在第一次加載) if (self.needLoadJSPOST) { // 調(diào)用使用JS發(fā)送POST請(qǐng)求的方法 [self postRequestWithJS]; // 將Flag置為NO(后面就不需要加載了) self.needLoadJSPOST = NO; } } // 調(diào)用JS發(fā)送POST請(qǐng)求 - (void)postRequestWithJS { // 發(fā)送POST的參數(shù) NSString *postData = @"\"username\":\"aaa\",\"password\":\"123\""; // 請(qǐng)求的頁面地址 NSString *urlStr = @"http://www.postexample.com"; // 拼裝成調(diào)用JavaScript的字符串 NSString *jscript = [NSString stringWithFormat:@"post('%@', {%@});", urlStr, postData]; // NSLog(@"Javascript: %@", jscript); // 調(diào)用JS代碼 [self.webView evaluateJavaScript:jscript completionHandler:^(id object, NSError * _Nullable error) { }]; }
Swift代碼:
// 加載完成的代理方法 func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) { // 判斷是否需要加載(僅在第一次加載) if needLoadJSPOST { // 調(diào)用使用JS發(fā)送POST請(qǐng)求的方法 postRequestWithJS() // 將Flag置為NO(后面就不需要加載了) needLoadJSPOST = false } } // 調(diào)用JS發(fā)送POST請(qǐng)求 func postRequestWithJS() { // 發(fā)送POST的參數(shù) let postData = "\"username\":\"aaa\",\"password\":\"123\"" // 請(qǐng)求的頁面地址 let urlStr = "http://www.postexample.com" // 拼裝成調(diào)用JavaScript的字符串 let jscript = "post('\(urlStr)', {\(postData)});" // 調(diào)用JS代碼 webView.evaluateJavaScript(jscript) { (object, error) in } }
好了巍沙,到目前為止你的請(qǐng)求就發(fā)出去了葵姥。相信后面的版本會(huì)解決這個(gè)問題,但是現(xiàn)在你要用的話也得有辦法句携,誰讓已經(jīng)入了
Apple
的坑呢榔幸,誰讓UIWebView
太不給力了呢.
寫在最后:
當(dāng)時(shí)選擇WKWebView
就是為了提高性能,但是沒有想到遇到這么多坑,從看iOS 9
才解決了iOS 8
無法加載本地樣式的問題削咆,有時(shí)候蘋果解決問題的速度還有略慢的牍疏,到現(xiàn)在POST
請(qǐng)求參數(shù)都發(fā)不出去也真是不應(yīng)該。不過沒辦法拨齐,先解決了鳞陨,說不定iOS 10
出來之后解決了呢。(我雖然有iOS 10
的設(shè)備瞻惋,但是我還沒有測(cè)試厦滤,感興趣的小伙伴們可以試試)。大家如果有什么問題歼狼,歡迎留言提問掏导。謝謝支持!