WKWebView使用與交互

參考:iOS 原生與 JS 交互击碗、 參考Demo地址

tips:學(xué)點(diǎn)web技術(shù)是有必要的

UIWebView已經(jīng)被蘋果爸爸拋棄了下面只說WKWebView其實(shí)方法思想差不多
demo地址

基礎(chǔ)使用

加載網(wǎng)頁

  • 導(dǎo)入
#import <WebKit/WebKit.h>
  • 懶加載
@property(nonatomic,strong)WKWebView *webView;
- (WKWebView *)webView
{
    if (!_webView) {
        WKWebView *view = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
        [self.view addSubview:view];
        _webView = view;
    }
    return _webView;
}
  • 加載本地戒良、網(wǎng)絡(luò)
//網(wǎng)絡(luò)
NSString *url = @"https://www.baidu.com";
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]];

//本地
NSString *filePath = [[NSBundle mainBundle]pathForResource:@"index" ofType:@"html"];
NSURL *baseUrl = [[NSBundle mainBundle]bundleURL];
NSString *sourceString = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
[self.webView loadHTMLString:sourceString baseURL:baseUrl];

Swift版本:

lazy var webView: WKWebView = {
    var webView = WKWebView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height))
    self.view.addSubview(webView)
    return webView
}()

let url = "https://www.baidu.com"
webView.load(URLRequest.init(url: URL.init(string: url)!))
image.png

image.png

代理

遵守代理 navigationDelegate,主要處理一些跳轉(zhuǎn)、加載處理操作
遵守代理 UIDelegate,主要處理JS腳本滴肿,確認(rèn)框,警告框等

navigationDelegate

處理 跳轉(zhuǎn)湖员、加載等
代理方法也很多 簡單講幾條

  • 身份驗(yàn)證 基本不用
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler;

公司要對接一個(gè)第三方平臺贫悄,然后就有了一個(gè)可奇葩的邏輯,用戶填寫完相關(guān)信息后娘摔,點(diǎn)擊提交窄坦,然后服務(wù)器返回一個(gè)網(wǎng)頁的源代碼……需要用WebView加載這個(gè)網(wǎng)頁。實(shí)現(xiàn)的時(shí)候發(fā)現(xiàn)凳寺,我自己寫的簡單的網(wǎng)頁源碼可以加載鸭津,但是服務(wù)器返回的就是無法加載。后來把源碼保存成文件以后肠缨,用瀏覽器打開發(fā)現(xiàn)逆趋,該網(wǎng)頁鏈接的站點(diǎn)是一個(gè)不受信任的站點(diǎn),應(yīng)該是因?yàn)榉?wù)器證書無效而不受信任晒奕。

- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler
{
    NSLog(@"didReceiveAuthenticationChallenge");
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        NSURLCredential *card = [[NSURLCredential alloc]initWithTrust:challenge.protectionSpace.serverTrust];
        completionHandler(NSURLSessionAuthChallengeUseCredential,card);
    }
}
  • decidePolicyForNavigationAction闻书、decidePolicyForNavigationResponse
    請求之前是否跳轉(zhuǎn)、請求響應(yīng)之后是否跳轉(zhuǎn)(方法會多次調(diào)用的 因?yàn)樘D(zhuǎn)就有)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction preferences:(WKWebpagePreferences *)preferences decisionHandler:(void (^)(WKNavigationActionPolicy, WKWebpagePreferences *))decisionHandler API_AVAILABLE(macos(10.15), ios(13.0));

2個(gè)方法任取其一

typedef NS_ENUM(NSInteger, WKNavigationActionPolicy) {
    WKNavigationActionPolicyCancel,
    WKNavigationActionPolicyAllow,
} API_AVAILABLE(macos(10.10), ios(8.0));

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
    NSLog(@"decidePolicyForNavigationAction");
    decisionHandler(WKNavigationActionPolicyAllow);
}
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
{
    NSLog(@"decidePolicyForNavigationResponse");
    decisionHandler(WKNavigationResponsePolicyAllow);
}

