218 lines
8.3 KiB
Swift
218 lines
8.3 KiB
Swift
//
|
|
// SPWebView.swift
|
|
// Thimra
|
|
//
|
|
// Created by 曾觉新 on 2025/4/14.
|
|
//
|
|
|
|
import UIKit
|
|
@preconcurrency import WebKit
|
|
|
|
class SPWebView: WKWebView {
|
|
|
|
weak var delegate: SPWebViewDelegate?
|
|
|
|
private(set) var scriptMessageHandlerArray: [SPWebViewMessageName] = [
|
|
WebMessageAPP,
|
|
]
|
|
|
|
|
|
deinit {
|
|
|
|
self.removeObserver(self, forKeyPath: "estimatedProgress")
|
|
self.removeObserver(self, forKeyPath: "title")
|
|
|
|
}
|
|
|
|
override init(frame: CGRect, configuration: WKWebViewConfiguration) {
|
|
super.init(frame: frame, configuration: configuration)
|
|
addScriptMessageHandler()
|
|
_setupInit()
|
|
}
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
private func _setupInit() {
|
|
|
|
self.isOpaque = false
|
|
self.uiDelegate = self
|
|
self.navigationDelegate = self
|
|
self.addObserver(self, forKeyPath: "estimatedProgress", options: .new, context: nil)
|
|
self.addObserver(self, forKeyPath: "title", options: .new, context: nil)
|
|
|
|
// var userAgent = (self.value(forKey: "userAgent") as? String) ?? ""
|
|
// if !userAgent.contains(";jxdbBrowser") {
|
|
// userAgent = userAgent + ";jxdbBrowser|V\(kYDAPPVersion)"
|
|
// self.customUserAgent = userAgent
|
|
// }
|
|
}
|
|
|
|
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
|
if object as? SPWebView == self {
|
|
if keyPath == "estimatedProgress", let progress = change?[NSKeyValueChangeKey.newKey] as? CGFloat {
|
|
self.delegate?.webView?(webView: self, didChangeProgress: progress)
|
|
} else if keyPath == "title", let title = change?[NSKeyValueChangeKey.newKey] as? String {
|
|
self.delegate?.webView?(webView: self, didChangeTitle: title)
|
|
}
|
|
}
|
|
}
|
|
|
|
func load(urlStr: String) {
|
|
guard let url = URL(string: urlStr) else { return }
|
|
var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 30)
|
|
self.load(request)
|
|
}
|
|
|
|
func removeScriptMessageHandler() {
|
|
self.scriptMessageHandlerArray.forEach{
|
|
configuration.userContentController.removeScriptMessageHandler(forName: $0)
|
|
}
|
|
}
|
|
func addScriptMessageHandler() {
|
|
self.scriptMessageHandlerArray.forEach{
|
|
configuration.userContentController.add(YYWeakProxy(target: self) as! WKScriptMessageHandler, name: $0)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//MARK:-------------- WKUIDelegate --------------
|
|
extension SPWebView: WKUIDelegate {
|
|
|
|
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
|
|
let alertController = UIAlertController(title: "提示", message: message, preferredStyle: .alert)
|
|
alertController.addAction(UIAlertAction(title: "确认", style: .default, handler: { (action) in
|
|
completionHandler()
|
|
}))
|
|
self.viewController?.present(alertController, animated: true, completion: nil)
|
|
}
|
|
|
|
func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
|
|
let alertController = UIAlertController(title: "提示", message: message, preferredStyle: .alert)
|
|
alertController.addAction(UIAlertAction(title: "取消", style: .cancel, handler: { (action) in
|
|
completionHandler(false)
|
|
}))
|
|
alertController.addAction(UIAlertAction(title: "确认", style: .default, handler: { (action) in
|
|
completionHandler(true)
|
|
}))
|
|
self.viewController?.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: prompt, message: "", preferredStyle: .alert)
|
|
alertController.addTextField { (textField) in
|
|
textField.text = defaultText
|
|
}
|
|
alertController.addAction(UIAlertAction(title: "完成", style: .default, handler: { (action) in
|
|
completionHandler(alertController.textFields?.first?.text)
|
|
}))
|
|
self.viewController?.present(alertController, animated: true, completion: nil)
|
|
}
|
|
}
|
|
|
|
//MARK:-------------- WKNavigationDelegate --------------
|
|
extension SPWebView: WKNavigationDelegate {
|
|
|
|
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
|
|
/*同步cookie*/
|
|
// let cookies = JXCookiesManager.getAllCookies()
|
|
// for cookie in cookies {
|
|
// setCookie(cookie: cookie)
|
|
// }
|
|
|
|
decisionHandler(.allow);
|
|
}
|
|
|
|
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
|
|
spLog(message: navigationAction.request.url)
|
|
|
|
// if navigationAction.request.url?.scheme == "tel" {
|
|
// UIApplication.shared.openURL(navigationAction.request.url!)
|
|
// decisionHandler(.cancel)
|
|
// return
|
|
// }
|
|
if let url = navigationAction.request.url,
|
|
url.scheme != "http",
|
|
url.scheme != "https"
|
|
{
|
|
UIApplication.shared.open(url)
|
|
decisionHandler(.cancel)
|
|
return
|
|
}
|
|
|
|
//防止抓包
|
|
// if JXRequestHttpProxy.isIntercept() {
|
|
// decisionHandler(.cancel)
|
|
// return
|
|
// }
|
|
|
|
|
|
if let result = self.delegate?.webView?(self, shouldStartLoadWith: navigationAction) {
|
|
if result {
|
|
decisionHandler(.allow)
|
|
} else {
|
|
decisionHandler(.cancel)
|
|
}
|
|
} else {
|
|
decisionHandler(.allow)
|
|
}
|
|
}
|
|
|
|
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
|
|
self.delegate?.webViewDidStartLoad?(self)
|
|
}
|
|
|
|
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
|
|
|
// ///禁用长按展示长图
|
|
// webView.evaluateJavaScript("document.documentElement.style.webkitTouchCallout='none';", completionHandler: nil)
|
|
// ///禁用长按选择图片文字
|
|
// webView.evaluateJavaScript("document.documentElement.style.webkitUserSelect='none';", completionHandler: nil)
|
|
|
|
|
|
|
|
self.delegate?.webViewDidFinishLoad?(self)
|
|
}
|
|
|
|
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
|
|
self.delegate?.webView?(self, didFailLoadWithError: error)
|
|
}
|
|
|
|
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
|
|
self.delegate?.webView?(self, didFailLoadWithError: error)
|
|
}
|
|
|
|
|
|
}
|
|
|
|
//MARK:-------------- WKScriptMessageHandler --------------
|
|
extension SPWebView: WKScriptMessageHandler {
|
|
|
|
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
|
self.delegate?.userContentController?(userContentController, didReceive: message)
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//MARK:-------------- YDWebViewDelegate --------------
|
|
@objc protocol SPWebViewDelegate: NSObjectProtocol {
|
|
|
|
@objc optional func webView(_ webView: SPWebView, shouldStartLoadWith navigationAction: WKNavigationAction) -> Bool
|
|
|
|
@objc optional func webViewDidStartLoad(_ webView: SPWebView)
|
|
|
|
@objc optional func webViewDidFinishLoad(_ webView: SPWebView)
|
|
|
|
@objc optional func webView(_ webView: SPWebView, didFailLoadWithError error: Error)
|
|
|
|
///进度
|
|
@objc optional func webView(webView: SPWebView, didChangeProgress progress: CGFloat)
|
|
///标题
|
|
@objc optional func webView(webView: SPWebView, didChangeTitle title: String)
|
|
|
|
///web交互用
|
|
@objc optional func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)
|
|
|
|
}
|