swift uiwebview 加载本地html5,swift - WKWebView在iOS 8下无法加载本地文件

swift - WKWebView在iOS 8下无法加载本地文件

对于以前的iOS 8测试版,加载一个本地Web应用程序(在Bundle中)它适用于/和WKWebView,我甚至使用新的WKWebView API移植了一个网页游戏。

var url = NSURL(fileURLWithPath:NSBundle.mainBundle().pathForResource("car", ofType:"html"))

webView = WKWebView(frame:view.frame)

webView!.loadRequest(NSURLRequest(URL:url))

view.addSubview(webView)

但在测试版4中,我只是得到一个空白的白色屏幕(/仍在工作),看起来没有任何加载或执行。 我在日志中看到一个错误:

无法为/创建沙箱扩展

有没有帮助引导我走向正确的方向? 谢谢!

14个解决方案

96 votes

他们终于解决了这个错误! 现在我们可以使用-[WKWebView loadFileURL:allowingReadAccessToURL:]。显然,这个修复在WWDC 2015视频中值得花几秒钟。介绍Safari View Controller

B1WB5.png

适用于iOS8~iOS10(Swift 3)

正如Dan Fabulish的回答所说,这是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)

}

}

}

nacho4d answered 2019-07-03T19:30:55Z

80 votes

WKWebView无法通过其/tmp/www方法从文件:URL加载内容。[http://www.openradar.me/18039024]

您可以通过/tmp/www加载内容,但如果您的baseURL是文件:URL,那么它仍然无法正常工作。

iOS 9有一个新的API,可以做你想要的,/tmp/www。

iOS 8有一个解决方法,由Objective-C中的shazron在[https://github.com/shazron/WKWebViewFIleUrlTest]中演示,将文件复制到/tmp/www并从那里加载它们。

如果你在Swift工作,你可以尝试使用nachos4d的样本。 (它也比shazron的样本短得多,所以如果你在使用shazron的代码时遇到麻烦,那就试试吧。)

Dan Fabulich answered 2019-07-03T19:31:47Z

8 votes

在iOS 9上如何使用[WKWebView loadFileURL:allowsReadAccessToURL:]的示例。

将Web文件夹移动到项目时,选择"创建文件夹引用"

7JpOu.png

然后使用类似这样的代码(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文件中使用像这样的文件路径

不喜欢这个

移动到xcode项目的目录示例。

6NY7y.png

Markus T. answered 2019-07-03T19:32:40Z

5 votes

临时解决方法:我正在使用GidoWebServer,正如GuidoMB所建议的那样。

我首先找到了捆绑的路径" www /" 文件夹(包含" index.html"):

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:上启动/重启它。

EthanB answered 2019-07-03T19:33:39Z

4 votes

除了Dan Fabulich提到的解决方案,XWebView是另一种解决方法。 [WKWebView loadFileURL:allowsReadAccessToURL:]是通过扩展实现的。

soflare answered 2019-07-03T19:34:04Z

4 votes

[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]

];

nullqube answered 2019-07-03T19:34:36Z

3 votes

我还不能评论,所以我将其作为一个单独的答案发布。

这是nacho4d解决方案的客观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;

}

Faryar answered 2019-07-03T19:35:08Z

2 votes

如果您尝试在较大的HTML字符串中显示本地图像,如:,它仍然没有出现在设备上,所以我将图像文件加载到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

Objective-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];

patrickd105 answered 2019-07-03T19:35:37Z

1 votes

我使用下面的内容。 有一些额外的东西我正在处理,但你可以看到我已经注释掉了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)")

}

}

Dustin Nielson answered 2019-07-03T19:36:04Z

1 votes

对于谁必须在iOS8下解决此问题:

如果页面不复杂,您可以选择将页面设置为单页面应用程序。

换句话说,将所有资源嵌入到html文件中。

去做:1.将js / css文件的内容分别复制到html文件中的/ tags中;2.将您的图像文件转换为svg以相应地替换。3.像以前一样使用[webView loadHTMLString:baseURL:]加载页面

设计一个svg图像有点不同,但它不应该阻止你这么多。

看起来页面渲染性能有所下降,但是在iOS8 / 9/10下有这么简单的解决方法是值得的。

firebear answered 2019-07-03T19:37:03Z

0 votes

在GCDWebServer的同一行中,我使用SImpleHttpServer([http://www.andyjamesdavies.com/blog/javascript/simple-http-server-on-mac-os-x-in-seconds)]然后使用loadRequest localhost网址。 使用这种方法,您不必添加任何库,但网站文件不会在捆绑中,因此无法交付。 因此,这对于Debug案例更合适。

toupper answered 2019-07-03T19:37:29Z

0 votes

我已经设法在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()

Patrick Smith answered 2019-07-03T19:38:02Z

0 votes

@ nacho4d解决方案很好。 我想稍微改变它但我不知道如何在你的帖子中改变它。 所以我把它放在这里我希望你不要介意。 谢谢。

如果你有一个www文件夹,还有许多其他文件,如png,css,js等。然后你必须将所有文件复制到tmp / www文件夹。例如,你有一个像这样的www文件夹:

irtFT.png

然后在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)")

}

}

}

从@ nacho4d复制函数fileURLForBuggyWKWebView8:

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

}

User9527 answered 2019-07-03T19:38:48Z

-1 votes

尝试使用

[webView loadHTMLString:htmlFileContent baseURL:baseURL];

似乎它仍在工作。 然而。

Oleksii answered 2019-07-03T19:39:15Z

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值