后退按钮不能快速工作,需要 4-5 秒的 Webview 才能返回,如何获得进度 SwiftUI

Back Button not working quickly, Take 4-5 Second Webview to back, How to get Progress SwiftUI

我正在使用 xcode13.1 在 swiftUI 中编写一个 Webapp 11=]

import SwiftUI
import WebKit

struct WebViewForCommunityTab : UIViewRepresentable {

let request: URLRequest
var webview: WKWebView?

init(web: WKWebView?, req: URLRequest) {
    self.webview = WKWebView()
    self.request = req
}

func makeUIView(context: Context) -> WKWebView  {
    return webview!
}

func updateUIView(_ uiView: WKWebView, context: Context) {
    uiView.load(request)
}

func goBack(){
    webview?.goBack()
}

func goForward(){
    webview?.goForward()
}

func goHomeScreen(){
    webview?.load(URLRequest(url: (URL(string: DefaultUrlString.CommunityWebLink)!)))
}
}


struct WebContentView: View {

let webview = WebViewForHomeTab(web: nil, req: URLRequest(url: URL(string: DefaultUrlString)!))

var body: some View {
    ZStack {
        VStack {
            VStack (spacing: 80) {
                webview
            }
            HStack (alignment: .center) {
                Group {
                    Spacer()
                    CustomButtonForWebView(btnImageTitle: ArrowLeftCircleImg, action: {
                        self.webview.goBack()
                    })
                    CustomButtonForWebView(btnImageTitle: ArrowRightCircleImg, action: {
                        self.webview.goForward()
                    })
                    Spacer()
                }.padding(.bottom,10)
            }.frame(width: UIScreen.screenWidth, height: 40, alignment: .center)
        }.hiddenNavigationBarStyle().background(Color.white)
    }
}
}

问题:当用户单击后退按钮时,如何在 WKWebView 中获取进度?

有人可以向我解释一下如何获得进度吗?

如有任何帮助,我们将不胜感激。

提前致谢。

它正在使用以下代码:-

import Foundation
import UIKit
import SwiftUI
import Combine
import WebKit

// MARK: - WebViewHandlerDelegate
// For printing values received from web app
protocol WebViewHandlerDelegate {
func receivedJsonValueFromWebView(value: [String: Any?])
func receivedStringValueFromWebView(value: String)
}

// MARK: - WebView
struct WebView: UIViewRepresentable, WebViewHandlerDelegate {
func receivedJsonValueFromWebView(value: [String : Any?]) {
    print("JSON value received from web is: \(value)")
}

func receivedStringValueFromWebView(value: String) {
    print("String value received from web is: \(value)")
}

var url: WebUrlType
// Viewmodel object
@ObservedObject var viewModel: ViewModel

// Make a coordinator to co-ordinate with WKWebView's default delegate functions
func makeCoordinator() -> Coordinator {
    Coordinator(self)
}

func makeUIView(context: Context) -> WKWebView {
    // Enable javascript in WKWebView
    let preferences = WKPreferences()
    preferences.javaScriptEnabled = true
    
    let configuration = WKWebViewConfiguration()
    // Here "iOSNative" is our delegate name that we pushed to the website that is being loaded
    configuration.userContentController.add(self.makeCoordinator(), name: "iOSNative")
    configuration.preferences = preferences
    
    let webView = WKWebView(frame: CGRect.zero, configuration: configuration)
    webView.navigationDelegate = context.coordinator
    webView.allowsBackForwardNavigationGestures = true
    webView.scrollView.isScrollEnabled = true
   return webView
}

func updateUIView(_ webView: WKWebView, context: Context) {
    if url == .localUrl {
        if let url = Bundle.main.url(forResource: "LocalWebsite", withExtension: "html", subdirectory: "www") {
            webView.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent())
        }
    } else if url == .publicUrl {
        if let url = URL(string: "https://www.medium.com/downtoride") {
            webView.load(URLRequest(url: url))
        }
    }
}

class Coordinator : NSObject, WKNavigationDelegate {
    var parent: WebView
    var delegate: WebViewHandlerDelegate?
    var valueSubscriber: AnyCancellable? = nil
    var webViewNavigationSubscriber: AnyCancellable? = nil
    
