在IOS开发中,可以通过webView/wkWebView来加载本地HTML,css,js等资源。
步骤如下:
一、将资源添加进工程本地
iOS 项目中使用前端打包过来的H5项目时,引入工程中的html js css 文件,有时会遇到引用路径出错的问题,导致html js css image文件无法加载的情况。
那么,引入H5相关文件的正确操作方式如下,这样就不会出现资源文件无法引入并不能被正常使用的情况:
1 在项目目录下创建存放Html5文件文件夹:myHTML
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 开发内容。
网友评论