正如here所述,WKWebView
有一个错误,即捆绑本地网页的应用必须将捆绑包复制到tmp
目录中。我将捆绑包复制到tmp
的代码是:
// Clear tmp directory
NSArray* temporaryDirectory = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:NSTemporaryDirectory() error:NULL];
for (NSString *file in temporaryDirectory) {
[[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:@"%@%@", NSTemporaryDirectory(), file] error:NULL];
}
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"build"];
NSString *temporaryPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"build"];
NSError *error = nil;
// Copy directory
if(![fileManager copyItemAtPath:sourcePath toPath:temporaryPath error:&error]) {
[self logError:@"Could not copy directory" :error];
}
我已经计划了这个特定的代码片段,它占用了我应用启动时间的50%! (约0.5s,总共~1s。)
有没有办法可以在iOS 8下加速(或完全避免)这个特定的代码片段?线程可以帮忙吗?
答案 0 :(得分:5)
鉴于您的资产足够大,需要0.5秒才能复制,我的建议是采用稍微不同的方法来加快(明显)启动时间:
div
创建一个普通的旧HTML页面以加载资源(如果您愿意,可以在base64中包含小资源(例如加载指示符图像))webView:didFinishNavigation:
上),将副本启动到构建文件夹evaluateJavaScript:completionHandler:
)虽然我意识到这并没有直接解决这个问题,但我认为在这种情况下,方法的微小改变最好。
答案 1 :(得分:2)
注意:此技术适用于UIKit的UIWebView
和AppKit的WebView
,但不适用于新的WKWebView
,它似乎忽略了网址加载系统。见评论。
使用NSURLProtocol
处理本地文件读取,就好像它们是远程请求一样。有关完整示例,请参阅PandoraBoy中名为ResourceURLProtocol
的示例。我将在这里介绍它的略微简化版本。我们会将http://.RESOURCE./path/to/file
视为<resources>/path/to/file
。
将询问每个NSURLProtocol
是否可以处理系统中出现的每个请求。它需要在+canInitWithRequest:
中回答它是否可以。我们会说主持人是.RESOURCE.
,然后我们可以处理它。 .RESOURCE.
是一个非法的DNS名称,因此它不能与任何真正的主机冲突(但它是用于URL目的的合法主机名)。
NSString *ResourceHost = @".RESOURCE.";
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
return ( [[[request URL] scheme] isEqualToString:@"http"] &&
[[[request URL] host] isEqualToString:ResourceHost] );
}
然后我们需要一些记账方法。这里没什么可看的。
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
return request;
}
-(void)stopLoading {
return;
}
现在我们了解它。 startLoading
是您要对请求做任何事情的地方。
-(void)startLoading {
NSBundle *thisBundle = [NSBundle bundleForClass:[self class]];
NSString *notifierPath = [[thisBundle resourcePath] stringByAppendingPathComponent:[[[self request] URL] path]];
NSError *err;
NSData *data = [NSData dataWithContentsOfFile:notifierPath
options:NSUncachedRead // Assuming you only need to read this once
error:&err];
if( data != nil ) {
// Assuming you're only reading HTML.
// If you need other things, you'll need to work out the correct MIME type
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:[[self request] URL]
MIMEType:@"text/html"
expectedContentLength:[data length]
textEncodingName:nil];
// And we just pass it to the caller
[[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed];
[[self client] URLProtocol:self didLoadData:data];
[[self client] URLProtocolDidFinishLoading:self];
} else {
NSLog(@"BUG:Unable to load resource:%@:%@", notifierPath, [err description]);
[[self client] URLProtocol:self didFailWithError:err];
}
}
我还发现一个小ResourceURL
包装器有用:
@implementation ResourceURL
+ (ResourceURL*) resourceURLWithPath:(NSString *)path {
return [[[NSURL alloc] initWithScheme:@"http"
host:ResourceHost
path:path] autorelease];
}
@end
要使用它,您只需要先注册协议处理程序:
[NSURLProtocol registerClass:[ResourceURLProtocol class]];
然后你可以创建一个“资源URL”并加载它:
ResourceURL *resource = [ResourceURL resourceURLWithPath:...];
[webView loadRequest:[NSURLRequest requestWithURL:resource]];
有关NSURLProtocol
的详细信息以及更复杂的缓存示例,请参阅Drop-in Offline Caching for UIWebView (and NSURLProtocol)。
PandoraBoy充满了NSURLProtocol
个示例(查找名称中包含Protocol
的所有类)。您可以通过这种方式劫持,监视,重定向或操纵通过URL加载系统传输的任何内容。
答案 2 :(得分:1)
尝试XWebView而不复制文件。它包括一个微小的http服务器。您只需致电 [webview loadFileURL:allowingReadAccessToURL:]
答案 3 :(得分:1)
使这与0.5s的启动时间的其余部分并行肯定会有所帮助。 (只有当你在0.5s的其他启动时做的事情不依赖于正在加载的WebView或正在读取的文件时,这才有可能实现)
您将获得的最佳优化是减少&#34; build&#34;中的文件大小。目录。试试这些 -