HybridiOS开发技巧H5学习之路

wkwebview交互的简单的使用

2017-01-16  本文已影响1392人  qingchen91

前言:

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

WKWebView的特点:

使用及注意点

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

WKWebView的相关的代理方法

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

具体的使用的过程

创建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)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中
}];
```

上一篇下一篇

猜你喜欢

热点阅读