我们APP的核心功能实现方式为:原生和JS交互。这就需要频繁的互传数据,互传数据在这里就先不说,之后写的一篇,可以看这个。WKWebView填坑之----与H5相互交互
最早用的UIWebView,交互没有WebKit方便但也还凑合,主要是太吃内存了,性能太差,而且现在最低支持iOS 8,所以决定换成WebKit,由此开始了这次的填坑之路。
我们前端显示的内容是从沙盒内加载的图片和音乐文件,用UIWebView时是我把文件的本地路径传给前端然后前端直接去访问文件的本地路径就可以了,但是换成WebKit就没办法加载出来资源文件。google了之后发现这是WebKit现在的bug,好吧,没什么好的解决方案,大部分给的都是在文件前加一个localhost,但是也没给出具体的方案实施步骤。这一看就是在本地开了一个类似Apache服务器啊,顿时感觉这思路也是可以。有了思路现在就开始干。
GitHub上有个神器:GCDWebServer,这次就用的这个
pod集成这些就不说了,直接上代码
// 官方给的示例是在AppDelegate里启动本地服务器,但是我这个并没有必要在APP启动时就启动本地服务器,所以我放在了核心功能控制器的viewDidLoad方法内
// 1.导入头文件
#import <GCDWebServer/GCDWebDAVServer.h>
// 2.定义全局属性
@property (nonatomic,strong) GCDWebServer *webSever;
// 3. 主要代码
_webSever = [[GCDWebServer alloc]init];
[_webSever addGETHandlerForBasePath:@"/" directoryPath:NSHomeDirectory() indexFilename:nil cacheAge:3600 allowRangeRequests:YES];
[_webSever startWithPort:80 bonjourName:nil];
// 好了,这就结束了!WTF,这就完了,是的,可以这么说
// 比方说文件存在Library下有一个123的文件
NSString *basePath = @"http://localhost/Library/123"; // 这样就可以访问到这个文件了,我只需要把我的文件名拼上localhost路径然后传给前端,他们拿到这个链接直接访问就可以拿到这个文件了
上面只是代码,还是来点调试过程吧!
进入到APP内的WebView页面,然后

对了,这里Safari需要把“开发”选项打开
点击链接后回打开一个网页检查器