WKNavigationActionPolicyAllow:網(wǎng)頁可以正常跳轉(zhuǎn)
WKNavigationActionPolicyCancel:取消網(wǎng)頁跳轉(zhuǎn)
此方法可以用于攔截url與web交互
獲取協(xié)議脑慧、域名魄眉、完整路徑、相對路徑闷袒、端口坑律、路徑、search囊骤、參數(shù)
例子:

NSLog(@"scheme:%@",navigationAction.request.URL.scheme);
NSLog(@"host:%@",navigationAction.request.URL.host);
NSLog(@"absoluteString:%@",navigationAction.request.URL.absoluteString);
NSLog(@"relativePath:%@",navigationAction.request.URL.relativePath);
NSLog(@"port:%@",navigationAction.request.URL.port);
NSLog(@"path:%@",navigationAction.request.URL.path);
NSLog(@"pathComponents:%@",navigationAction.request.URL.pathComponents);
NSLog(@"query:%@",navigationAction.request.URL.query);
NSLog(@"decidePolicyForNavigationAction");

------ ViewController.m ------ 65 行 ------ scheme:https
------ ViewController.m ------ 66 行 ------ host:hqhhtest.hqhh520.cn
------ ViewController.m ------ 67 行 ------ absoluteString:https://hqhhtest.hqhh520.cn/h5/#/carRental?classId=9
------ ViewController.m ------ 68 行 ------ relativePath:/h5
------ ViewController.m ------ 69 行 ------ port:(null)
------ ViewController.m ------ 70 行 ------ path:/h5
------ ViewController.m ------ 71 行 ------ pathComponents:(
    "/",
    h5
)
------ ViewController.m ------ 72 行 ------ query:(null)

如果加載本地界面 不會主動(dòng)調(diào)用action晃择、response方法

  • 頁面開始加載內(nèi)容返回也物、加載完成宫屠、加載失敗*
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation
{
    NSLog(@"didStartProvisionalNavigation");
}
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation
{
    NSLog(@"didCommitNavigation");
}
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
    NSLog(@"didFinishNavigation");
}
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error
{
    NSLog(@"didFailNavigation");
}
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
{
    //當(dāng)Response響應(yīng)后 不允許則會加載失敗
    NSLog(@"didFailProvisionalNavigation");
}

UIDelegate

處理JS腳本,確認(rèn)框滑蚯,警告框等
js中加彈出框代碼哦

- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
{
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提醒" message:message preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"知道了" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        completionHandler();
    }]];
    [self presentViewController:alert animated:YES completion:nil];
}

小功能

返回激况、前進(jìn)上一個(gè)界面
if (self.webView.canGoBack) {
    [self.webView goBack];
}
if (self.webView.canGoForward) {
    [self.webView goForward];
}
獲取標(biāo)題、獲取加載進(jìn)度

記得銷毀 dealloc 移除監(jiān)聽

[_webView removeObserver:self forKeyPath:@"title"];
[_webView removeObserver:self forKeyPath:@"estimatedProgress"];
[_webView.scrollView removeObserver:self forKeyPath:@"contentSize"];
- (void)addObserver
{
    [self.webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:NULL];
    [self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:NULL];
    [self.webView.scrollView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    NSLog(@"keyPath:%@",keyPath);
    if ([keyPath isEqualToString:@"title"]) {
        self.title = self.webView.title;
    } else if ([keyPath isEqualToString:@"estimatedProgress"]) {
        NSLog(@"%f",self.webView.estimatedProgress);
    } else if ([keyPath isEqualToString:@"contentSize"]) {
        NSLog(@"%@",object);
    } else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

交互

url重定向

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
    NSLog(@"URL:%@",navigationAction.request.URL);
    decisionHandler(WKNavigationActionPolicyAllow);
}
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
{
    NSLog(@"decidePolicyForNavigationResponse");
    decisionHandler(WKNavigationResponsePolicyAllow);
}

判斷url

MessageHandler(原生)

拓展點(diǎn)configuration膘魄、userContentController

初始化設(shè)置

- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
//設(shè)置偏好設(shè)置
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc]init];
// 默認(rèn)是0 其實(shí)不建議在此設(shè)置的
config.preferences.minimumFontSize = 10;
// 是否支持javascript
config.preferences.javaScriptEnabled = YES;
//不通過用戶交互,是否可以打開窗口
config.preferences.javaScriptCanOpenWindowsAutomatically = NO;
點(diǎn)擊js原生響應(yīng)

