There are questions remain, We'll search for the answers together. But one thing we known for sure,the future is not set!

【原创文章】详解ios swift wkwebview加载包内资源文件的几种方式

APP 百蔬君 374℃ 已收录 0评论

这几天一致都在处理这个问题,在这里纪录分享一下。

首先要明确一个问题,我这里针对的是加载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天,希望看到这篇文章的朋友不要走弯路吧!

转载请注明:百蔬君 » 【原创文章】详解ios swift wkwebview加载包内资源文件的几种方式

喜欢 (1)or分享 (0)
发表我的评论
取消评论

请证明您不是机器人(^v^):

表情