把网页相关的文件打包到APP中
把网页相关文件打包到App中会加快一些js和css文件的加载速度(个人认为,不用耗流量去请求了)
这里的注意点:
Resourse
文件夹放到这里 Resourse
显示成黄色文件夹
自己定义的文件夹,需要填加成蓝色文件夹
folder references
这里就是蓝色的文件夹
Copy Bundle Resourses
这里你需要看看有没有加到这里来。如果这里没有把文件的引用加进来,Bundle
包里面是找不到这个文件的。
苹果官方关于如何查找本地资源的文档在这里
For more details on how localized resources are found, read The Bundle Search Pattern in Bundle Programming Guide
.
相关加载代码
let path = Bundle.main.path(forResource: "view1/html/recordMaterial", ofType: "html")
let basePath = (path! as NSString).deletingLastPathComponent
do{
// 这里可能会抛出错误,, try 这里会出现错误的。
// NSString(contentsOfFile: path!, encoding: String.Encoding.utf8.rawValue
// 下面的这两个 file 的路径 调用方法 等价
// let htmlString = ( try NSString(contentsOfFile: path!, encoding: String.Encoding.utf8.rawValue) ) as String
let htmlString = try String(contentsOfFile: path!, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue))
webView.loadHTMLString(htmlString, baseURL:NSURL(fileURLWithPath: basePath) as URL)
}catch{
print(error)
}
注意: forResource: "view1/html/recordMaterial"
这里的路径要替换成你自己的。
WKWebView 中alert(jsString)
不显示的问题
Swift 的代码中,当前加载WKWebview的 Controller遵守WKUIDelegate
代理协议,
wkWebviewInstance..uiDelegate = self
, 这里的 self
就是当前的 Controller .
copy 一下 代码::
// WKUIDelegate
// 用于 WkWebView 上面 使用 alert 弹窗 结束
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo,
completionHandler: @escaping () -> Void) {
let alertController = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
completionHandler()
}))
present(alertController, animated: true, completion: nil)
}
func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo,
completionHandler: @escaping (Bool) -> Void) {
let alertController = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
completionHandler(true)
}))
alertController.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (action) in
completionHandler(false)
}))
present(alertController, animated: true, completion: nil)
}
func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo,
completionHandler: @escaping (String?) -> Void) {
let alertController = UIAlertController(title: nil, message: prompt, preferredStyle: .actionSheet)
alertController.addTextField { (textField) in
textField.text = defaultText
}
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
if let text = alertController.textFields?.first?.text {
completionHandler(text)
} else {
completionHandler(defaultText)
}
}))
alertController.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (action) in
completionHandler(nil)
}))
present(alertController, animated: true, completion: nil)
}
// 用于 WkWebView 上面 使用 alert 弹窗 结束
我自己试验了一下,WKUIDelegate
将JS的弹窗效果展示除了原生iOS的弹窗效果。
WKWebView 传值给 js.
给当前的controller
加一个扩展
extension RecordMaterialViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
let dict = [
"num1": 4,
"num2": 8
]
let jsonData = try! JSONSerialization.data(withJSONObject: dict, options: [])
let jsonString = String(data: jsonData, encoding: String.Encoding.utf8)!
webView.evaluateJavaScript("addTwoNumbers(\(jsonString));") { (result, error) in
guard error == nil else {
print("there was an error")
print("error === \(String(describing: error))")
return
}
print("结果是\(result)")
}
}
}
Note:
evaluateJavaScript
这个函数的参数传入的值,必须是JS中在全局作用域下能拿到值的函数或在JS中全局作用域能执行的JS语句。
设置webView.navigationDelegate = self
,设置这个代理
javascript 中定义这个函数 addTwoNumbers
var addTwoNumbers = function(swiftObj){
// swiftObj 传过来的已经是一个对象了
window.total = (swiftObj.num1 || 0) + (swiftObj.num2 || 0);
alert("xxx===" + window.total )
return window.total ;
}
swiftObj
这个就是传过来的数据了
调试JS和页面传值的小技巧
开使用手机App加载 Webview的时候,有时候会遇到 window.xxx
绑定属性和alert
不显示弹窗的问题。有个技巧就是讲你要处理的数据绑定到某个html
页面的元素属性上,或者赋值给span
元素的文字上。
同时打开Xcode
和javascript
代码编辑器可以提高效率
代码提示,代码片段等等有助于我们编程的东东大多数和编辑器关联。
使用 Xcode 处理iOS . JS代码编辑器处理网页,不要只在 Xcode上处理JS.
调用JS的流程
注意点:
使用Swfit
执行javascript
这个方法的时候比较慢。需要使用 swift
传递过来的数据的时候,需要在webView.evaluateJavaScript(XXX)
中的XXX
函数数调用其它的代码。否则,swift
数据还没传递过来,其它函数执行了就没有正确的数据了。
JS传值给Swfit
如何使用javascript
给swift
传值呢,WKUserContentController 可以做这个事情。
第一步
当前的控制器遵守 协议:WKScriptMessageHandler
使用WKUserContentController
, WKUserContentController
可以提供一个add
方法。
WKUserContentController
的实例,可以填加 add
的方法:
func add(_ scriptMessageHandler: WKScriptMessageHandler, name: String)
这里面:
WKScriptMessageHandler
就是遵守这个 WKScriptMessageHandler
这个协议的类。在当前控制器这里使用self
就可以了。
func add(_ scriptMessageHandler: WKScriptMessageHandler, name: String)
这个方法实现之后,
window.webkit.messageHandlers.name.postMessage(messageBody)
import UIKit
import WebKit
class UseHardWareViewController: UIViewController,WKScriptMessageHandler{
}
第二步
创建WKWebViewConfiguration
的实例,这个实例可以给网页进行一些配置。注意这个实例只能在 web view第一次创建的时候才能使用。
WKWebViewConfiguration
的实例的一个属性是WKWebViewConfiguration
的实例。
给WKWebViewConfiguration
的实例赋值WKWebViewConfiguration
的实例。
第三步
使用 WKWebViewConfiguration
的实例来创建webView, 并且将webView 添加到当前的控制器的视图上。
let o = WKUserContentController()
o.add(self, name: "foo")
let config = WKWebViewConfiguration()
config.userContentController = o
webView = WKWebView.init(frame: view.bounds, configuration: config)
self.view.addSubview(webView)
第四步
JS里面实现window.webkit.messageHandlers.name.postMessage(messageBody)
。
var messageObj = {
'tel':'010-12345678',
'address':'安徽省合肥市滨河西路1200号',
"dictionary": {"name": "foo"},
'name':'fool'
}
window.webkit.messageHandlers.foo.postMessage(messageObj)
第五步
实现这个方法 swift
里面:
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)
/// Js 给 Swift 传值
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage){
let body = message.body
print("body===\(body)")
if let dict = body as? Dictionary<String, AnyObject> {
print("dict====\(dict)");
print("message====\(message)");
print(message.name)
if(message.name == "foo"){
let value = String(describing: dict["name"]!)
print("body.name: \(value)")
}
}
}
打印结果是
body.name: fool
JS 给 Swift 传值就打通了。
WKWebView中web页面跳转处理
extension UseHardWareViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
print("webView===\(webView.url!)")
}
}
遵守这个协议WKNavigationDelegate
后, 每次导航结束后都会有打印。
在WKWebView
加载了网页之后,对网页进行更改
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
let modifyImagesJS =
"var images = document.getElementsByTagName('img');" +
"for(var i = 0; i < images.length; i++) {" +
"images[i].removeAttribute(\"height\");" +
"images[i].style.height = \"auto\";" +
"images[i].style.maxWidth = window.innerWidth - 20 * 2;" +
"}"
webView.evaluateJavaScript(modifyImagesJS) { (result, error) in
guard error == nil else {
print("there was an error")
print("error === \(String(describing: error))")
return
}
print("结果是\(result)")
}
}
在WKNavigationDelegate中的webView(_:didFinish:)
代码方法中实现,页面跳转完成之后实现更改网页中的图片尺寸。
不同帐号进入相同内容详情
let url = NSURL(string:"**YourWebPath**");
let request = NSURLRequest.init(url:url! as URL, cachePolicy:NSURLRequest.CachePolicy.returnCacheDataElseLoad, timeoutInterval: 10.0)
webView.load(request as URLRequest)
returnCacheDataElseLoad
使用的比较多:
Swift4
Specifies that the existing cached data should be used to satisfy the request, regardless of its age or expiration date. If there is no existing data in the cache corresponding the request, the data is loaded from the originating source.
大意就是如果这个请求的URL 的页面,本地有缓存,就请求缓存,没有再去请求。
例如新闻详情这样的不更改内容的静态网页就可以使用这个方式来加载。
这个网页加载的方式的优点是省流量:
网页的内容包括(图片)都可以缓存。