一、问题描述
iOS12
系统,在同一个WKWebView
先使用( loadRequest:
方式)去加载一个在线网页(https://
)
再使用(loadFileURL:allowingReadAccessToURL:
)加载一个存在Documents目录
下的本地的静态html
页面(file://
)
此时WKWebView
将通过代理方法:
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
输出错误:
[ProcessSwapping] 0x10af34160 - ProvisionalPageProxy::didFailProvisionalLoadForFrame: pageID = 1, frameID = 1, navigationID = 4
最终无法正常加载本地的静态html
页面。
二、问题原因
同一个WKWebview
混用了https://
和file://
两种不同的协议,猜测:iOS12
系统中WKWebView
有内部限制,会锁定第一次使用资源文件目录
(readAccessURL
);
例如:先加载网络资源(loadRequest:
方式),资源文件目录
(readAccessURL
)指向网络目录(tmp目录
);再去使用(loadFileURL:allowingReadAccessToURL:
方式)加载存在Documents目录
下的本地的静态html
资源时,是无法通过allowingReadAccessToURL:
方法重新指定资源文件目录
(readAccessURL
)。
目前测试其他系统是正常的(iOS11
、iOS13
),iOS9
、iOS10
还有待验证(暂时没设备),仅在iOS12
上出现此问题。
三、解决方案
第一种:重新创建一个WKWebView
对象,专门用来通过(loadFileURL:allowingReadAccessToURL:
)加载本地的静态html
页面。
//仅做一个示例
- (void)loadNetworkAndLocalSourceMethod {
NSURL *httpUrl = [NSURL URLWithString:@"https://www.baidu.com"];
WKWebView *httpWebView = [[WKWebView alloc] initWithFrame:self.view.bounds];
httpWebView.navigationDelegate = self;
httpWebView.UIDelegate = self;
[self.view addSubview:httpWebView];
[httpWebView loadRequest:[NSURLRequest requestWithURL:httpUrl]];
NSURL *accessUrl = [NSURL fileURLWithPath:@"xxxxx/xxxx/xx/"];
NSURL *fileUrl = [NSURL fileURLWithPath:@"xxxxx/xxxx/xx/x.html"];
WKWebView *fileWebView = [[WKWebView alloc] initWithFrame:self.view.bounds];
fileWebView.navigationDelegate = self;
fileWebView.UIDelegate = self;
[self.view addSubview:fileWebView];
[fileWebView loadFileURL:fileUrl allowingReadAccessToURL:accessUrl];
}
第二种:将本地的静态html
资源存放在工程(NSBundle
)中,使用loadRequest:
的方式打开,这种方式会增加安装包的大小。
第三种:判断系统版本,如果设备系统是iOS12
的系统,将本地的静态html
资源的内容,通过代码的方式copy
到tmp目录
下,可继续使用loadFileURL:allowingReadAccessToURL:
的方式打开本地的静态html
页面。
#import
FOUNDATION_EXPORT NSString *DXDocumentsDirectory(void); //获取Documents路径
FOUNDATION_EXPORT NSString *DXTemporaryDirectory(void); //获取Temporary路径
@interface DXFileManager : NSObject
/*!
拷贝文件夹或文件从源路径到指定的路径中
* @param fromPath 源路径
* @param toPath 目标路径
*/
+ (void)copyFileFromPath:(NSString *)fromPath toPath:(NSString *)toPath;
/*!
创建一个新的文件夹目录
* @param directoryPath 文件夹路径
* @return 是否创建成功
*/
+ (BOOL)createDirectoryAtPath:(NSString *)directoryPath;
/*!
判断一个文件路径是否是文件夹路径
* @param targetPath 目标路径
* @return 是否是文件夹路径
*/
+ (BOOL)directoryExistsAtPath:(NSString *)targetPath;
/*!
判断一个文件是否是存在
* @param filePath 文件路径
* @return 是否是存在文件
*/
+ (BOOL)fileExistsAtPath:(NSString *)filePath;
@end
#import "DXFileManager.h"
//获取Documents路径
NSString *DXDocumentsDirectory(void) {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES) firstObject];
};
//获取Temporary路径
NSString *DXTemporaryDirectory(void) {
return NSTemporaryDirectory();
}
@implementation DXFileManager
+ (void)copyFileFromPath:(NSString *)fromPath toPath:(NSString *)toPath {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *array = [fileManager contentsOfDirectoryAtPath:fromPath error:nil];
for (int i = 0; i < [array count]; i ++) {
NSString *component = [array objectAtIndex:i];
NSString *startPath = [fromPath stringByAppendingPathComponent:component];
NSString *closePath = [toPath stringByAppendingPathComponent:component];
//判断是否存在路径
BOOL isFolder = NO; //判断是否是文件夹
BOOL isExist = [fileManager fileExistsAtPath:startPath isDirectory:&isFolder];
if (isExist) {
NSError *error = nil;
[fileManager copyItemAtPath:startPath toPath:closePath error:&error];
if (isFolder) {
[self copyFileFromPath:startPath toPath:closePath];
}
}
}
}
+ (BOOL)createDirectoryAtPath:(NSString *)directoryPath {
NSError *error = nil;
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL status = [fileManager createDirectoryAtPath:directoryPath
withIntermediateDirectories:YES
attributes:nil
error:&error];
return (status && (error == nil));
}
+ (BOOL)directoryExistsAtPath:(NSString *)targetPath {
BOOL isDirectory = NO;
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL status = [fileManager fileExistsAtPath:targetPath isDirectory:&isDirectory];
return (status && isDirectory);
}
+ (BOOL)fileExistsAtPath:(NSString *)filePath {
return [[NSFileManager defaultManager] fileExistsAtPath:filePath];
}
@end
第四种:通过本地起服的方式,去加载本地资源html
页面资源(需要本地资源html
页面支持该方式)。