美文网首页热门iOS问题 连载
iOS 如何加载本地HTML,css,js资源 和 https请

iOS 如何加载本地HTML,css,js资源 和 https请

作者: 9d8c8692519b | 来源:发表于2017-10-17 15:15 被阅读42次

    在IOS开发中,可以通过webView/wkWebView来加载本地HTML,css,js等资源。

    步骤如下:

    一、将资源添加进工程本地

    iOS 项目中使用前端打包过来的H5项目时,引入工程中的html js css 文件,有时会遇到引用路径出错的问题,导致html js css image文件无法加载的情况。
    那么,引入H5相关文件的正确操作方式如下,这样就不会出现资源文件无法引入并不能被正常使用的情况:
    1 在项目目录下创建存放Html5文件文件夹:myHTML

    文件夹myHTML.jpg

    2 将 文件夹myHTML 拖放至项目中对应的位置,此处注意要选择:Create folder references for any added folders (创建实体结构)如下图:

    文件夹myHTML拖放至工程.jpg

    在这里,再提一句吧。Xcode9的话 在添加folders的时候,结束后选中文件夹,看下文件夹的target是否被Xcode 自动勾选上,我这里就是出现了未选中的问题,导致代码实现的时候,发现路径一直找不到。找了好久原因。气得不行!上图吧:

    target勾选情况.jpg

    到这里,我们的所有H5资源已经添加进入了工程。如图:

    全部资源.jpg

    二、将资源进行加载展示

    下面这段代码实现后将会对上面引入的index.html在webview展示出来。如果你的出现了问题,请按上面的步骤检查资源路径即可。

        _web = [[UIWebView alloc] initWithFrame:self.view.bounds];
        _web.backgroundColor = [UIColor whiteColor];
        _web.delegate = self;
        [_web loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"index" ofType:@"html" inDirectory:@"myHTML"]]]];
        _web.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    //    _web.scrollView.bounces = NO;
        [self.view addSubview:_web];
    

    展示出来了就ok了吗?NO,NO,NO,页面的操作,js会与服务端有网络通讯。那么当服务端支持https,但是https的自制证书不被认可的情况下控制台就会出现如下报错。

    2017-10-17 15:04:16.829664+0800 APP_H5[13075:3858625] [] nw_proxy_resolver_create_parsed_array PAC evaluation error: NSURLErrorDomain: -1004
    2017-10-17 15:04:16.953642+0800 APP_H5[13075:3858630] TIC SSL Trust Error [1:0x604000174c40]: 3:0
    2017-10-17 15:04:16.954017+0800 APP_H5[13075:3858630] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)
    2017-10-17 15:04:16.954133+0800 APP_H5[13075:3858630] Task <7431DA05-2DBC-415E-BA7C-D894B978C9DD>.<0> HTTP load failed (error code: -1202 [3:-9813])
    2017-10-17 15:04:16.954281+0800 APP_H5[13075:3858448] NSURLConnection finished with error - code -1202

    从上面的控制台打印信息,我们可以看到error code虽然很多,但是大多都是与NSURLConnection有关的,那么既然知道了是网络请求部分的原因。那就考虑下流程,定位具体的原因,再找出解决思路不就ok了吗?

    这里原因是:https的服务端自签名证书不被客户端所认可造成的。认为链接不安全中断了请求。解决方案如下:

    先看下需要的代理,定义的变量。

    @interface ViewController ()<UIWebViewDelegate,NSURLConnectionDelegate>
    {
        UIWebView *_web;
        NSURLConnection *_urlConnection;
        NSURLRequest *_request;
        BOOL _authenticated;
    }
    

    上面的了解后,实现代码就是下面这样了。如果有异同,根据不同的业务流程。做差别化处理即可。。实现代码:

    // NSURLConnection适配
    - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
    {
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
        {
            NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
        }
        else
        {
            if ([challenge previousFailureCount] == 0)
            {
                [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];
            }
            else
            {
                [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];
            }
        }
    }
    
    #pragma mark - NSURLSessionDelegate代理方法 HTTPS ---开始---
    - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
    {
        NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        __block NSURLCredential *credential = nil;
        // 判断服务器返回的证书是否是服务器信任的
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
        {
            credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            if (credential)
            {
                disposition = NSURLSessionAuthChallengeUseCredential; // 使用证书
            }
            else
            {
                disposition = NSURLSessionAuthChallengePerformDefaultHandling; // 忽略证书 默认的做法
            }
        }
        else
        {
            disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge; // 取消请求,忽略证书
        }
        if (completionHandler)// 安装证书
        {
            completionHandler(disposition, credential);
        }
    }
    
    
    #pragma mark - Webview delegate
    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
    {
        NSLog(@"Did start loading: %@ auth:%d", [[request URL] absoluteString], _authenticated);
        _authenticated = NO;
        
        // 这里在 首次加载本地request H5的时候 将不能正常请求的https  做一个证书信任方面的处理  拿https://39.108.172.22下的任意一个接口处理下信任问题即可
        _request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://39.108.172.22/nengtou/app/login?mobile=15825275552&password=123456"]];
        _urlConnection = [[NSURLConnection alloc] initWithRequest:_request delegate:self];
        [_urlConnection start];
        
        // 这里做一个  特有化处理  因为第一次加载的H5 是本地资源路径  如果是  url资源,可以注释掉
        if ([[[request URL] absoluteString] containsString:@"myHTML/index.html"])
        {
            return YES;
        }
    
        if (!_authenticated)
        {
            _authenticated = NO;
            _urlConnection = [[NSURLConnection alloc] initWithRequest:_request delegate:self];
            [_urlConnection start];
            return NO;
        }
        return YES;
    }
    
    #pragma mark - NURLConnection delegate
    - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
    {
        NSLog(@"WebController Got auth challange via NSURLConnection");
        if ([challenge previousFailureCount] == 0)
        {
            _authenticated = YES;
            NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            [challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
        } else
        {
            [[challenge sender] cancelAuthenticationChallenge:challenge];
        }
    }
    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
    {
        NSLog(@"WebController received response via NSURLConnection");
        
        // remake a webview call now that authentication has passed ok.
        _authenticated = YES;
    //    [_web loadRequest:_request];  //  如果加载的是url 而不是本地资源路径  那么注释放开即可
        
        // Cancel the URL connection otherwise we double up (webview + url connection, same url = no good!)
        [_urlConnection cancel];
    }
    
    - (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
    {
        return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
    }
    

    其他(WKWebView)

    对于WKWebView你需要实现如下代理WKWebView的UIDelegate

    // 加载 HTTPS 的链接,需要权限认证时调用  \  如果 HTTPS 是用的证书在信任列表中这不要此代理方法
    - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            if ([challenge previousFailureCount] == 0) {
                NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
                completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
            } else {
                completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
            }
        } else {
            completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
        }
    }
    
    

    大致就是以上这些内容了,看看都应该可以正确处理的。
    还有一句:
    关注我,获取更多精彩的iOS 开发内容。

    相关文章

      网友评论

        本文标题:iOS 如何加载本地HTML,css,js资源 和 https请

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