swiftUI使用WKWebView,实现返回(goback)、关闭等功能

经过一天的研究终于实现了我需要的效果,点击“x”关闭当前页面,箭头返回上一页,如果没有上一页关闭当前页。(新手入坑实属不易)

如图:

//
//  AuthorView.swift
//  Java
//
//  Created by codeceo on 2020/4/7.
//  Copyright © 2020 白瑾浩. All rights reserved.
//

import SwiftUI
        import UIKit
        import WebKit
// 展示视图
        struct  AuthorView: View {
@Environment(\.presentationMode) var presentationMode
@State var isShowing: Bool = true
//let  webview :WebView = WebView(web: nil, URLRequest( url: URL(string: "http://www.itsayer.com")! ))
//    init(){
//         _isShowing = State(initialValue: true )
//    }
@State  var back: Bool = false
@State  var close: Bool = false
@ObservedObject var webViewStore = WebViewStore()
        var body: some View {
        ZStack{
        WebView(web: webViewStore.webView, URLRequest( url: URL(string: "http://www.itsayer.com")! ),self.$isShowing, self.$back, self.$close )

        .navigationBarTitle("作者blog",displayMode: .inline)
        .navigationBarItems(leading: HStack.init(spacing:0){
        Button(action: goBack ) {
        Image("返回")
        .imageScale(.large)
        .aspectRatio(contentMode:.fit)
        .frame(width: 32, height: 32)
        .foregroundColor(Color.white).padding( 0 )
        //.background( Color.red )
        //Text("返回").foregroundColor(Color.white).padding( 0 ).background( Color.red )
        }.padding(0).lineSpacing( 0 ).lineLimit( 1 )
        Button(action: goClose ) {
        Image("searchclose")
        .imageScale(.large)
        .aspectRatio(contentMode: .fill)
        .frame(width: 32, height: 32)
        .foregroundColor(Color.white).padding( .leading,10 )
        }

        })
        .onDisappear(){//消失
        print("消失")
        }.onAppear(){//出现
        print("出现")
        }
        LoadingView(isShowing:self.$isShowing)// { 匿名函数方便追加视图在底层
        //  Spacer()
//            VStack{
//                Button(action:{
//                    self.isShowing = !self.isShowing
//                    //self.isAnimating = false
//
//                }){
//                    Text(" Show loading ").foregroundColor(.white)
//                }.background(Color.orange)
//                    .cornerRadius(2.0)
//                .shadow(radius: 2)
//                }
        //  }
        }

        }
        func goBack() {

        let isBack = webViewStore.webView.goBack()
        if !(isBack != nil) {
        self.presentationMode.wrappedValue.dismiss()
        }

        }

        func goClose() {
        self.presentationMode.wrappedValue.dismiss()
        }

        }
        protocol NetCallBack {
        func success()
        }
        struct WebView : View, UIViewRepresentable{
@Binding var isShowing: Bool
@Binding  var back: Bool
@Binding  var close: Bool

        let request : URLRequest
        let webview : WKWebView

        init(web: WKWebView?,_ req: URLRequest , _ isShowing : Binding<Bool>, _ back : Binding<Bool> , _ close : Binding<Bool>) {
        self.webview = web!//WKWebView()
        self.request = req
        self._isShowing = isShowing
        self._back = back
        self._close = close
        }

        func makeUIView(context: Context) -> WKWebView {

        return webview
        }
        func updateUIView(_ uiView: WKWebView, context:Context) {

        uiView.uiDelegate = context.coordinator
        uiView.navigationDelegate = context.coordinator
        uiView.load( request )

        print("updateUIView")
        }

        func goBack()-> WKNavigation?{
        return webview.goBack()
        }

        func goForward(){
        webview.goForward()
        }

        func reload(){
        webview.reload()
        }
//正确显示 js的 alert 和 confirm
//来自https://stackoverflow.com/questions/59382225/how-to-implement-wkuidelegate-into-swiftui-wkwebview
class Coordinator: NSObject, WKUIDelegate,WKNavigationDelegate{
        var parent: WebView


        init(_ parent: WebView) {
        self.parent = parent
        //navigationItem.title="1"
        }

        // Delegate methods go here
        //javascript的交互
        func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
        // alert functionality goes here
        }
        func webView(_ webView : WKWebView, didFinish navigation: WKNavigation!) {
        print("完成")
        DispatchQueue.main.async {
        self.parent.isShowing = false     // must be async
        }
        // checkGoBack()

        }
        func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        print("失败")
        DispatchQueue.main.async {
        self.parent.isShowing = false     // must be async
        }
        // checkGoBack()
        }
        func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        print("准备开始")
        }
        func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
        print("开始加载")
