iOS 记录UIWebView & WKWebView 关于JS交互、cookie、session的一些问题和方法

上周在发布版本中,因为要和web做一些交互登录、Native调用、微信支付之类的需求。这让我对JS产生了很大的兴趣,感觉很有意思。
项目中之前多数使用了WKWebView、少部分为了兼容一些第三方的网页使用了UIWebView。WK的API和我们项目封装不完善为这次发版留下了很多坑。期间查到了很多的博客和文章,有很好的但不能解决我的问题,也有人云亦云的,所以趁周末抽空记录一下。

一、Cookie、session id问题

公司这次做了一个线上运动会的活动,要求用户在app里点击web网页时获取用户登录信息,如果没有登录就回调Native的登录页面登录成功在进行报名查询之类的操作。

在我们这边处理时就涉及到一个cookie的操作,同事在debug时发现WKWeb cookie并不能带进去 在网上查资料文章发现所有的都说WK是不自带进去的 经此放弃 但经过。。。后 我发现当时用的是模拟器debug我在使用真机debug时cookie缺可以正常传入 我用了iOS8.4 和11.3的手机测试过 是可以的 很费解 如果有遇到或者研究过什么原因的同学可以一起讨论一下

获取cookie
//cookie在app内有一个储存管理器 根据base url获取cookie列表
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:[NSURL URLWithString:APIURL]];
    NSHTTPCookie *cookie = nil;
    for (NSHTTPCookie *c in cookies) {
        if ([c.domain hasSuffix:@"imxingzhe.com"] && [c.name isEqualToString:@"sessionid"]) {
            cookie = c;
            NSLog(@"saveCookies name: %@ ", c.value);
            break;
        }
    }
iOS11.0 增加了WKHTTPCookieStore 可以操作WKWeb cookie的store 亲测有效
 [_webView.configuration.websiteDataStore.httpCookieStore setCookie:cookie completionHandler:^{
            
        }];

二、WKWeb&UIWeb 设置User-Agent

/** 设置web全局UA 一般用来标识来源 方便web端来作区分 可以在app初始化时进行设置  WK同样有效*/
- (void)setUserAgent{
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        UIWebView* tempWebView = [[UIWebView alloc] initWithFrame:CGRectZero];
        NSString* userAgent = [tempWebView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
        NSString *newUserAgent ;
        
        NSString *versionString = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
        if (![userAgent containsString:@"AppName"]) {
            newUserAgent = [NSString stringWithFormat:@"%@ AppName/%@",userAgent,versionString];
        }
        NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:newUserAgent, @"UserAgent", nil];
        [[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];
    });
    
    
}

三、WKWebView JS交互

客户端监听js方法(web调客户端方法)

web端实现 调用webkit组件发送postMessage
//Web 端代码实现 toNativeLogin是方法名 客户端和web端商量协定就行 后面可以携带参数 客户端用来接收
window.webkit.messageHandlers.toNativeLogin.postMessage("参数")
iOS端WK实现 需要在初始化配置的时候addScriptMessageHandler
WKUserContentController *userContentController = [[WKUserContentController alloc] init];   
[userContentController addScriptMessageHandler:self name:@"toNativeLogin"];
// WKWebView的配置       
WKWebViewConfiguration *configuration =[[WKWebViewConfiguration alloc] init];
configuration.userContentController = userContentController;
_webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, _width, _height)
                                      configuration:configuration];
_webView.backgroundColor = [UIColor white];
_webView.UIDelegate = self;
_webView.navigationDelegate = self;
_webView.allowsBackForwardNavigationGestures = YES;
[self.view addSubview:_webView];
#pragma mark-- delegate 监测到js需要调用客户端方法
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    // 方法名
    NSString *methods = [NSString stringWithFormat:@"%@:", message.name];
    SEL selector = NSSelectorFromString(methods);
    // 调用方法
    if ([self respondsToSelector:selector]) {
        [self performSelector:selector withObject:message.body];
    } else {
        //        NSLog(@"未实行方法:%@", methods);
    }
   
}

- (void)toNativeLogin:(id)body
{
      //JS 调用客户端方法 实现 body参数
}
客户端注入JS(一般用来注入参数或者在某些特定情况下调用JS方法获取参数)

web 端实现方法 可以选择是否带参数 统一

 // 提供 pic_url 给客户端
  var picNative = 'http://static.imxingzhe.com/tuchuangupload/1524196576.jpg';
  function sendPic2Native() {
          return pic2Native;
    }
iOS端实现 可以选择是否带参数 统一
 [webView evaluateJavaScript:@"sendPicNative()" completionHandler:^(id picResurlt, NSError * _Nullable error) {
                        dispatch_async(dispatch_get_main_queue(), ^{
                            NSLog(@"从web获取需要分享的图片 %2",picResurlt);
                        });
                    }];

四、UIWebView JS交互

iOS端注入JS
//参数方法都可以向web协定传入
JSContext context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
 NSString *alertJS=@"alert('test js OC')"; //准备执行的js代码  
[context evaluateScript:alertJS];//通过oc方法调用js的alert  
iOS端获取web设定的参数 (例如分享参数) 或者web掉用客户端代码 web声明方法 客户端来实现都可以
//从webview上获取相应的JSContext。
JSContext context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
context[@"toNativeShare"] = ^(NSString *url,NSString *title,NSString *picStr) {
        dispatch_async(dispatch_get_main_queue(), ^{
           //根据协定参数自定实现
        });
    };

推荐文章:
WKWebView与JS交互内存不释放问题探究
WKWebView 与js交互实例
WKWebView与JS交互实战技巧之API介绍

你可能感兴趣的:(iOS 记录UIWebView & WKWebView 关于JS交互、cookie、session的一些问题和方法)