iOS與H5的互動【WKWebView】
H5因其及時響應的更新速度媲美著需求的速度和較高的趣味性受到越來越多的使用者的青睞。目前,大多數的應用中都嵌入了H5。優點非常明顯。那麼在iOS應用中如何嵌入一個H5,並且和它進行互動就成了一個勢必要掌握的技術了。本文我將結合我在專案中的一些需求整理出對應的技術點,僅供參考。
在iOS開發中,H5的嵌入可以通過UIWebView或者WKWebView。這兩個都是繼承UIView,來載入web資料的類。UIWebView是在iOS2的時候開始使用的。特點是載入速度慢,佔用記憶體多,優化艱難。WKWebView是在iOS8蘋果新推出的,載入速度快,佔用記憶體較少,是一個不錯的選擇。如果想要比較兩者的區別,您可以選擇一個網頁進行測試一下。鑑上所述,我們選擇WKWebView進行開發。好了,廢話不多說了。
2- (void)createWebView
{
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init]
// 根據需要去設定對應的屬性
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呼叫OC 新增處理指令碼
[self.webView.configuration.userContentController addScriptMessageHandler:self name:@"Share"];
}
JS呼叫OC程式碼
[self.webView.configuration.userContentController addScriptMessageHandler:self name:@"Share"];
這是利用WKWebView的一個新特性MessageHandler來處理JS呼叫原生方法。要實現JS呼叫iOS原生方法,步驟見下。
新增<WKScriptMessageHandler>協議。讓控制器成為MessageHandler的代理物件。
對於監聽的方法名要和JS開發的人商量好。這裡我們監聽的是Share方法,對於JS開發的人員必須要以以下方式寫。
window.webkit.messageHandlers. Share.postMessage(null)
實現協議方法。在這個方法裡message引數有一個屬性body。message.body就是JS傳過來的引數,可以是字串,可以是陣列,也可以是字典。通過message.name判斷可以知道監聽的是JS的哪個方法。
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
if ([message.name isEqualToString:@"Share"]) {
//TODO
}
}
至此,JS呼叫OC程式碼就已完結。是不是很簡單。另外,我在網上也看到了不一樣的處理方式。大家可以參考WebViewJavascriptBridge我覺得寫的比較清楚。本人還沒有嘗試過這種,如果都嘗試過的寶寶能不能分享一下兩者的優缺點啊。
3OC呼叫JS程式碼
[self.webView evaluateJavaScript:@"show()" completionHandler:^(id _Nullable response, NSError * _Nullable error) {
//TODO
}];
相信程式碼已經看得很清楚啦。show()就是JS寫的方法,這個方法可傳可不傳引數,具體依實際情況而定。另外關於UIWebView和JS的互動,以下部分僅供參考。
4JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
context[@"Share"] = ^() {
NSArray *args = [JSContext currentArguments];
dispatch_async(dispatch_get_main_queue(), ^{
//TODO
});
關於<WKNavigationDelegate>
網頁載入開始,結束,失敗這幾個都特別簡單,我就不贅述了。說一下下面這個協議方法,這個方法發生在頁面跳轉中。WKNavigationActionPolicy是一個列舉,WKNavigationActionPolicyAllow表示允許跳轉,WKNavigationActionPolicyCancel表示取消跳轉。對了,這裡還有一個補充: scrollView巢狀網頁和原生view,原生view要根據網頁的高度來佈局。我看到不少的電商應用都有這種佈局,但在算高度上會有各種問題,不知道你們有遇見過?
5- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
NSString *url = navigationAction.request.URL.absoluteString;
if(![url isEqualToString:self.strURL]) {
// 頁面跳轉
}
decisionHandler(WKNavigationActionPolicyAllow);
}
關於< WKUIDelegate >
不知道您有沒有遇見過JS寫的alert()框在iOS上不彈出。那麼您有沒有實現這些協議方法呢。
6/// 建立一個新的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;
/// 確認框
- (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;
獲取網頁標題,網頁載入進度和載入狀態
這是通過KVO的方式進行監聽的。您可以點選進WKWebView的內部看一下,他們每個屬性上面都有很長的解釋,你不難發現這一段。舉一個獲取標題的例子。其他的類似。別忘了,KVO監聽在dealloc中移除監聽者哦。
8E6F0A58-609E-4093-BD65-F51A10D1703D.png
[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];
}
}
以上就是我個人對WKWebView的一些理解。demo就不奉上了,這個要服務端配合。因為我寫的H5基本見不了人,哈哈,我會努力的!
↙點選“閱讀原文”,加入
『程式設計師大咖』