H5因其及時(shí)響應(yīng)的更新速度媲美著需求的速度和較高的趣味性受到越來(lái)越多的用戶的青睞盖矫。目前,大多數(shù)的應(yīng)用中都嵌入了H5击奶。優(yōu)點(diǎn)非常明顯辈双。那么在iOS應(yīng)用中如何嵌入一個(gè)H5,并且和它進(jìn)行交互就成了一個(gè)勢(shì)必要掌握的技術(shù)了柜砾。本文我將結(jié)合我在項(xiàng)目中的一些需求整理出對(duì)應(yīng)的技術(shù)點(diǎn)湃望,僅供參考。
在iOS開發(fā)中痰驱,H5的嵌入可以通過(guò)UIWebView或者WKWebView证芭。這兩個(gè)都是繼承UIView,來(lái)加載web數(shù)據(jù)的類担映。UIWebView是在iOS2的時(shí)候開始使用的废士。特點(diǎn)是加載速度慢,占用內(nèi)存多蝇完,優(yōu)化艱難官硝。WKWebView是在iOS8蘋果新推出的,加載速度快四敞,占用內(nèi)存較少泛源,是一個(gè)不錯(cuò)的選擇。如果想要比較兩者的區(qū)別忿危,您可以選擇一個(gè)網(wǎng)頁(yè)進(jìn)行測(cè)試一下达箍。鑒上所述,我們選擇WKWebView進(jìn)行開發(fā)铺厨。好了缎玫,廢話不多說(shuō)了。
1.WKWebView創(chuàng)建和加載
- (void)createWebView
{
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init]
// 根據(jù)需要去設(shè)置對(duì)應(yīng)的屬性
WKWebView *webView = [[WKWebView alloc]initWithFrame:self.view.bounds configuration:config];
webView.navigationDelegate = self;
[self.view addSubview:webView];
NSURL *url = [NSURL URLWithString:self.strURL];
[self loadWebViewWithURL:url]; // JS調(diào)用OC 添加處理腳本
[self.webView.configuration.userContentController addScriptMessageHandler:self name:@"Share"];
}
2.JS調(diào)用OC代碼解滓。
[self.webView.configuration.userContentController addScriptMessageHandler:self name:@"Share"];
這是利用WKWebView的一個(gè)新特性MessageHandler來(lái)處理JS調(diào)用原生方法赃磨。要實(shí)現(xiàn)JS調(diào)用iOS原生方法,步驟見下洼裤。
- 添加<WKScriptMessageHandler>協(xié)議邻辉。讓控制器成為MessageHandler的代理對(duì)象。
- 對(duì)于監(jiān)聽的方法名要和JS開發(fā)的人商量好腮鞍。這里我們監(jiān)聽的是Share方法值骇,對(duì)于JS開發(fā)的人員必須要以以下方式寫。
window.webkit.messageHandlers. Share.postMessage(null)
- 實(shí)現(xiàn)協(xié)議方法移国。在這個(gè)方法里message參數(shù)有一個(gè)屬性body吱瘩。message.body就是JS傳過(guò)來(lái)的參數(shù),可以是字符串迹缀,可以是數(shù)組使碾,也可以是字典蜜徽。通過(guò)message.name判斷可以知道監(jiān)聽的是JS的哪個(gè)方法。
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
if ([message.name isEqualToString:@"Share"]) {
//TODO
}
}
至此票摇,JS調(diào)用OC代碼就已完結(jié)拘鞋。是不是很簡(jiǎn)單。另外兄朋,我在網(wǎng)上也看到了不一樣的處理方式掐禁。大家可以參考WebViewJavascriptBridge我覺得寫的比較清楚。本人還沒有嘗試過(guò)這種颅和,如果都嘗試過(guò)的寶寶能不能分享一下兩者的優(yōu)缺點(diǎn)啊傅事。
3. OC調(diào)用JS代碼。
[self.webView evaluateJavaScript:@"show()" completionHandler:^(id _Nullable response, NSError * _Nullable error) {
//TODO
}];
相信代碼已經(jīng)看得很清楚啦峡扩。show()就是JS寫的方法蹭越,這個(gè)方法可傳可不傳參數(shù),具體依實(shí)際情況而定教届。另外關(guān)于UIWebView和JS的交互,以下部分僅供參考响鹃。
JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
context[@"Share"] = ^() {
NSArray *args = [JSContext currentArguments];
dispatch_async(dispatch_get_main_queue(), ^{
//TODO
});
4. 關(guān)于<WKNavigationDelegate>
網(wǎng)頁(yè)加載開始,結(jié)束案训,失敗這幾個(gè)都特別簡(jiǎn)單买置,我就不贅述了。說(shuō)一下下面這個(gè)協(xié)議方法强霎,這個(gè)方法發(fā)生在頁(yè)面跳轉(zhuǎn)中忿项。WKNavigationActionPolicy是一個(gè)枚舉,WKNavigationActionPolicyAllow表示允許跳轉(zhuǎn)城舞,WKNavigationActionPolicyCancel表示取消跳轉(zhuǎn)轩触。對(duì)了,這里還有一個(gè)補(bǔ)充: scrollView嵌套網(wǎng)頁(yè)和原生view家夺,原生view要根據(jù)網(wǎng)頁(yè)的高度來(lái)布局脱柱。我看到不少的電商應(yīng)用都有這種布局,但在算高度上會(huì)有各種問(wèn)題拉馋,不知道你們有遇見過(guò)榨为?
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
NSString *url = navigationAction.request.URL.absoluteString;
if(![url isEqualToString:self.strURL]) {
// 頁(yè)面跳轉(zhuǎn)
}
decisionHandler(WKNavigationActionPolicyAllow);
}
5. 關(guān)于< WKUIDelegate >
不知道您有沒有遇見過(guò)JS寫的alert()框在iOS上不彈出。那么您有沒有實(shí)現(xiàn)這些協(xié)議方法呢煌茴。
/// 創(chuàng)建一個(gè)新的WebView
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures;
/// 輸入框
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler;
/// 確認(rèn)框
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;
/// 警告框
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;
6. 獲取網(wǎng)頁(yè)標(biāo)題随闺,網(wǎng)頁(yè)加載進(jìn)度和加載狀態(tài)
這是通過(guò)KVO的方式進(jìn)行監(jiān)聽的。您可以點(diǎn)擊進(jìn)WKWebView的內(nèi)部看一下景馁,他們每個(gè)屬性上面都有很長(zhǎng)的解釋,你不難發(fā)現(xiàn)這一段逗鸣。舉一個(gè)獲取標(biāo)題的例子合住。其他的類似绰精。別忘了,KVO監(jiān)聽在dealloc中移除監(jiān)聽者哦透葛。
[self.webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:NULL];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
if ([keyPath isEqualToString:@"title"]) {
if (object == self.webView) {
if(self.navigationController)
self.navigationItem.title = self.webView.title;
}
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
以上就是我個(gè)人對(duì)WKWebView的一些理解笨使。demo就不奉上了,這個(gè)要服務(wù)端配合僚害。因?yàn)槲覍懙腍5基本見不了人硫椰,哈哈,我會(huì)努力的萨蚕!