// // WebViewController.swift // yinmeng-ios // // Created by yinmeng on 2024/2/26. // import UIKit import WebKit class WebViewWeakScriptMessage: NSObject, WKScriptMessageHandler { private(set) weak var target: WKScriptMessageHandler? required init(target: WKScriptMessageHandler?) { self.target = target } func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { target?.userContentController(userContentController, didReceive: message) } } class WebViewController: BaseViewController { typealias OnReceiveMessage = (_ msg: WKScriptMessage) -> Void private(set) lazy var webview = makeWebView() private(set) var progressView = UIProgressView() private lazy var userContentController = WKUserContentController() private var callbacks: [String: [OnReceiveMessage]] = [:] private(set) weak var navigationDelegate: WKNavigationDelegate? private(set) var url: String? var isHalf:Bool = false convenience init( url: String?, navigationDelegate: WKNavigationDelegate? = nil,isHalf:Bool = false ) { self.init(nibName: nil, bundle: nil) self.url = url self.isHalf = isHalf if var url = url { if !url.hasPrefix("http") { url = "\(H5_URL)/\(url)" } self.url = url } self.navigationDelegate = navigationDelegate } override func viewDidLoad() { super.viewDidLoad() loadSubViews() loadWebView() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) addObserve() } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) removeObserve() } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() view.bringSubviewToFront(progressView) } private func loadSubViews() { if self.isHalf{ let bakcBtn = UIButton() bakcBtn.addTarget(self, action: #selector(dissViewAction), for: .touchUpInside) view.addSubview(bakcBtn) bakcBtn.snp.makeConstraints { make in make.edges.equalTo(view) } view.addSubview(webview) view.addSubview(progressView) progressView.snp.makeConstraints { make in make.top.equalTo(view).offset(0) make.left.right.equalTo(view).offset(0) make.height.equalTo(1) } view.backgroundColor = .clear webview.snp.makeConstraints { make in make.left.bottom.right.equalTo(view) make.height.equalTo(ScreenHeight * 0.65) } }else{ view.addSubview(webview) view.addSubview(progressView) progressView.snp.makeConstraints { make in make.top.equalTo(view).offset(0) make.left.right.equalTo(view).offset(0) make.height.equalTo(1) } webview.snp.makeConstraints { make in make.top.equalTo(view).offset(1) make.left.right.bottom.equalTo(view) } } progressView.trackTintColor = .clear progressView.transform = .init(scaleX: 1, y: 1.5) progressView.alpha = 0 } @objc func dissViewAction(){ self.dismiss(animated: true) } override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { if let object = object as? WKWebView, object == webview { if keyPath == "estimatedProgress" { progressView.setProgress(Float(webview.estimatedProgress), animated: true) return } } if keyPath == "title" { title = webview.title return } } func addObserve() { //添加KVO,WKWebView有一个属性estimatedProgress,就是当前网页加载的进度,所以监听这个属性 webview.addObserver(self, forKeyPath: "estimatedProgress", context: nil) //添加KVO,监听title属性 webview.addObserver(self, forKeyPath: "title", context: nil) } func removeObserve() { webview.removeObserver(self, forKeyPath: "estimatedProgress") webview.removeObserver(self, forKeyPath: "title") } func loadWebView() { guard let url = url, let theUrl = URL(string: url), let _ = theUrl.scheme, let _ = theUrl.host else { return } webview.load(URLRequest(url: theUrl)) } func reloadWebViewWithUrl(_ url: String) { self.url = url loadWebView() } func makeWebView() -> WKWebView { let configuration = WKWebViewConfiguration() configuration.mediaTypesRequiringUserActionForPlayback = .all configuration.allowsInlineMediaPlayback = true configuration.allowsPictureInPictureMediaPlayback = true configuration.selectionGranularity = .character configuration.userContentController = userContentController let preferences = WKPreferences() if #available(iOS 14, *) { let webpagePreferences = WKWebpagePreferences() webpagePreferences.allowsContentJavaScript = true configuration.defaultWebpagePreferences = webpagePreferences } else { preferences.javaScriptEnabled = true } preferences.javaScriptCanOpenWindowsAutomatically = true preferences.minimumFontSize = 10 configuration.preferences = preferences let webview = WKWebView(frame: UIScreen.main.bounds, configuration: configuration) webview.navigationDelegate = self return webview } func dicValueString(_ dic:[String:Any]) ->String? { let data = try? JSONSerialization.data(withJSONObject: dic,options: []) let str = String(data: data!,encoding:String.Encoding.utf8) return str } } extension WebViewController: WKScriptMessageHandler { func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { //TODO: 拦截一些h5的事件 } } extension WebViewController: WKNavigationDelegate { func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { progressView.alpha = 1 navigationDelegate?.webView?(webview, didStartProvisionalNavigation: navigation) } func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { UIView.animate(withDuration: 0.2) { self.progressView.alpha = 0 } navigationDelegate?.webView?(webview, didFinish: navigation) } func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { UIView.animate(withDuration: 0.2) { self.progressView.alpha = 0 } navigationDelegate?.webView?(webView, didFailProvisionalNavigation: navigation, withError: error) } }