对于以前的iOS 8测试版,加载一个本地网络应用程序(在Bundle中),它适用于UIWebView
和WKWebView
,我甚至使用新的{{1}移植了一个网页游戏API。
WKWebView
但是在测试版4中,我只有一个空白的白色屏幕(var url = NSURL(fileURLWithPath:NSBundle.mainBundle().pathForResource("car", ofType:"html"))
webView = WKWebView(frame:view.frame)
webView!.loadRequest(NSURLRequest(URL:url))
view.addSubview(webView)
仍在工作),看起来没有任何内容被加载或执行。我在日志中看到一个错误:
无法为UIWebView
有什么帮助引导我走向正确的方向吗?谢谢!
答案 0 :(得分:97)
他们终于解决了这个错误!现在我们可以使用-[WKWebView loadFileURL:allowingReadAccessToURL:]
。
显然,修复在WWDC 2015 video 504 Introducing Safari View Controller
正如Dan Fabulish's answer所述,这是WKWebView 的一个错误,显然很快就没有解决,正如他所说的有一个解决办法:)
我的回答只是因为我想在这里展示解决方法。 https://github.com/shazron/WKWebViewFIleUrlTest中显示的IMO代码充满了大多数人可能不感兴趣的无关细节。
解决方法是包含20行代码,包含错误处理和注释,不需要服务器:)
func fileURLForBuggyWKWebView8(fileURL: URL) throws -> URL {
// Some safety checks
if !fileURL.isFileURL {
throw NSError(
domain: "BuggyWKWebViewDomain",
code: 1001,
userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("URL must be a file URL.", comment:"")])
}
try! fileURL.checkResourceIsReachable()
// Create "/temp/www" directory
let fm = FileManager.default
let tmpDirURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("www")
try! fm.createDirectory(at: tmpDirURL, withIntermediateDirectories: true, attributes: nil)
// Now copy given file to the temp directory
let dstURL = tmpDirURL.appendingPathComponent(fileURL.lastPathComponent)
let _ = try? fm.removeItem(at: dstURL)
try! fm.copyItem(at: fileURL, to: dstURL)
// Files in "/temp/www" load flawlesly :)
return dstURL
}
可以用作:
override func viewDidLoad() {
super.viewDidLoad()
var fileURL = URL(fileURLWithPath: Bundle.main.path(forResource:"file", ofType: "pdf")!)
if #available(iOS 9.0, *) {
// iOS9 and above. One year later things are OK.
webView.loadFileURL(fileURL, allowingReadAccessTo: fileURL)
} else {
// iOS8. Things can (sometimes) be workaround-ed
// Brave people can do just this
// fileURL = try! pathForBuggyWKWebView8(fileURL: fileURL)
// webView.load(URLRequest(url: fileURL))
do {
fileURL = try fileURLForBuggyWKWebView8(fileURL: fileURL)
webView.load(URLRequest(url: fileURL))
} catch let error as NSError {
print("Error: " + error.debugDescription)
}
}
}
答案 1 :(得分:81)
WKWebView无法通过loadRequest:
方法从文件:网址加载内容。 http://www.openradar.me/18039024
您可以通过loadHTMLString:
加载内容,但如果您的baseURL是文件:网址,那么它仍然无法正常工作。
iOS 9有一个新的API可以满足您的需求, [WKWebView loadFileURL:allowingReadAccessToURL:]
。
iOS 8有一种解决方法,由shazron在Objective-C https://github.com/shazron/WKWebViewFIleUrlTest到copy files into /tmp/www
and load them from there进行了演示。
如果你在Swift工作,你可以try nachos4d's sample代替。 (它也比shazron的样本短得多,所以如果你在使用shazron的代码时遇到麻烦,那就试试吧。)
答案 2 :(得分:8)
如何在 iOS 9 上使用[WKWebView loadFileURL:allowsReadAccessToURL:]。
将Web文件夹移动到项目时,选择“创建文件夹引用”
然后使用类似这样的代码(Swift 2):
if let filePath = NSBundle.mainBundle().resourcePath?.stringByAppendingString("/WebApp/index.html"){
let url = NSURL(fileURLWithPath: filePath)
if let webAppPath = NSBundle.mainBundle().resourcePath?.stringByAppendingString("/WebApp") {
let webAppUrl = NSURL(fileURLWithPath: webAppPath, isDirectory: true)
webView.loadFileURL(url, allowingReadAccessToURL: webAppUrl)
}
}
在html文件中使用像这样的文件路径
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
不喜欢这个
<link href="/bootstrap/css/bootstrap.min.css" rel="stylesheet">
移动到xcode项目的目录示例。
答案 3 :(得分:5)
临时解决方法:我按照GuidoMB的建议使用GCDWebServer。
我首先找到捆绑的路径&#34; www /&#34;文件夹(包含&#34; index.html&#34;):
NSString *docRoot = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html" inDirectory:@"www"].stringByDeletingLastPathComponent;
...然后启动它:
_webServer = [[GCDWebServer alloc] init];
[_webServer addGETHandlerForBasePath:@"/" directoryPath:docRoot indexFilename:@"index.html" cacheAge:3600 allowRangeRequests:YES];
[_webServer startWithPort:port bonjourName:nil];
要阻止它:
[_webServer stop];
_webServer = nil;
性能似乎很好,即使在iPad 2上也是如此。
我确实注意到应用进入后台后发生了崩溃,所以我在applicationDidEnterBackground:
和applicationWillTerminate:
停止了;我在application:didFinishLaunching...
和applicationWillEnterForeground:
上启动/重新启动它。
答案 4 :(得分:4)
除了Dan Fabulich提到的解决方案之外,XWebView是另一种解决方法。 [WKWebView loadFileURL:allowsReadAccessToURL:] 为implemented through extension。
答案 5 :(得分:4)
[configuration.preferences setValue:@"TRUE" forKey:@"allowFileAccessFromFileURLs"];
这解决了我的问题 iOS 8.0+ dev.apple.com
这似乎也很好......
NSString* FILE_PATH = [[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent:@"htmlapp/FILE"];
[self.webView
loadFileURL: [NSURL fileURLWithPath:productURL]
allowingReadAccessToURL: [NSURL fileURLWithPath:FILE_PATH]
];
答案 6 :(得分:3)
我还不能发表评论,所以我将其作为一个单独的答案发布。
这是nacho4d's solution的Objective-c版本。到目前为止我见过的最好的解决方法。
- (NSString *)pathForWKWebViewSandboxBugWithOriginalPath:(NSString *)filePath
{
NSFileManager *manager = [NSFileManager defaultManager];
NSString *tempPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"www"];
NSError *error = nil;
if (![manager createDirectoryAtPath:tempPath withIntermediateDirectories:YES attributes:nil error:&error]) {
NSLog(@"Could not create www directory. Error: %@", error);
return nil;
}
NSString *destPath = [tempPath stringByAppendingPathComponent:filePath.lastPathComponent];
if (![manager fileExistsAtPath:destPath]) {
if (![manager copyItemAtPath:filePath toPath:destPath error:&error]) {
NSLog(@"Couldn't copy file to /tmp/www. Error: %@", error);
return nil;
}
}
return destPath;
}
答案 7 :(得分:2)
如果您尝试在较大的HTML字符串中显示本地图像,例如:<img src="file://...">
,它仍然不会出现在设备上,因此我将图像文件加载到NSData中并且能够通过用数据本身替换src字符串来显示它。示例代码,以帮助构建要加载到WKWebView的HTML字符串,其结果将替换src =“”引号内的内容:
<强>夫特:强>
let pathURL = NSURL.fileURLWithPath(attachmentFilePath)
guard let path = pathURL.path else {
return // throw error
}
guard let data = NSFileManager.defaultManager().contentsAtPath(path) else {
return // throw error
}
let image = UIImage.init(data: data)
let base64String = data.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
result += "data:image/" + attachmentType + "base64," + base64String
var widthHeightString = "\""
if let image = image {
widthHeightString += " width=\"\(image.size.width)\" height=\"\(image.size.height)\""
}
result += widthHeightString
<强>目标-C:强>
NSURL *pathURL = [NSURL fileURLWithPath:attachmentFilePath];
NSString *path = [pathURL path];
NSData *data = [[NSFileManager defaultManager] contentsAtPath:path];
UIImage *image = [UIImage imageWithData:data];
NSString *base64String = [data base64EncodedStringWithOptions:0];
[result appendString:@"data:image/"];
[result appendString:attachmentType]; // jpg, gif etc.
[result appendString:@";base64,"];
[result appendString:base64String];
NSString *widthHeightString = @"\"";
if (image) {
widthHeightString = [NSString stringWithFormat:@"\" width=\"%f\" height=\"%f\"", image.size.width, image.size.height];
}
[result appendString:widthHeightString];
答案 8 :(得分:1)
我使用以下内容。有一些额外的东西我正在处理,但你可以看到我已经注释掉了loadRequest并取代了loadHTMLString调用。希望这有助于修复错误。
import UIKit
import WebKit
class ViewController: UIViewController, WKScriptMessageHandler {
var theWebView: WKWebView?
override func viewDidLoad() {
super.viewDidLoad()
var path = NSBundle.mainBundle().pathForResource("index", ofType: "html", inDirectory:"www" )
var url = NSURL(fileURLWithPath:path)
var request = NSURLRequest(URL:url)
var theConfiguration = WKWebViewConfiguration()
theConfiguration.userContentController.addScriptMessageHandler(self, name: "interOp")
theWebView = WKWebView(frame:self.view.frame, configuration: theConfiguration)
let text2 = String.stringWithContentsOfFile(path, encoding: NSUTF8StringEncoding, error: nil)
theWebView!.loadHTMLString(text2, baseURL: nil)
//theWebView!.loadRequest(request)
self.view.addSubview(theWebView)
}
func appWillEnterForeground() {
}
func appDidEnterBackground() {
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func userContentController(userContentController: WKUserContentController!, didReceiveScriptMessage message: WKScriptMessage!){
println("got message: \(message.body)")
}
}
答案 9 :(得分:1)
对于谁必须在iOS8下解决此问题:
如果您的页面不复杂,您可以选择将该页面设为单页应用程序。
换句话说,将所有资源嵌入到html文件中。
要做: 1.将js / css文件的内容分别复制到html文件中的/ tags中; 2.将您的图像文件转换为svg以相应地替换。 3.像以前一样使用[webView loadHTMLString:baseURL:]加载页面,例如
与svg图像的样式有点不同,但它不应该阻止你这么多。
似乎页面渲染性能有所下降,但是在iOS8 / 9/10下有这么简单的解决方法是值得的。
答案 10 :(得分:0)
在GCDWebServer的同一行中,我使用SImpleHttpServer(http://www.andyjamesdavies.com/blog/javascript/simple-http-server-on-mac-os-x-in-seconds),然后使用localhost url加载LoadRequest。使用这种方法,您不必添加任何库,但网站文件不会在捆绑中,因此无法交付。因此,这对于Debug案例更合适。
答案 11 :(得分:0)
我已经设法在OS X上使用PHP的Web服务器。复制到临时/ www目录对我来说不起作用。 Python SimpleHTTPServer抱怨想要读取MIME类型,可能是沙盒问题。
这是使用php -S
的服务器:
let portNumber = 8080
let task = NSTask()
task.launchPath = "/usr/bin/php"
task.arguments = ["-S", "localhost:\(portNumber)", "-t", directoryURL.path!]
// Hide the output from the PHP server
task.standardOutput = NSPipe()
task.standardError = NSPipe()
task.launch()
答案 12 :(得分:0)
@ nacho4d解决方案很好。我想稍微改变它但我不知道如何在你的帖子中改变它。所以我把它放在这里我希望你不要介意。感谢。
如果你有一个www文件夹,还有许多其他文件,如png,css,js等。然后你必须将所有文件复制到tmp / www文件夹。 例如,你有一个像这样的www文件夹:
然后在Swift 2.0中:
override func viewDidLoad() {
super.viewDidLoad()
let path = NSBundle.mainBundle().resourcePath! + "/www";
var fileURL = NSURL(fileURLWithPath: path)
if #available(iOS 9.0, *) {
let path = NSBundle.mainBundle().pathForResource("index", ofType: "html", inDirectory: "www")
let url = NSURL(fileURLWithPath: path!)
self.webView!.loadRequest(NSURLRequest(URL: url))
} else {
do {
fileURL = try fileURLForBuggyWKWebView8(fileURL)
let url = NSURL(fileURLWithPath: fileURL.path! + "/index.html")
self.webView!.loadRequest( NSURLRequest(URL: url))
} catch let error as NSError {
print("Error: \(error.debugDescription)")
}
}
}
函数fileURLForBuggyWKWebView8是从@ nacho4d复制的:
func fileURLForBuggyWKWebView8(fileURL: NSURL) throws -> NSURL {
// Some safety checks
var error:NSError? = nil;
if (!fileURL.fileURL || !fileURL.checkResourceIsReachableAndReturnError(&error)) {
throw error ?? NSError(
domain: "BuggyWKWebViewDomain",
code: 1001,
userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("URL must be a file URL.", comment:"")])
}
// Create "/temp/www" directory
let fm = NSFileManager.defaultManager()
let tmpDirURL = NSURL.fileURLWithPath(NSTemporaryDirectory())
try! fm.createDirectoryAtURL(tmpDirURL, withIntermediateDirectories: true, attributes: nil)
// Now copy given file to the temp directory
let dstURL = tmpDirURL.URLByAppendingPathComponent(fileURL.lastPathComponent!)
let _ = try? fm.removeItemAtURL(dstURL)
try! fm.copyItemAtURL(fileURL, toURL: dstURL)
// Files in "/temp/www" load flawlesly :)
return dstURL
}
答案 13 :(得分:-1)
尝试使用
[webView loadHTMLString:htmlFileContent baseURL:baseURL];
似乎它仍然有效。然而。