wkwebview交互的简单的使用

前言:

web页面和app的直接的交互是很常见的东西,在ios8之前,用的是uiwebview,但是在ios8之后,苹果推出了WebKit这个框架,用来替代原有的UIWebView。以前的时候需要适配iOS7,现在扔掉了iOS7,所以在做和web页面的交互的时候,可以用wkwebview替代原有的uiwebview。

WKWebView的特点:

  • 性能高,稳定性好,占用的内存比较小,
  • 支持JS交互
  • 支持HTML5 新特性
  • 可以添加进度条。
  • 支持内建手势,
  • 据说高达60fps的刷新频率

使用及注意点

WKWebView只能用代码创建,而且自身就支持了右滑返回手势allowsBackForwardNavigationGestures和加载进度estimatedProgress等一些UIWebView不具备却非常好用的属性。在创建的时候,指定初始化方法中要求传入一个WKWebViewConfiguration对象,一般我们使用默认配置就好,但是有些地方是要根据自己的情况去做更改。比如,配置中的allowsInlineMediaPlayback这个属性,默认为NO,如果不做更改,网页中内嵌的视频就无法正常播放。

WKWebView的相关的代理方法

WKWebView的相关的代理方法分别在WKNavigationDelegate和WKUIDelegate以及WKScriptMessageHandler这个与JavaScript交互相关的代理方法。

  • WKNavigationDelegate
    该代理提供的方法,可以用来追踪加载过程(页面开始加载、加载完成、加载失败)、决定是否执行跳转。具体的使用可以看下面的代码示例
  • WKUIDelegate
    这个代理方法全都是与界面弹出提示框相关的,所以最好是实现的,否则的话,遇到网页alert的时候,如果此代理方法没有实现,则不会出现弹框提示。
  • WKScriptMessageHandler
    这个代理方法就是实现和JavaScript交互相关的。下面会介绍js调用oc,oc调用js的具体的使用。

具体的使用的过程

创建WKWebView

  • 我这里是定义了全局的变量
@interface ACViewController ()<WKNavigationDelegate,WKUIDelegate,WKScriptMessageHandler>
@property (strong, nonatomic)   WKWebView                   *wkwebView;
@property (strong, nonatomic)   UIProgressView              *progressView;//这个是加载页面的进度条
@end
@implementation ACViewController
{
    UILabel * label ;
    WKUserContentController * userContentController;
}
  • 创建
#pragma mark 初始化webview
-(void)initWKWebView
{
 WKWebViewConfiguration * configuration = [[WKWebViewConfiguration alloc]init];//先实例化配置类 以前UIWebView的属性有的放到了这里
 //注册供js调用的方法
    userContentController =[[WKUserContentController alloc]init];
//弹出登录
    [userContentController addScriptMessageHandler:self  name:@"loginVC"];
    
    //加载首页
    [userContentController addScriptMessageHandler:self name:@"gotoFirstVC"];
    
    //进入详情页
   [userContentController addScriptMessageHandler:self  name:@"gotodetailVC"];
configuration.userContentController = userContentController;
    configuration.preferences.javaScriptEnabled = YES;//打开js交互
    _wkwebView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0.0f, screen_width, screen_height) configuration:configuration];
    
    _wkwebView.backgroundColor = [UIColor clearColor];
    _wkwebView.UIDelegate = self;
    _wkwebView.navigationDelegate = self;
    _wkwebView.allowsBackForwardNavigationGestures =YES;//打开网页间的 滑动返回
    _wkwebView.allowsLinkPreview = YES;//允许预览链接
 [self initProgressView];
  [_wkwebView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];//注册observer 拿到加载进度
 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:具体的网址]];
 [_wkwebView loadRequest:request];
