美文网首页
webview中遇到的一些问题

webview中遇到的一些问题

作者: 10m每秒滑行 | 来源:发表于2018-01-23 16:00 被阅读0次

    App内接入第三方活动,每次重启进入活动都需要重新登陆

    为了赶上一波活动的热潮,蹭蹭流量,app内接入了第三方的热门活动,用户在参与活动前需要先登录,用本app的token去换一个第三方账号的登陆的token,并在app内保存cookie,以保存用户的登录状态。

        // 設定 cookie
     NSURL *cookieHost=[NSURL URLWithString:self.url];
     NSDictionary *token = [NSDictionary dictionaryWithObjectsAndKeys:@"access_token", NSHTTPCookieName,
                                        [User currentUser].accessToken, NSHTTPCookieValue,
                                        @"/", NSHTTPCookiePath,
                                        [cookieHost host], NSHTTPCookieDomain,
                                        nil];
    

    但是发现活动入口因为在app内一直保存,但用户每次重新进入app后都需要重新登陆,才能开始参与活动。这样产品当然是不答应的。后来发现之所以用户需要重新登录,是因为用户之前登陆保存的cookie失效了,app杀死时将原来设置的cookie清空了。

    查了一下,发现还可以设置cookie的失效时间,即NSHTTPCookieExpires,还顺带在API里看到了NSHTTPCookieDiscard key值。说是discard cookie的标志,表示不希望被discard。

    所以加了两个字段设置

        NSDate *expiresDate = [NSDate dateWithTimeIntervalSinceNow:3600*24];//1天后才失效
        token[NSHTTPCookieExpires] = expiresDate;
        [token removeObjectForKey:NSHTTPCookieDiscard];
    

    嗯,然后就没有一直需要重新登录了。

    webview加载的url路径中带”#“号

    原来遇到一个问题是,老板分享了一个来自微信某公众号的技术帖,路径尾部有两个”##“号,分享到公司的app的 IM中,点击用webview页面打开链接,会报错,但在微信内部看是没有问题的。后来发现,如果在打开url之前,对url编码,

    [NSURL URLWithString:[self.url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]
    

    此时路径中的”井井”号被编码为 ‘%23%23’,使用编码后的url是可以正常打开的。但是带来了新的问题,如果所有url都进行编码的话,一些使用SPA(前端框架)框架下部署的页面,路径后面会带 井号,此时不可以对url编码,否则路径不识别。后来咨询H5的同事,一般的页面很少框架下会在路径中出现两个连续井号,然后测试发现如果我讲url中出现的连续井号,替换成一个井号,微信内的那个链接就能正常打开了,并且测试了以前出现的大量站外url,未发现异常。这一个看起来很不靠谱的解决方案。。。。

     //webview  URL碰到两个#号,就不认识了,将 n 个#号替换成一个#号
        NSString *regExpStr = @"#+";
        NSString *replacement = @"#";
        NSRegularExpression *regExp = [[NSRegularExpression alloc]initWithPattern:regExpStr options:NSRegularExpressionCaseInsensitive error:nil];
        url = [regExp stringByReplacingMatchesInString:url options:NSMatchingProgress range:NSMakeRange(0, url.length) withTemplate:replacement];
    

    webview error code

    webview在加载过程中会报一些奇奇怪怪得错,而出错后按照业务需求需要展示错误页面。就会有测试进场过来问,我这个页面明明可以打开,可是咱们app为什么打不开,展示错误页呀。。。。嗯,我的锅!
    调试发现webview报错了,报错种类有这么些

    1. 当同时收到两个一样的请求时,webview会自动cancle其中一个,并抛出一个 -999的errorCode
    2. 当页面内元素或插件视图加载插件时,会抛出一个204的errorCode
    3. 当url链接有不符合url规范的字符时,会抛出一个101的errorCode
    4. 当缺乏https证书,却加载https协议链接时会抛出 -1202 的errorCode
      所以以上1,2,都可忽略,只需要失败回调里忽略就好
    - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
           if ([self isSpecialCancle:error.code]) {
            return;
        }
        [self addErrorPage];
    }
    
    - (BOOL)isSpecialCancle:(NSInteger)code {
        switch (code) {
            case -999:
                return YES;
                break;
            case -1003:
                return YES;
                break;
            case 204:
                return YES;//加载插件
                break;
            default:
                return NO;
                break;
        }
    }
    

    问题3可对url编码解决。问题4,解决方案就一搜一片了,只需要自定义NSURLConnection代理,在代理中信任此次请求便可,但最好的是制作https证书,或买专业机构的https证书。

    [NSURLConnection connectionWithRequest:self.request delegate:self];
    
    - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
        }
        [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
    }
    

    webview 内js调用alert()函数,会crash

    在调试过程中发现,js如果多次调用alert()函数,在8的系统上会引起crash,打印线程快照发现 alert() 函数实现调用的是系统私有api,用的是UIAlertView的私有函数,调用线程是js的线程。初步判断是在js线程调用UI操作,引起的crash。

    因此解决方法是用原生方法覆盖js的alert函数

        JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
        
        //覆盖js的alert
        context[@"alert"] = ^(id msg){
            if ([msg isKindOfClass:[NSString class]]) {
                [UIAlertView alertViewWithTitle:(NSString*)msg message:nil cancelButtonTitle:@"确定" otherButtonTitles:nil onDismiss:^(NSInteger buttonIndex) {
                } onCancel:^{
                }];
                
            }
        };
    

    Webview注入OC对象引起内存泄漏

    在做hybrid功能时,因为要向H5暴露OC对象,并暴露协议方法,因此要向JsContext中注入OC对象代码如下:

    JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    context[JSSDK_NATIVENAME] = self;
    

    但最初hybrid没有形成规模和框架时,我们webController -> webview是强持有关系,webview -> JSContext 是系统定的强持有关系, 而此时context[JSSDK_NATIVENAME] = self 操作会让 JSContext强持有webController ,形成循环引用,导致内存泄漏。

    所以中间需要引入一个webviewHandle

    webController -> webview 强持有
    webview -> JSContext 强持有
    JSContext -> webviewHandle 强持有
    webviewHandle ——> webController(或其他Module) 弱代理关系,来解除循环引用。

    相关文章

      网友评论

          本文标题:webview中遇到的一些问题

          本文链接:https://www.haomeiwen.com/subject/bhisaxtx.html