WKWebView访问本地文件遇到的问题及解决方案

使用WKWebView加载3D模型,3D模型是使用webGL开发的,考虑到网络问题,采用本地化的方式,将3D模型数据下载到本地沙盒,将JS代码放入到工程目录下,再使用WKWebView加载index.html。

问题一:WKWebView访问index.html

由于JS代码中是通过文件路径找访问其他JS文件,所以在将js代码导入到项目中时,要创建实体文件夹才能够正常访问,如下图:
​​​​​​​

问题二:WKWebView无权限访问本地文件

1、访问本地文件使用的是file://协议,由于WKWebView的安全机制,会报一些错无法访问到。需要打开webView的file://协议访问权限,设置`allowFileAccessFromFileURLs`为`true`。

2、如果出现跨域的报错,也可以通过设置`allowUniversalAccessFromFileURLs`为`true`来解决。

WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
// 解决HTML请求跨域
[config setValue:@(true) forKey:@"allowUniversalAccessFromFileURLs"];
​
WKPreferences *preferences = [[WKPreferences alloc] init];
// 打开web访问本地文件权限
[preferences setValue:@(true) forKey:@"allowFileAccessFromFileURLs"];
config.preferences = preferences;

问题三:WKWebView访问沙盒文件

WKWebView无法访问Documents文件夹下的内容,只能访问tmp文件夹,因为下载的文件是放在Documents文件夹下的,所以有下面两个解决方案:

方案一、将文件拷贝到tmp文件夹下访问

通过文件管理类`NSFileManager`进行文件的拷贝,但是由于下载的文件比较大,并且会有文件更新的情况,如果每次都拷贝的话,拷贝的时间比较长,很影响用户体验。

+ (void)copyFileFromPath:(NSString *)sourcePath toPath:(NSString *)toPath {
   NSFileManager *fileManager = [NSFileManager defaultManager];
   // 判断目标位置 id 文件夹是否存在
   if ([fileManager fileExistsAtPath:toPath]) {
       // 存在,先移除
      [fileManager removeItemAtPath:toPath error:nil];
  }
   // 不存在 先创建 目标位置 id 文件夹
   BOOL toSuccess = [fileManager createDirectoryAtPath:toPath withIntermediateDirectories:YES attributes:nil error:nil];
   if (toSuccess) {
       // 获取fromPath文件路径下所有文件
       NSArray* array = [fileManager contentsOfDirectoryAtPath:sourcePath error:nil];
       for(int i = 0; i<[array count]; i++) {
           NSString *fullPath = [sourcePath stringByAppendingPathComponent:[array objectAtIndex:i]];
           NSString *fullToPath = [toPath stringByAppendingPathComponent:[array objectAtIndex:i]];
           // 判断是否存在并且为文件夹
           BOOL isFolder = NO;
           BOOL isExist = [fileManager fileExistsAtPath:fullPath isDirectory:&isFolder];
           if (isExist && isFolder) {
               // 存在并且是文件夹,在toPath下创建
              [fileManager createDirectoryAtPath:fullToPath withIntermediateDirectories:YES attributes:nil error:nil];
              [self copyFileFromPath:fullPath toPath:fullToPath];
          } else if (isExist && !isFolder) {
               NSError *err = nil;
              [fileManager copyItemAtPath:fullPath toPath:fullToPath error:&err];
          } else {
               NSLog(@"未找到源文件");
          }
      }
  }
   
}

方案二、拦截file://协议,使用原生获取本地沙盒文件,再将数据传给JS

该方案的具体实现可参考另一篇文章《WKWebView实现请求拦截,http/https/file等》

问题四:加载本地3D模型的时候,无法显示

在拦截file://请求之后,需要回传给webView请求任务一个response,在生成response的时候有两种方式`NSURLResponse`和`NSHTTPURLResponse`两种方式,使用`NSHTTPURLResponse`方式生成可以正常加载。(可参考另一篇文章《WKWebView实现请求拦截,http/https/file等》


版权声明:本文为colrying原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。