    init(_ uiWebView: WebView) {
        self.parent = uiWebView
        self.delegate = parent
    }
    
    deinit {
        valueSubscriber?.cancel()
        webViewNavigationSubscriber?.cancel()
    }
    
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        self.parent.viewModel.showLoader.send(false)
    }
    
    func webViewWebContentProcessDidTerminate(_ webView: WKWebView) {
        parent.viewModel.showLoader.send(false)
    }
    
    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        parent.viewModel.showLoader.send(false)
    }
    
    func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
        parent.viewModel.showLoader.send(true)
    }
    
    func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        parent.viewModel.showLoader.send(true)
        self.webViewNavigationSubscriber = self.parent.viewModel.webViewNavigationPublisher.receive(on: RunLoop.main).sink(receiveValue: { navigation in
            switch navigation {
                case .backward:
                    if webView.canGoBack {
                        webView.goBack()
                    }
                case .forward:
                    if webView.canGoForward {
                        webView.goForward()
                    }
                case .reload:
                    webView.reload()
            }
        })
    }
    
    // This function is essential for intercepting every navigation in the webview
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void){
        if let host = navigationAction.request.url?.host {
            if host == "restricted.com" {
                // This cancels the navigation
                decisionHandler(.cancel)
                return
            }
        }
        // This allows the navigation
        decisionHandler(.allow)
       }
    }
  }

 // MARK: - Extensions
 extension WebView.Coordinator: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
    if message.name == "iOSNative" {
        if let body = message.body as? [String: Any?] {
            delegate?.receivedJsonValueFromWebView(value: body)
        } else if let body = message.body as? String {
            delegate?.receivedStringValueFromWebView(value: body)
        }
    }
    }
  }

  import Foundation
  import Combine
  class ViewModel: ObservableObject {
var webViewNavigationPublisher = PassthroughSubject<WebViewNavigation, Never>()
var showWebTitle = PassthroughSubject<String, Never>()
var showLoader = PassthroughSubject<Bool, Never>()
var valuePublisher = PassthroughSubject<String, Never>()
}

// For identifiying WebView's forward and backward navigation
enum WebViewNavigation {
case backward, forward, reload
}

// For identifying what type of url should load into WebView
enum WebUrlType {
case localUrl, publicUrl
}

使用:-

import WebKit
import SwiftUI
import Combine
import Foundation

struct Loader: View {

@Binding var showActivity:Bool

var body: some View {
    VStack {
        if showActivity {
            ProgressView()
                .progressViewStyle(CircularProgressViewStyle(tint: Color.gray))
                .frame(width: 20, height: 20)
                .padding(.trailing,5)
           }
        }
    }
}

struct WebContentView: View {

@StateObject var viewModel = ViewModel()
@State var showLoader = false
@State var message = ""
@State var webTitle = ""

// For WebView's forward and backward navigation
var NavigationBar: some View {
    VStack(spacing: 0) {
        Divider()
        HStack {
            Spacer()
            Button(action: {
                self.viewModel.webViewNavigationPublisher.send(.backward)
            }) {
                Image(systemName: "ArrowLeftCircleImg")
                    .font(.system(size: 20, weight: .regular))
                    .imageScale(.large)
                    .foregroundColor(.blue)
            }
            
            Button(action: {
                self.viewModel.webViewNavigationPublisher.send(.forward)
            }) {
                Image(systemName: "ArrowRightCircleImg")
                    .font(.system(size: 20, weight: .regular))
                    .imageScale(.large)
                    .foregroundColor(.blue)
            }
            Spacer()
        }.frame(height: 45)
        Divider()
    }
}

var body: some View {
    ZStack {
        VStack(alignment:.trailing) {
            VStack(spacing: 0) {
                WebView(url: .publicUrl, viewModel: viewModel).overlay(Loader(showActivity: $showLoader), alignment: .center)
                NavigationBar
            }.onReceive(self.viewModel.showLoader.receive(on: RunLoop.main)) { value in
                self.showLoader = value
            }
         }
      }
   }
}