Veloria/Veloria/Base/WebView/VPWebView.swift
2025-05-26 18:28:51 +08:00

198 lines
7.5 KiB
Swift

//
// VPWebView.swift
// Veloria
//
// Created by on 2025/5/26.
//
import UIKit
@preconcurrency import WebKit
//MARK:-------------- VPWebViewDelegate --------------
@objc protocol VPWebViewDelegate: NSObjectProtocol {
@objc optional func webView(_ webView: VPWebView, shouldStartLoadWith navigationAction: WKNavigationAction) -> Bool
@objc optional func webViewDidStartLoad(_ webView: VPWebView)
@objc optional func webViewDidFinishLoad(_ webView: VPWebView)
@objc optional func webView(_ webView: VPWebView, didFailLoadWithError error: Error)
///
@objc optional func webView(webView: VPWebView, didChangeProgress progress: CGFloat)
///
@objc optional func webView(webView: VPWebView, didChangeTitle title: String)
///web
@objc optional func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)
}
class VPWebView: WKWebView {
weak var delegate: VPWebViewDelegate?
// private(set) var scriptMessageHandlerArray: [SPWebViewMessageName] = [
// WebMessageAPP,
// WebMessageOpenFeedbackList,
// WebMessageOpenFeedbackDetail,
// WebMessageOpenPhotoPicker,
// ]
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)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if object as? VPWebView == 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 VPWebView: 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 VPWebView: WKNavigationDelegate {
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
decisionHandler(.allow);
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
vpLog(message: navigationAction.request.url)
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!) {
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 VPWebView: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
self.delegate?.userContentController?(userContentController, didReceive: message)
}
}