美文网首页
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