iOS常用方法——WKWebView與h5互動的實現
阿新 • • 發佈:2019-01-04
隨著前端開發的強大,原生與h5的互動用的也越來越多。
為什麼選用WKWebView,我們可以做一個對比,同一個web頁面,用UIWebView載入和用WKWebView來載入,記憶體佔用情況很容易看出來,回到原生頁面之後,UIWebView對應的記憶體也不會降下來。從效能而言,個人覺得能用WKWebView就不要用UIWebView。
UIWebView與h5的互動方式和WKWebView與h5的互動方式不太一樣,對h5那邊的實現方式要求也不一樣。下面給一個WKWebView與h5實現互動的主要程式碼。
- 需要的成員變數的初始化:
//初始化webView
-(WKWebView *)webView{
if (!_webView) {
_webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT - self.mNavigationbarHeight) configuration:self.configuration];
_webView.navigationDelegate = self;
_webView.UIDelegate = self;
}
return _webView;
}
//初始化配置
-(WKWebViewConfiguration *)configuration{
if (!_configuration) {
_configuration = [[WKWebViewConfiguration alloc] init];
WKPreferences *preferences = [WKPreferences new];
preferences.javaScriptCanOpenWindowsAutomatically = YES;
_configuration.preferences = preferences;
_configuration.userContentController = self .userContentController;
}
return _configuration;
}
-(WKUserContentController *)userContentController{
if (!_userContentController) {
_userContentController = [[WKUserContentController alloc] init];
//互動關鍵程式碼
[_userContentController addScriptMessageHandler:self name:@"webViewApp"];
}
return _userContentController;
}
- WKWebView相關代理及互動的實現
#pragma mark - WKUIDelegate
// 在JS端呼叫alert函式時,會觸發此代理方法。
// JS端呼叫alert時所傳的資料可以通過message拿到
// 在原生得到結果後,需要回調JS,是通過completionHandler回撥
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
NSLog(@"%s", __FUNCTION__);
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:message preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler();
}]];
[self presentViewController:alert animated:YES completion:NULL];
NSLog(@"%@", message);
}
// JS端呼叫confirm函式時,會觸發此方法
// 通過message可以拿到JS端所傳的資料
// 在iOS端顯示原生alert得到YES/NO後
// 通過completionHandler回撥給JS端
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {
NSLog(@"%s", __FUNCTION__);
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:message preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler(YES);
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
completionHandler(NO);
}]];
[self presentViewController:alert animated:YES completion:NULL];
NSLog(@"%@", message);
}
// JS端呼叫prompt函式時,會觸發此方法
// 要求輸入一段文字
// 在原生輸入得到文字內容後,通過completionHandler回撥給JS
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler {
NSLog(@"%s", __FUNCTION__);
NSLog(@"%@", prompt);
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"請輸入" message:@"JS呼叫輸入框" preferredStyle:UIAlertControllerStyleAlert];
[alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.textColor = [UIColor redColor];
}];
[alert addAction:[UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler([[alert.textFields lastObject] text]);
}]];
[self presentViewController:alert animated:YES completion:NULL];
}
#pragma mark - WKNavigationDelegate
-(void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
//頁面開始載入
}
-(void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{
//內容開始到達時
}
-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
//頁面載入完成
}
-(void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error{
//頁面載入失敗
}
-(void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation{
//收到伺服器重定向請求後呼叫
}
-(void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
// 在請求開始載入之前呼叫,決定是否跳轉
decisionHandler(WKNavigationActionPolicyAllow);
}
-(void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
// 在收到響應開始載入後,決定是否跳轉
decisionHandler(WKNavigationResponsePolicyAllow);
}
#pragma mark - WKScriptMessageHandler
//實現互動的代理
-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
//message.body為h5向原生互動時所傳的引數,這個為客戶端與h5端協商,端需要什麼就讓h5端給什麼
NSDictionary * messageDic = message.body;
//以下為協商後處理的一個例項,根據方法名判斷原生需要做什麼處理
if ([messageDic[@"method"] isEqualToString:@"h5share"]) {
//調起原生分享頁面
[BZJSInteractiveManager h5shareInteractive:messageDic];
}else if ([messageDic[@"method"] isEqualToString:@"mall_wxpay"]){
//微信支付
[BZJSInteractiveManager h5WeiXinPayInteractive:messageDic[@"result"][@"payuri"]];
}else if ([messageDic[@"method"] isEqualToString:@"h5tologin"]){
//token失效
[BZJSInteractiveManager h5ToLogin];
}
}
需要注意的一點是WKUIDelegate需要按上面的程式碼處理,否則h5中的一些彈框無法彈出。
如果專案中用到的web比較多,可以寫一個基類,基類中基本可以實現大部分功能,互動的處理也可以在基類中統一分發處理,這樣的話互動不必在意是哪個介面,只要確定互動方法,在任何頁面有互動都可以實現。
h5實現互動程式碼示例:
- 按鈕:
<p align="center"> <input type="button" value="測試WKWebView中..." onClick="functest1()"></p>
- 點選方法:
function functest1(){
var message = {
'method' : 'hello',
'param1' : 'liuyanwei',
};
//這句為關鍵程式碼,沒有這句,客戶端無法再代理方法中獲取到該點選事件
window.webkit.messageHandlers.webViewApp.postMessage(message);
}