使用
- WebViewManager 管理 wkwebview 可调用方法 比如goback, 需要观察者模式的通过 block回调, 初始化的时候传了block才会 addObserver
@State var title: String = ""
@State var canGoBack: Bool = false
@State var loadingStatus: LoadingStaus = .Wait
@State var estimatedProgress: Double = 0.0
let manager = WebViewManager()
WebView(manager, listenTitle: { title in
self.title = title
print("title: \(title)")
}, listenCanGoBack: { canGoBack in
self.canGoBack = canGoBack
print("canGoBack: \(canGoBack)")
}, listenLoadingStatus: { loadingStaus in
self.loadingStatus = loadingStaus
print("loadingStaus: \(loadingStaus)")
}, listenEstimatedProgress: { estimatedProgress in
self.estimatedProgress = estimatedProgress
print("estimatedProgress: \(estimatedProgress)")
})
.loadUrl("https://www.baidu.com")
代码
import SwiftUI
import WebKit
typealias StringBlock = (String) -> Void
typealias BoolBlock = (Bool) -> Void
typealias WebLoadingStatusBlock = (LoadingStaus) -> Void
typealias DoubleBlock = (Double) -> Void
/// webview 加载状态
enum LoadingStaus: String {
case Wait = "wait"
case Finish = "finish"
case Faile = "faile"
}
class WebViewManager {
let webView: WKWebView
init(){
let pres = WKWebpagePreferences()
pres.allowsContentJavaScript = true
let config = WKWebViewConfiguration()
config.defaultWebpagePreferences = pres
self.webView = WKWebView(frame: .zero, configuration: config)
}
func goBack(){
if(webView.canGoBack){
webView.goBack()
}
}
}
struct WebView: UIViewRepresentable {
let manager: WebViewManager
private var listenTitle: StringBlock?
private var listenCanGoBack: BoolBlock?
private var listenLoadingStatus: WebLoadingStatusBlock?
private var listenEstimatedProgress: DoubleBlock?
init(_ manager: WebViewManager, listenTitle: StringBlock? = nil, listenCanGoBack: BoolBlock? = nil, listenLoadingStatus: WebLoadingStatusBlock? = nil, listenEstimatedProgress: DoubleBlock? = nil){
self.manager = manager
self.listenTitle = listenTitle
self.listenCanGoBack = listenCanGoBack
self.listenLoadingStatus = listenLoadingStatus
self.listenEstimatedProgress = listenEstimatedProgress
}
func makeUIView(context: Context) -> WKWebView {
manager.webView.navigationDelegate = context.coordinator
return manager.webView
}
func updateUIView(_ webView: WKWebView, context: Context) {
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, WKNavigationDelegate {
let parent: WebView
init(_ parent: WebView) {
self.parent = parent
super.init()
if(self.parent.listenTitle != nil){
self.parent.manager.webView.addObserver(self, forKeyPath: "title", options: .new, context: nil)
}
if(self.parent.listenCanGoBack != nil){
self.parent.manager.webView.addObserver(self, forKeyPath: "canGoBack", options: .new, context: nil)
}
if(self.parent.listenEstimatedProgress != nil) {
self.parent.manager.webView.addObserver(self, forKeyPath: "estimatedProgress", options: .new, context: nil)
}
}
deinit{
if(self.parent.listenTitle != nil){
self.parent.manager.webView.removeObserver(self, forKeyPath: "title")
}
if(self.parent.listenCanGoBack != nil){
self.parent.manager.webView.removeObserver(self, forKeyPath: "canGoBack")
}
if(self.parent.listenEstimatedProgress != nil) {
self.parent.manager.webView.removeObserver(self, forKeyPath: "estimatedProgress")
}
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
if let callback = self.parent.listenLoadingStatus{
callback(.Wait)
}
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
if let callback = self.parent.listenLoadingStatus{
callback(.Finish)
}
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
if let callback = self.parent.listenLoadingStatus{
callback(.Faile)
}
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
// TODO
if let url = navigationAction.request.url?.absoluteString {
//url拦截
if(url.contains("你要拦截的urL")){
//处理拦截逻辑
}
}
decisionHandler(.allow)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if(keyPath == "title"){
if let callback = self.parent.listenTitle {
callback(self.parent.manager.webView.title ?? "")
}
}
if(keyPath == "canGoBack"){
if let callback = self.parent.listenCanGoBack {
callback(self.parent.manager.webView.canGoBack)
}
}
if(keyPath == "estimatedProgress"){
if let callback = self.parent.listenEstimatedProgress {
callback(self.parent.manager.webView.estimatedProgress)
}
}
}
}
func loadUrl(_ urlString: String) -> Self{
let url = URL.init(string: urlString)
if let _url = url {
let request = URLRequest.init(url: _url)
self.manager.webView.load(request)
}
return self
}
}