//            DispatchQueue.main.async {
//            self.parent.isShowing = false     // must be async
//                              }
        }
        /// 检查返回(pop/goback)
        func checkGoBack(){
        if self.parent.webview.canGoBack
        {
        DispatchQueue.main.async {
        self.parent.back = true     // must be async
        // self.parent.goBack()
        }

        }else{
        // self.navigationItem.leftBarButtonItems = nil
        DispatchQueue.main.async {
        self.parent.back = false     // must be async

        }
        }
        }
        }
        func makeCoordinator() -> Coordinator {
        Coordinator(self)
        }


        }

public class WebViewStore: ObservableObject {
@Published public var webView: WKWebView {
        didSet {
        setupObservers()
        }
        }

public init(webView: WKWebView = WKWebView()) {
        self.webView = webView
        setupObservers()
        }

private func setupObservers() {
        func subscriber<Value>(for keyPath: KeyPath<WKWebView, Value>) -> NSKeyValueObservation {
        return webView.observe(keyPath, options: [.prior]) { _, change in
        if change.isPrior {
        self.objectWillChange.send()
        }
        }
        }
        // Setup observers for all KVO compliant properties
        observers = [
        subscriber(for: \.title),
        subscriber(for: \.url),
        subscriber(for: \.isLoading),
        subscriber(for: \.estimatedProgress),
        subscriber(for: \.hasOnlySecureContent),
        subscriber(for: \.serverTrust),
        subscriber(for: \.canGoBack),
        subscriber(for: \.canGoForward)
        ]
        }

private var observers: [NSKeyValueObservation] = []

        deinit {
        observers.forEach {
        // Not even sure if this is required?
        // Probably wont be needed in future betas?
        $0.invalidate()
        }
        }
        }


/**
 等待加载框
 * */
        struct ActivityIndicator: UIViewRepresentable {

@Binding var isAnimating: Bool
        let style: UIActivityIndicatorView.Style

        func makeUIView(context: UIViewRepresentableContext<ActivityIndicator>) -> UIActivityIndicatorView {
        return UIActivityIndicatorView(style: style)
        }

        func updateUIView(_ uiView: UIActivityIndicatorView, context: UIViewRepresentableContext<ActivityIndicator>) {
        isAnimating ? uiView.startAnimating() : uiView.stopAnimating()
        }
        }

        struct AuthorView_Previews: PreviewProvider {
static var previews: some View {
        AuthorView()
        }
        }

//
//  LoadingView.swift
//  Java
//
//  Created by codeceo on 2020/4/8.
//  Copyright © 2020 白瑾浩. All rights reserved.
//

import SwiftUI
//首次加载 等待的加载框
        struct LoadingView: View {
//struct LoadingView<Content>: View where Content: View {

@Binding var isShowing: Bool
@State var isAnimating: Bool = true
        //匿名函数方便追加视图在底层
        //var content: () -> Contents

        var body: some View {
        GeometryReader { geometry in
        ZStack(alignment: .center) {

        // self.content()

        VStack {
        Text("Loading...")
        ActivityIndicator(isAnimating: self.$isAnimating, style: .large)
//                    Button(action:{
//                        self.isShowing = false
//                        //self.isAnimating = false
//
//                    }){
//                        Text(" Hide ")
//                    }.background(Color.white)
//                        .cornerRadius(2.0)
//                    .shadow(radius: 2)
        }

        .frame(width: geometry.size.width / 3,
        height: geometry.size.height / 6)
        .background(Color.secondary.colorInvert())
        .foregroundColor(Color.primary)
        .cornerRadius(20)
        .opacity(self.isShowing ? 1 : 0)

        }
        }
        }

        }

以上就是实现的效果的代码,希望入坑的朋友对你有所帮助