為了測試:本地準(zhǔn)備好html文件 這里的js方法 和 三方
WebViewJavaScriptBridge寫法略有不同哦

為了測試:本地準(zhǔn)備好html文件 這里的js方法 和 三方WebViewJavaScriptBridge寫法略有不同哦
為了測試:本地準(zhǔn)備好html文件 這里的js方法 和 三方WebViewJavaScriptBridge寫法略有不同哦

window.webkit.messageHandlers.<name>.postMessage(<messageBody>)
image.png

設(shè)置userContentController 遵守代理WKScriptMessageHandler 實(shí)現(xiàn)方法

WKUserContentController *userContentController = config.userContentController;
[userContentController addScriptMessageHandler:self name:@"showMobile"];
[userContentController addScriptMessageHandler:self name:@"showName"];
[userContentController addScriptMessageHandler:self name:@"showSendMsg"];

移除

WKUserContentController *controller = self.webView.configuration.userContentController;
[controller removeScriptMessageHandlerForName:@"showMobile"];
[controller removeScriptMessageHandlerForName:@"showName"];
[controller removeScriptMessageHandlerForName:@"showSendMsg"];

代理

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    NSLog(@"%@",message.body);
    NSLog(@"%@",message.name);
}
原生驅(qū)動(dòng)js響應(yīng) evaluateJavaScript

可以編寫幾個(gè)按鈕 去觸發(fā)
js代碼


image.png
[self.webView evaluateJavaScript:@"alertMobile()" completionHandler:^(id _Nullable response, NSError * _Nullable error) {
    //JS 返回結(jié)果
    NSLog(@"%@ %@",response,error);
}];
[self.webView evaluateJavaScript:@"alertName('wpp')" completionHandler:^(id _Nullable response, NSError * _Nullable error) {
    //JS 返回結(jié)果
    NSLog(@"%@ %@",response,error);
}];
[self.webView evaluateJavaScript:@"alertSendMsg('wpp','20歲')" completionHandler:^(id _Nullable response, NSError * _Nullable error) {
    //JS 返回結(jié)果
    NSLog(@"%@ %@",response,error);
}];

WebViewJavascriptBridge(三方)

  • 單獨(dú)準(zhǔn)備html文件
  • 最好都是最新的庫 舊的或許會崩潰
  • 設(shè)置minimumFontSize是40 不然界面控件有點(diǎn)小
  • 不能單獨(dú)設(shè)置navigationDelegate代理 因?yàn)閎ridge需要設(shè)置該代理
  • 設(shè)置屬性
#import "WebViewJavascriptBridge.h"
@property(nonatomic,strong)WebViewJavascriptBridge *bridge;
self.bridge = [WebViewJavascriptBridge bridgeForWebView:self.webView];
[self.bridge setWebViewDelegate:self];
  • 設(shè)置監(jiān)聽的webView
- (void)addRegisterHandler
{
    [self.bridge registerHandler:@"scanClick" handler:^(id data, WVJBResponseCallback responseCallback) {
        NSLog(@"掃一掃 %@",data);
        responseCallback(@"回調(diào)");
    }];
    [self.bridge registerHandler:@"locationClick" handler:^(id data, WVJBResponseCallback responseCallback) {
        NSLog(@"地址 %@",data);
        responseCallback(@"回調(diào)");
    }];
    [self.bridge registerHandler:@"colorClick" handler:^(id data, WVJBResponseCallback responseCallback) {
        NSLog(@"改變顏色 %@",data);
        responseCallback(@"回調(diào)");
    }];
    [self.bridge registerHandler:@"shareClick" handler:^(id data, WVJBResponseCallback responseCallback) {
        NSLog(@"分享%@",data);
        responseCallback(@"回調(diào)");
    }];
    [self.bridge registerHandler:@"payClick" handler:^(id data, WVJBResponseCallback responseCallback) {
        NSLog(@"支付 %@",data);
        responseCallback(@"回調(diào)");
    }];
    [self.bridge registerHandler:@"shakeClick" handler:^(id data, WVJBResponseCallback responseCallback) {
        NSLog(@"搖一搖 %@",data);
        responseCallback(@"回調(diào)");
    }];
    [self.bridge registerHandler:@"goback" handler:^(id data, WVJBResponseCallback responseCallback) {
        NSLog(@"返回 %@",data);
        responseCallback(@"回調(diào)");
    }];
}
  • js互動(dòng)
