js交互

iOS WKWebView的用法介绍,Native(OC)与JS

2017-08-11  本文已影响87人  90de46ea2b08

在开发过程中,iOS 中实现加载 web 页面主要有两种控件,UIWebView 和 WKWebview,两种控件对应具体的实现方法不同。WKWebView是苹果公司在iOS8系统推出的,这里主要概述WebKit中更新的WKWebView控件的新特性与使用方法,以及小编在开发过程中踩的坑

一、WKWebView新特性

1.在性能、稳定性、功能方面有很大提升(最直观的体现就是加载网页是占用的内存,模拟器加载百度与开源中国网站时,WKWebView占用23M,而UIWebView占用85M);
2.允许JavaScript的Nitro库加载并使用(UIWebView中限制);
3.支持了更多的HTML5特性;
4.高达60fps的滚动刷新率以及内置手势;
5.将UIWebViewDelegate与UIWebView重构成了14类与3个协议。
6.KVO监听页面加载进度,添加进度条。

二、创建WKWebView并加载url

先引入头文件
#import <WebKit/WebKit.h>
然后创建webview

//配置
WKWebViewConfiguration * config = [[WKWebViewConfiguration alloc] init];
WKUserContentController *userContentController = [[WKUserContentController alloc] init];//js与h5交互的类

[userContentController addScriptMessageHandler:self name:@"Share"];//添加ScriptMessageHandler
config.userContentController = userContentController;

WKPreferences *preferences = [WKPreferences new];
preferences.javaScriptCanOpenWindowsAutomatically = YES;//允许js交互
preferences.minimumFontSize = 40.0;
config.preferences = preferences;

//创建
_webView = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, Screen_Height - 64) configuration:config];
_webView.navigationDelegate = self;
_webView.UIDelegate = self;
//添加此属性可触发侧滑返回上一网页与下一网页操作
_webView.allowsBackForwardNavigationGestures = YES;
//KVO监听页面加载进度
[_webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:NULL];
NSURL *url = [NSURL URLWithString:[_webUrlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]];
[_webView loadRequest:[[NSURLRequest alloc] initWithURL:url]];

KVO监听网页加载进度设置进度条(_loadingProgressView进度条创建就不赘述了哈)

//kvo监听
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"estimatedProgress"]) {//进度条
        _loadingProgressView.progress = [change[@"new"] floatValue];
        if (_loadingProgressView.progress == 1.0) {
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.4f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                _loadingProgressView.hidden = YES;
            });
        }
    }
}
@interface WeakScriptMessageDelegate : NSObject<WKScriptMessageHandler>

@property (nonatomic, assign) id<WKScriptMessageHandler> scriptDelegate;

- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate;

@end

@implementation WeakScriptMessageDelegate

- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate
{
    self = [super init];
    if (self) {
        _scriptDelegate = scriptDelegate;
    }
    return self;
}

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    [self.scriptDelegate userContentController:userContentController didReceiveScriptMessage:message];
}

@end
WKUserContentController *userContentController = [[WKUserContentController alloc] init];    
[userContentController addScriptMessageHandler:[[WeakScriptMessageDelegate alloc] initWithDelegate:self] name:@"对象名"];
- (void)dealloc {
    ...
    [[_webView configuration].userContentController removeScriptMessageHandlerForName:@"对象名"];
    ...
}

2. 需要加载的url最好做一次encoding编码处理,开发过程中url包含中文出现过请求发不出去的情况
3. WKWebView中增加了WKWebViewConfiguration,WKUserContentController,用来配置页面属性,JS相关的一些东西

三、WKWebView的代理方法

1. WKNavigationDelegate

追踪加载过程的代理方法(页面开始加载、服务开始响应返回数据时、加载完成、加载失败)

// 2⃣️页面开始加载时调用
-(void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation;

// 4⃣️当内容开始返回时调用
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation;

// 5⃣️页面加载完成之后调用
-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;

// 页面加载失败时调用
 -(void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation;

页面跳转的代理方法有三种,分为(收到跳转与决定是否跳转两种):

//接收到服务器跳转请求之后调用 (服务器端redirect),不一定调用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation;
 // 3⃣️在收到响应后,决定是否跳转
 -(void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;

// 1⃣️在发送请求之前,决定是否跳转
-(void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;

以上代理的方法执行的顺序:1⃣️->2⃣️->3⃣️->4⃣️->5⃣️

2. WKUIDelegate

WKUIDelegate主要是做跟网页交互的,可以显示javascript的一些alert或者Action,看起来跟自己做的一样的。不过这几个代理方法小编开发中没用到过哈,所以不知道有没有坑。

//1.创建一个新的WebVeiw
- (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures;
//2.WebVeiw关闭(9.0中的新方法)
- (void)webViewDidClose:(WKWebView *)webView NS_AVAILABLE(10_11, 9_0);
//3.显示一个JS的Alert(与JS交互)
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;
//4.弹出一个输入框(与JS交互的)
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler;
//5.显示一个确认框(JS的)
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;
3. WKScriptMessageHandler(负责处理js和oc交互)

先贴上HTML掉用JS代码

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf8">
        <script language="javascript">

        //JS执行window.webkit.messageHandlers.Share.postMessage(<messageBody>)
        function shareClick() {
            window.webkit.messageHandlers.Share.postMessage({title:'测试分享的标题',content:'测试分享的内容',url:'https://github.com/maying1992'});
        }

        //分享回调结果显示
        function shareResult(channel_id,share_channel,share_url) {
            var content = channel_id+","+share_channel+","+share_url;
            alert(content);
            document.getElementById("returnValue").value = content;
        }
            </script>
        </head>

<body>
    <h1>这是按钮调用</h1>
    <input type="button" value="分享" onclick="shareClick()" />
    <h1>回调展示区</h1>
    <textarea id ="returnValue" type="value" rows="5" cols="40">
    </textarea>
</body>
</html>

首先客户端通过- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;
添加了ScriptMessageHandler。例如:[config.userContentController addScriptMessageHandler:self name:@"Share"];

然后在HTML中JS 执行window.webkit.messageHandlers.<name>.postMessage(<messageBody>)时,OC端被添加的ScriptMessageHandler就会执行实现的WKScriptMessageHandler协议的方法 即

-(void)userContentController:(WKUserContentController*)userContentController didReceiveScriptMessage:(WKScriptMessage*)message
{
    //JS调用OC方法
    //message.boby就是JS里传过来的参数
    if ([message.name isEqualToString:@"Share"]) {
        NSLog(@"body:%@",message.body);
    }
    //OC调用JS,回传结果
    NSString *JSResult = [NSString stringWithFormat:@"shareResult('%@','%@','%@')",title,content,url];
    [_webView evaluateJavaScript:JSResult completionHandler:^(id _Nullable result, NSError * _Nullable error) {
    NSLog(@"%@", error);
}];
}

总结:

简单介绍了WKWebView的创建、加载、属性配置以及JS和
OC交互的一些使用心得,包括已经踩过的坑,后续后继续补充,如有描述不当或者错误的地方,在评论区给我指出来,小编马不停蹄的更正哈

上一篇下一篇

猜你喜欢

热点阅读