可以看到我们已经可以访问沙盒内容了,如果在mac上开过本地Apache服务器的同学看到这个界面应该一眼就能看出来这是开了一个本地服务器。
至此,大功告成。我只需要把路径告诉前端我的工作就完成了。
忘了说了,在viewDidLoad开启的话在控制器注销时需要把本地服务器停止
// 此页面并没有右滑返回手势
- (void)goBack{
// 这也是为什么要定义全局属性的原因
[_webSever stop];
_webSever = nil;
[self.navigationController popViewControllerAnimated:YES];
}
顺便说一下,GCDWebServer我在模拟器上并不能通过IP地址或者localhost来访问。
网友评论
本地 html 存在 ajax 请求 跨域, 谁能帮帮我谢谢
我感觉使用UIWebview也会存在跨域问题 目前没有成功 能给下思路吗? 感谢
通过 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15.0f];这种方式不能访问到真机中的文件,在模拟器可行,在真机沙盒加载HTML文件必须使用你这种方式吗??
baseUrl是文件的上一级路径http:/localhost/var/mobile/Containers/Data/Application/F1BE3E05-B6BD-43B4-815C-48C9AE24F683/Library/Caches -- file:/// 不知道那块有问题,求解答
其次,我建议你先看懂代码,总共也没几行,我写的明明是在APP内的沙盒路径下开启服务器。
SDWebImageManager *imageManager = [SDWebImageManager sharedManager];
NSURL *imageUrl = [NSURL URLWithString:src];
[imageManager diskImageExistsForURL:imageUrl completion:^(BOOL isInCache) {
if (isInCache) {
NSString *cacheKey = [imageManager cacheKeyForURL:imageUrl];
NSString *imagePaths = [imageManager.imageCache defaultCachePathForKey:cacheKey];
NSString *srcStr = [NSString stringWithFormat:@"img_%zd,%@",index,imagePaths];
[self.bridge callHandler:@"testJSFunction" data:srcStr responseCallback:^(id responseData) {
}];
}else{
[imageManager loadImageWithURL:imageUrl options:SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
} completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
if (image && finished) {//如果下载成功
NSString *cacheKey = [imageManager cacheKeyForURL:imageUrl];
NSString *imagePaths = [imageManager.imageCache defaultCachePathForKey:cacheKey];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSString *srcStr = [NSString stringWithFormat:@"img_%zd,%@",index,imagePaths];
[self.bridge callHandler:@"testJSFunction" data:srcStr responseCallback:^(id responseData) {
}];
});
}
}];
}
}];
1.拷贝html这些个文件到沙盒内
2.在沙盒根目录或者library内开启GCDServer,所有访问使用localhost,包括加载HTML文件,拼接你的图片路径,把拼接好的路径丢给HTML让它根据这个路径去访问图片,这样就OK
使用下面方法加载页面:
[self.wkWebView loadFileURL:fileURL allowingReadAccessToURL:baseUrl];
注意:
fileURL,是需要加载的HTML文件路径
baseUrl,是HTML的上一级文件路径.这是坑点,baseUrl和fileURL不能相同!!!!!!
baseUrl是文件的上一级路径http:/localhost/var/mobile/Containers/Data/Application/F1BE3E05-B6BD-43B4-815C-48C9AE24F683/Library/Caches -- file:/// 不知道那块有问题,求解答
NSLog(@"+++最终的htmlString%@+++",html);
NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"ldd.html"];
[html writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];
NSLog(@"本地的html文件---%@",path);
NSURL * url1 = [NSURL fileURLWithPath:path];
[self.wkWebView loadFileURL:url1 allowingReadAccessToURL:url1];
#pragma mark -- UIWebView
UIWebView * webView = [[UIWebView alloc]initWithFrame:CGRectMake(0, self.view.bounds.size.height/2 + 20, self.view.bounds.size.width, self.view.bounds.size.height/2)];
//[webView loadHTMLString:html baseURL:url];
[webView loadRequest:[NSURLRequest requestWithURL:url1]];
[self.view addSubview:webView];
我是把一个html字符串 写入文件 在沙盒生成了一个H5的文件 这个H5的文件里的图片链接用的本地的 不是http的 新生成的H5文件如下
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Test ios native load webview's image'</title>
</head>
<body>
<h1>Test how to use ios native code to load webview's image and set the image to webview</h1>
<div>
<h2>Here has two image urls. We will try to request this two image with ios but not html</h2>
</div>
<hr style="color: red;" />
<img src="/var/mobile/Containers/Data/Application/F7721407-D958-4A2A-ACAC-1E230B12C33C/Documents/5353c07f4c2ea0471b9f3ee36dedcaac" />
<img src="/var/mobile/Containers/Data/Application/F7721407-D958-4A2A-ACAC-1E230B12C33C/Documents/54edea1f2edd444aaba9d0321d786962" />
</body>
</html>
目前这个H5用UIWebView加载可以 用WKWebView加载不可以 真机上图片出不来 模拟机上可以
我把您说的这个GCDWebServer集成到项目里了
<code>_webSever = [[GCDWebServer alloc]init];
[_webSever addGETHandlerForBasePath:@"/" directoryPath:NSHomeDirectory() indexFilename:nil cacheAge:3600 allowRangeRequests:YES];
[_webSever startWithPort:80 bonjourName:nil];
// 好了,这就结束了!WTF,这就完了,是的,可以这么说
// 比方说文件存在Library下有一个123的文件
NSString *basePath = @"http://localhost/Library/123"; // 这样就可以访问到这个文件了,我只需要把我的文件名拼上localhost路径然后传给前端,他们拿到这个链接直接访问就可以拿到这个文件了
</code>
<code>
NSLog(@"+++最终的htmlString%@+++",html);
NSString *path = [basePath stringByAppendingPathComponent:@"ldd.html"];
[html writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];
NSLog(@"本地的html文件---%@",path);
NSURL * url1 = [NSURL fileURLWithPath:path];
[self.wkWebView loadFileURL:url1 allowingReadAccessToURL:url1];
</code>
我这么写不成 我应该怎么把我这个H5的字符串和他上面的localhost联系一下 让这个路径是对的 让WK可以加载呢