后退按钮不能快速工作,需要 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
}
}
}
}
}
我正在使用 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
}
}
}
}
}