[self.view addSubview:_wkwebView];
}
    ```
- 关于进度条的监听

pragma mark --这个就是设置的上面的那个加载的进度

-(void)initProgressView
{
_progressView =[[UIProgressView alloc]initWithFrame:CGRectMake(0,0, screen_width, 10.0f)];
_progressView.tintColor = [UIColor blueColor];
_progressView.trackTintColor = [UIColor whiteColor];
[self.view addSubview:_progressView];
}
//这个是检测那个进度条的,显示完成之后,进度条就隐藏了
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
if([keyPath isEqualToString:@"estimatedProgress"])
{
_progressView.hidden = NO;
CGFloat progress = [ change[@"new"] floatValue];
[_progressView setProgress:progress];

    if(progress==1.0)
    {
        _progressView.hidden =YES;
    }

}
}

- 和js交互
1.js调用oc的方法

WKScriptMessage有两个关键属性name 和 body。因为我们给每一个OC方法取了一个name,所以就可以根据name 来区分执行不同的方法。body 中存着JS 要给OC 传的参数。

在这里我是在前面注册了三个供js调用的方法,loginVC,gotoFirstVC,gotodetailVC。就是name。
在这个方法里面实现的
-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{};
具体的代码如下

-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
if(message.name ==nil || [message.name isEqualToString:@""])
return;
//message body : js 传过来值
NSLog(@"message.body ==%@",message.body);
if ([message.name isEqualToString:@"loginVC"])
{
[self showLoginView];
}

else if ([message.name isEqualToString:@"gotoFirstVC"])
{
    
    [self showFirstVC];
}
//进入详情页
else if ([message.name isEqualToString:@"gotodetailVC"])
{
    

   NSString*url = [message.body objectForKey:@"body"];
    
    [self gotodetial:url];
    
}

}

接下来就是具体的调用方法的实现了。

//弹出登陆页面

  • (void)showLoginView
    {
    //具体看项目中的实现了
    }
    /**
    跳转到首页
    /
    -(void)showFirstVC{
    //具体看项目中的实现了
    }
    /
    *
    跳转到详情页
    */

-(void)gotodetial:(NSString *)url {
//具体看项目中的实现了
}

2.oc调用js的方法,给js传值
oc调用js是通过evaluateJavaScript,这个方法里面的实现的
我这里处理的时候,是在页面加载完成的时候,oc给js传值
比如我需要给js传用户的登录状态和用户的信息,只要在加载完成的时候,调用方法,直接给值就行。
代码示例

//加载页面数据完成
-(void)webView:(WKWebView )webView didFinishNavigation:(null_unspecified WKNavigation )navigation
{
[_wkwebView evaluateJavaScript:@"document.getElementById("content").offsetHeight;" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
//获取页面高度,并重置webview的frame
CGFloat documentHeight = [result doubleValue];
CGRect frame = _wkwebView.frame;
frame.size.height = documentHeight+[UIScreen mainScreen].bounds.size.height-58 /
显示不全
/;
_wkwebView.frame = frame;
}];
NSString *js = [NSString stringWithFormat:@"isLogin(%d)",[[UserInfoSingleton shareUserInfoSingleton] isLogin]];

// NSLog(@"%@",message.name);
//[self.wkwebView evaluateJavaScript:js completionHandler:nil];
[self.wkwebView evaluateJavaScript:js completionHandler:^(id item, NSError * _Nullable error) {

}];

NSString *js1 = [NSString stringWithFormat:@"userId(\'%@\')",[UserInfoSingleton shareUserInfoSingleton].userId];

// [self.wkwebView evaluateJavaScript:js1 completionHandler:nil];
[self.wkwebView evaluateJavaScript:js1 completionHandler:^(id item, NSError * _Nullable error) {

}];

}

- 弹窗
代码示例

//弹窗
-(void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:([UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler();
}])];
[self presentViewController:alertController animated:YES completion:nil];
}
-(void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{
// DLOG(@"msg = %@ frmae = %@",message,frame);
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:([UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
completionHandler(NO);
}])];
[alertController addAction:([UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler(YES);
}])];
[self presentViewController:alertController animated:YES completion:nil];
}
-(void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:prompt message:@"" preferredStyle:UIAlertControllerStyleAlert];
[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.text = defaultText;
}];
[alertController addAction:([UIAlertAction actionWithTitle:@"完成" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler(alertController.textFields[0].text?:@"");
}])];
}

- wkwebview所有的代理方法
1.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 didFailProvisionalNavigation:(WKNavigation *)navigation;

2. WKNavigtionDelegate来进行页面跳转

// 接收到服务器跳转请求之后再执行
-(void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation;
// 在收到响应后,决定是否跳转
-(void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
// 在发送请求之前,决定是否跳转
-(void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
```

  1. WKUIDelegate
//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;
    ```
以上的所有的代理方法,根据自己的使用情况调用就行。
#注意
- Objective-C在回调JavaScript的时候,WKWebView没有办法传过来一个匿名函数,所以回调方式,要么执行一段JavaScript代码,或者就是调用JavaScript那边的一个全局函数。一般是采用后者,至于Web端虽说暴露了一个全局函数,同样可以把这一点代码处理的很优雅。Objective-C传给JavaScript的参数,可以为Number, String, and Object。参考如下:

// 数字
NSString *js = [NSString stringWithFormat:@"方法名(%@)", number];
[self.webView evaluateJavaScript:js completionHandler:nil];
// 字符串
NSString *js = [NSString stringWithFormat:@"方法名('%@')", string];
[self.webView evaluateJavaScript:js completionHandler:nil];
// 对象
NSString *js = [NSString stringWithFormat:@"方法名(%@)", @{@"name" : @"timefor"}];
[self.webView evaluateJavaScript:js completionHandler:nil];
// 带返回值的JS函数
[self.webView evaluateJavaScript:@"方法名()" completionHandler:^(id result, NSError * _Nullable error) {
// 接受返回的参数,result中
}];
```

  • 我在本文中写的,都是根据自己项目中用到的写的,主要是在和h5交互的这块,互相传值,调用的,都是用的自己项目中的方法名。可能会好理解一些。
  • 关于导航栏处理的之类的,这次项目中没用用到,所以没有做深入的研究,只是研究了项目中的问题。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345

推荐阅读更多精彩内容