这几天一致都在处理这个问题,在这里纪录分享一下。
首先要明确一个问题,我这里针对的是加载app bundle内打包的资源文件,而不是说安装app的ios系统的文件,所以这里应当不涉及apple严查的ATS权限问题,但是在查找问题时候开始以为是ATS原因,所以对ATS做了详细的调查,wkwebview默认是不开启http访问,如果想访问需要开启权限,并且在Info.plist制定例外规则。
<key>LSRequiresIPhoneOS</key> <true/> <key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> <key>NSAllowsArbitraryLoadsForMedia</key> <true/> <key>NSAllowsArbitraryLoadsInWebContent</key> <true/> <key>NSAllowsLocalNetworking</key> <true/> <key>NSExceptionAllowInsecureHTTPLoads</key> <true/> </dict>
特定网站需要开启特定规则,与主题无关,这里不再详述。
言归正传,这里详细说说加载包内文件的事情。
首先加载xcode项目加载资源文件,这里建议使用“create folder references”方式,我的理解就是建立引用文件,或者说相对路径。同时选择“copy items if needed”,这样当文件不在项目时会自动复制到项目处。
这样建立的文件夹显示蓝色!个人喜欢把该文件夹与代码放在同一个目录,这样便于后面手动拼装url使用!
一,获取文件路径
要想加载文件,首先是要获取文件路径,下面说说获取路径的几种方式。
第一种:手动拼装
let bundlePath = Bundle.main.bundlePath let path:String? = "file://\(bundlePath)/adv/index.htm" let url = URL(string: path!)!
简约化为
let fileURL = URL(string: "file://\(Bundle.main.bundlePath)/advs/index.htm")!
在这里Bundle.main.bundlePath的地址为包地址为
/var/containers/Bundle/Application/5701E155-D7AA-4167-B2A8-DAC2324FFBFF/nkbaishu.app/
然后自己拼装完成文件地址就好了,等于是手动完成了下面两种函数实现的方法
第二种:Bundle.main.path
这里以advs/index.html文件夹为例,该页面需要加载同目录下的img,css和js文件。获取路径代码如下
let fileURL = Bundle.main.path(forResource: "index", ofType:"htm", inDirectory: "advs") let filePathURL = URL(fileURLWithPath: fileURL)////init为默认,可省略 //let filePathURL = URL.init(fileURLWithPath: fileURL)
这样获取到的路径是这样的
fileURL:/var/containers/Bundle/Application/5701E155-D7AA-4167-B2A8-DAC2324FFBFF/nkbaishu.app/advs/index.htm filePathURL:file:///var/containers/Bundle/Application/5701E155-D7AA-4167-B2A8-DAC2324FFBFF/nkbaishu.app/advs/index.htm
需要说明的是这样获取到的地址是string,需要进行URL初始化,这里URL初始化的主要作用就是给 fileURL加上file://补全路径,才能被wkwebview加载,
第三种:Bundle.main.url
代码如下
let fileURL = Bundle.main.url(forResource: "index", withExtension: "htm", subdirectory: "advs")
上面的代码也可以简写为
let fileURL = Bundle.main.url(forResource: "adv/index", withExtension: "htm" )!
这样获取到的就是已经完成url初始化的完整路径,相对于前面两种方法,很明显这是最为高效简洁的了!
二,加载文件
上面获取到文件之后下面就是加载文件了。
第一种:loadFileURL
该函数加载方式如下
webview?.loadFileURL(fileURL,allowingReadAccessTo:fileURL.deletingLastPathComponent())
可以注意到这里有一个allowingReadAccessTo
参数。
这个参数的意思就是该文件允许访问的目录权限,我大概测试了三种情况,都没问题。
1,设置为和url一样,我测试了一下,加载html没有问题;
2,设置为Bundle.main.bundleURL,即把权限控制在bundle包范围内,经过测试ok;
3,设置为fileURL.deletingLastPathComponent(),这个意思就是允许访问与该html页面相关的资源文件,比如css,js,img等,个人认为这个是最合适的,开放访问该页面相关的资源文件。
第二种:loadHTMLString
do { let html = try String(contentsOfFile: fileURL, encoding: .utf8) webview?.loadHTMLString(html, baseURL: Bundle.main.resourceURL?.appendingPathComponent("advs")) } catch { print("Error loading html") }
这里,我把baseurl设置为Bundle.main.resourceURL?.appendingPathComponent("advs")
,也就是html网页的文件夹位置
第三种:load
这个load函数主要是用来加载远程网络地址的,加载本地网页时需要先进行URLRequest处理。
let request = URLRequest(url:fileURL) webView.load(request)
简写为
webview?.load(URLRequest(url: fileURL))
好了,ios swift加载bundle包内资源的方法基本上就介绍完了。
如果您在使用了上面的方法之后程序没有报错,但是打开之后页面总是空白,什么都不显示,那么请检查您的代理函数decidePolicyFor
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
请确认您是否允许了scheme为file:
时的请求,即有没有将file:///var/containers/Bundle/Application/5701E155-D7AA-4167-B2A8-DAC2324FFBFF/nkbaishu.app/advs/index.htm
这样的地址decisionHandler(.allow)
,由于疏忽大意,加载包内html总是空白,我被这个问题忽悠了 2天,希望看到这篇文章的朋友不要走弯路吧!