把網頁相關的文件打包到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 的頁面,本地有緩存,就請求緩存,沒有再去請求。
例如新聞詳情這樣的不更改內容的靜態網頁就可以使用這個方式來加載。
這個網頁加載的方式的優點是省流量:
網頁的內容包括(圖片)都可以緩存。