[self.bridge callHandler:@"testJSFunction" data:@"一個(gè)字符串" responseCallback:^(id responseData) {
        NSLog(@"%@",responseData);
    }];

demo地址

小tip

預(yù)算view的高度

//避免高度不徒呋洌回調(diào)
@property(nonatomic,assign)CGFloat webViewHeight;
//回調(diào)高度
@property(nonatomic,copy)void (^refreshUIBlock)(void);
if ([keyPath isEqualToString:@"contentSize"]) {
    if (self.webViewHeight == self.webView.scrollView.contentSize.height) {
        return;
    }
    self.webView.height = self.webView.scrollView.contentSize.height;
    self.height = self.webView.height;
    self.webViewHeight = self.webView.height;
    !self.refreshUIBlock ?: self.refreshUIBlock ();
    self.webViewHeight = self.webView.scrollView.contentSize.height;
}

進(jìn)度條

顯示不出來添加到scrollview
[self.webView.scrollView addSubview:self.progressView];

@property(nonatomic,strong)UIProgressView *progressView;

- (UIProgressView *)progressView
{
    if (!_progressView) {
        UIProgressView *view = [[UIProgressView alloc]initWithFrame:CGRectMake(0, 0, self.width, 0)];
        [self.webView addSubview:view];
        view.progressTintColor = kThemeColor;
        //view.trackTintColor = [UIColor lightGrayColor];
        _progressView = view;
    }
    return _progressView;
}

if ([keyPath isEqualToString:@"estimatedProgress"]) {
    //NSLog(@"%f",self.webView.estimatedProgress);
    [self.progressView setProgress:self.webView.estimatedProgress animated:YES];
    self.progressView.hidden = self.webView.estimatedProgress == 1.0 ? YES : NO;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末创葡,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子绢慢,更是在濱河造成了極大的恐慌灿渴,老刑警劉巖洛波,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異骚露,居然都是意外死亡蹬挤,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進(jìn)店門棘幸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來焰扳,“玉大人,你說我怎么就攤上這事误续《趾罚” “怎么了?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵蹋嵌,是天一觀的道長育瓜。 經(jīng)常有香客問我,道長栽烂,這世上最難降的妖魔是什么躏仇? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮腺办,結(jié)果婚禮上焰手,老公的妹妹穿的比我還像新娘。我一直安慰自己菇晃,他們只是感情好册倒,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著磺送,像睡著了一般驻子。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上估灿,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天崇呵,我揣著相機(jī)與錄音,去河邊找鬼馅袁。 笑死域慷,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的汗销。 我是一名探鬼主播犹褒,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼弛针!你這毒婦竟也來了叠骑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤削茁,失蹤者是張志新(化名)和其女友劉穎宙枷,沒想到半個(gè)月后掉房,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡慰丛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年卓囚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诅病。...
    茶點(diǎn)故事閱讀 40,615評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡哪亿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出睬隶,到底是詐尸還是另有隱情锣夹,我是刑警寧澤,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布苏潜,位于F島的核電站银萍,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏恤左。R本人自食惡果不足惜贴唇,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望飞袋。 院中可真熱鬧戳气,春花似錦、人聲如沸巧鸭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纲仍。三九已至呀袱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間郑叠,已是汗流浹背夜赵。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留乡革,地道東北人寇僧。 一個(gè)月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像沸版,于是被迫代替她去往敵國和親嘁傀。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評論 2 359

推薦閱讀更多精彩內(nèi)容