ios: How to reload webview from a Coordinator class SwiftUi - swift

I am making an app that contains multiple web-view's. I am wanting to reload my web-view from the coordinator class after a JS command is sent from the webpage and inside the "func processReturnedJS(body: String)" shown below. I am wondering how I can achieve this in a simple way?
Thanks
SubscriptionViewController:
import SwiftUI
import WebKit
struct SubscriptionViewController: UIViewRepresentable {
#StateObject var storeManager: StoreManager
let frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
let config = WKWebViewConfiguration()
let cookies = HTTPCookieStorage.shared.cookies ?? []
func makeUIView(context: UIViewRepresentableContext<SubscriptionViewController>) -> WKWebView {
for cookie in cookies {
config.websiteDataStore.httpCookieStore.setCookie(cookie, completionHandler: nil)
}
let preferences = WKPreferences()
let configuration = WKWebViewConfiguration()
configuration.preferences = preferences
let userContentController = WKUserContentController()
userContentController.add(context.coordinator, name:"observer")
configuration.userContentController = userContentController
let view = WKWebView(frame: frame, configuration: configuration)
view.navigationDelegate = context.coordinator
DispatchQueue.main.async {
let url = URL(string:"theurl")!
let request = URLRequest(url: url)
for cookie in cookies {
config.websiteDataStore.httpCookieStore.setCookie(cookie, completionHandler: nil)
view.configuration.websiteDataStore.httpCookieStore.setCookie(cookie, completionHandler: nil)
}
view.load(request)
}
return view
}
func updateUIView(_ uiView: WKWebView, context: UIViewRepresentableContext<SubscriptionViewController>) {
}
func makeCoordinator() -> CoordinatorSubscription {
CoordinatorSubscription(self, storeManage: self.storeManager)
}
typealias UIViewType = WKWebView
}
class CoordinatorSubscription: NSObject, WKNavigationDelegate, WKScriptMessageHandler {
var control: SubscriptionViewController
var storeManage: StoreManager
init(_ control: SubscriptionViewController, storeManage: StoreManager) {
self.control = control
self.storeManage = storeManage
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
processReturnedJS(body: message.body as! String)
}
func sendjs(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
}
func processReturnedJS(body: String) {
print("kkkk")
//want to reload webview from here
}
}

You can store a reference to the WKWebView in your coordinator:
class CoordinatorSubscription: NSObject, WKNavigationDelegate, WKScriptMessageHandler {
var control: SubscriptionViewController
var storeManage: StoreManager
var webView : WKWebView? //<-- Here
init(_ control: SubscriptionViewController, storeManage: StoreManager) {
self.control = control
self.storeManage = storeManage
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
processReturnedJS(body: message.body as! String)
}
func sendjs(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
}
func processReturnedJS(body: String) {
self.webView?.reload() //here
}
}
Then, make sure to set that property in makeUIView:
func makeUIView(context: UIViewRepresentableContext<SubscriptionViewController>) -> WKWebView {
for cookie in cookies {
config.websiteDataStore.httpCookieStore.setCookie(cookie, completionHandler: nil)
}
let preferences = WKPreferences()
let configuration = WKWebViewConfiguration()
configuration.preferences = preferences
let userContentController = WKUserContentController()
userContentController.add(context.coordinator, name:"observer")
configuration.userContentController = userContentController
let view = WKWebView(frame: frame, configuration: configuration)
view.navigationDelegate = context.coordinator
DispatchQueue.main.async {
let url = URL(string:"theurl")!
let request = URLRequest(url: url)
for cookie in cookies {
config.websiteDataStore.httpCookieStore.setCookie(cookie, completionHandler: nil)
view.configuration.websiteDataStore.httpCookieStore.setCookie(cookie, completionHandler: nil)
}
view.load(request)
}
context.coordinator.webView = view //<-- Here
return view
}

Related

WKWebView not receiving configuration from previous WebView

I'm trying to receive the configuration that , to my understanding, should have been transmitted from a the previous website. The example below is a website that has a simple login button, when pressed, it opens a new tab (which I want to open in the same view). There you'd login and after that you would be brought back to the previous site.
The website can also be visited in a normal browser website
Its an open source project found here Github
I have the following code:
ContentView
import SwiftUI
import UIKit
import WebKit
struct ContentView: View {
var webView: WKWebView
init() {
let userContentController = WKUserContentController() //CustomContentController()
let webViewConfiguration = WKWebViewConfiguration()
webViewConfiguration.userContentController = userContentController
self.webView = WKWebView(frame: .zero, configuration: webViewConfiguration)
self.webView.configuration.limitsNavigationsToAppBoundDomains = true
self.webView.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true
}
var body: some View {
WebviewNew(web: webView, req: URLRequest(url: URL(string: "https://vasb2-4yaaa-aaaab-qadoa-cai.ic0.app/")!))
}
}
WebViewNew
struct WebviewNew : UIViewRepresentable {
let request: URLRequest
var webview: WKWebView?
init(web: WKWebView?, req: URLRequest) {
self.webview = web ?? WKWebView()
self.request = req
}
class Coordinator: NSObject, WKUIDelegate, WKNavigationDelegate {
var parent: WebviewNew
init(_ parent: WebviewNew) {
self.parent = parent
}
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
if navigationAction.targetFrame == nil {
let newWebView = WKWebView(frame: webView.frame, configuration: configuration)
newWebView.uiDelegate = self
newWebView.load(navigationAction.request)
//
return newWebView
// webView.load(navigationAction.request)
}
return nil
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> WKWebView {
return webview!
}
func updateUIView(_ uiView: WKWebView, context: Context) {
uiView.uiDelegate = context.coordinator
uiView.load(request)
}
func goBack(){
webview?.goBack()
}
func goForward(){
webview?.goForward()
}
func reload(){
webview?.reload()
}
}
This solution does somehow not work. When clicking the Login Button on the website inside the WKWebView nothing happens. When setting a breakpoint in func webView one can see that it gets passed but somehow nothing happens.
When altering the WebViewNew like this:
struct WebviewNew : UIViewRepresentable {
let request: URLRequest
var webview: WKWebView?
init(web: WKWebView?, req: URLRequest) {
self.webview = web ?? WKWebView()
self.request = req
}
class Coordinator: NSObject, WKUIDelegate, WKNavigationDelegate {
var parent: WebviewNew
init(_ parent: WebviewNew) {
self.parent = parent
}
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
if navigationAction.targetFrame == nil {
// Changed HERE
webView.load(navigationAction.request)
}
return nil
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> WKWebView {
return webview!
}
func updateUIView(_ uiView: WKWebView, context: Context) {
uiView.uiDelegate = context.coordinator
uiView.load(request)
}
func goBack(){
webview?.goBack()
}
func goForward(){
webview?.goForward()
}
func reload(){
webview?.reload()
}
}
With a change in func webView it opens the login page but it seems to be missing the context as the login does not know who made the request.
In the open source website the login button can be found here
Why is my solution not working and what could make it work?

Xcode Webview items not loading

I have a Xcode Project with a Webview and a TabBar and with the TabBar I can switch between WebViews. My Problem is that when I put something in my ShoppingCard under Lieferworld.de and switch with the TabBar to my Shopping Card url the Items in there are not Visible. How can I solve this? the ShoppingCard URL ends with .php. Below is the code which is implemented
I also uploaded a video on YouTube were I you can see the error
https://youtu.be/qU3Mu1G7MY0
Viewhome:
import UIKit
import WebKit
class viewHome: UIViewController, WKUIDelegate {
#IBOutlet var webViewHome: WKWebView!
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
webViewHome = WKWebView(frame: .zero, configuration: webConfiguration)
webViewHome.uiDelegate = self
webViewHome.configuration.preferences.javaScriptEnabled = true
//webViewHome.configuration.preferences.javaEnabled = true
view = webViewHome
}
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "https://lieferworld.de")
let request = URLRequest(url: url!)
webViewHome.configuration.preferences.javaScriptEnabled = true
//webViewHome.configuration.preferences.javaEnabled = true
webViewHome.load(request)
}
#IBAction func GoBackHome(_ sender: Any) {
if webViewHome.canGoBack {
webViewHome.goBack()
}
}
#IBAction func GoForwardHome(_ sender: Any) {
if webViewHome.canGoForward {
webViewHome.goForward()
}
}
}
ViewShopping | Shopping Cart Class:
import UIKit
import WebKit
class viewShopping: UIViewController, WKUIDelegate {
#IBOutlet var webViewShopping: WKWebView!
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
webViewShopping = WKWebView(frame: .zero, configuration: webConfiguration)
webViewShopping.uiDelegate = self
//webViewShopping.configuration.preferences.javaEnabled = true
webViewShopping.configuration.preferences.javaScriptEnabled = true
view = webViewShopping
}
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "https://lieferworld.de/warenkorb.php")
let request = URLRequest(url: url!)
webViewShopping.configuration.preferences.javaScriptEnabled = true
//webViewShopping.configuration.preferences.javaEnabled = true
webViewShopping.load(request)
}
#IBAction func goBackShoppingCart(_ sender: Any) {
if webViewShopping.canGoBack {
webViewShopping.goBack()
}
}
#IBAction func goForwardShoppingCart(_ sender: Any) {
if webViewShopping.canGoForward {
webViewShopping.goForward()
}
}
#IBAction func webViewRefresh(_ sender: Any) {
webViewShopping.reload()
}
}
WKNavigationDelegate has three delegates.
Here's an example;
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
print(error.localizedDescription)
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
print("Start page load")
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)
{
let title = webView.title
print("finish load. \(title).")
// you can do processing on the results here or trigger processing elsewhere
webView.evaluateJavaScript("document.documentElement.outerHTML.toString()",completionHandler:
{ (html: Any?, error: Error?) in
print(html as Any)
self.htmlSource = html as! String
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "pageLoaded"), object: nil)
})
}

How can i use open in new tab in swift ?(WEBKIT)

How can i use safari-open in new tab in my webkit app
I am creating a internet browser and i need that
Just like the photo
For example, I want to show the open in new tab option when I hold my finger on a link in Google
enter image description here
class ViewController: UIViewController, UITextFieldDelegate, WKNavigationDelegate {
#IBOutlet weak var backButton: UIButton!
#IBOutlet weak var forwardButton: UIButton!
#IBOutlet weak var webView: WKWebView!
#IBOutlet weak var urlTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
urlTextField.delegate = self
webView.navigationDelegate = self
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear( animated )
let urlString:String = "https://www.google.com"
let url:URL = URL(string: urlString)!
let urlRequest:URLRequest = URLRequest(url: url)
webView.load(urlRequest)
urlTextField.text = urlString
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
let urlString:String = urlTextField.text!
let url:URL = URL(string: urlString)!
let urlRequest:URLRequest = URLRequest(url: url)
webView.load(urlRequest)
textField.resignFirstResponder()
return true
}
#IBAction func backButtonTapped(_ sender: Any) {
if webView.canGoBack {
webView.goBack()
}
}
#IBAction func forwardButtonTapped(_ sender: Any) {
if webView.canGoForward {
webView.goForward()
}
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
backButton.isEnabled = webView.canGoBack
forwardButton.isEnabled = webView.canGoForward
urlTextField.text = webView.url?.absoluteString
}
}
Use this delegate method in bellow you last medhod :
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
if navigationAction.targetFrame == nil {
if let url = navigationAction.request.url {
let app = UIApplication.shared
if app.canOpenURL(url) {
app.open(url, options: [:], completionHandler: nil)
}
}
}
decisionHandler(.allow)
}
is It oky ?

I'm trying to open external links from my app but it won't open

I have a wkwebview app, I need help with my code, I can't seems to open external links from my website inside my app.
import UIKit
import WebKit
import UserNotifications
class ViewController: UIViewController, WKUIDelegate, WKNavigationDelegate {
var webView: WKWebView!
var activityIndicator: UIActivityIndicatorView!
var bgImage: UIImageView!
var urlString = ""
override func loadView() {
super.loadView()
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
webView.navigationDelegate = self
view = webView
}
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
if navigationAction.targetFrame == nil {
let vc = ViewController()
vc.urlString = navigationAction.request.url?.absoluteString ?? "https://mywebsite"
vc.view.frame = UIScreen.main.bounds
vc.webView = WKWebView(frame: UIScreen.main.bounds, configuration: configuration)
navigationController?.pushViewController(vc, animated: false)
return vc.webView
}
return nil
}
override var prefersStatusBarHidden: Bool{
return true
}
override func viewDidLoad() {
super.viewDidLoad()
let image : UIImage = UIImage(named:"bgx1")!
bgImage = UIImageView(image: image)
bgImage.frame = CGRect(x: 0, y: 0, width: 1000, height: 2000)
view.addSubview(bgImage)
let myURL = URL(string: "https://mywebsite/")
let myRequest = URLRequest(url: myURL!)
webView.load(myRequest)
webView.allowsBackForwardNavigationGestures = true
activityIndicator = UIActivityIndicatorView()
activityIndicator.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
self.activityIndicator.center = CGPoint(x:self.view.bounds.size.width/2.0,y: self.view.bounds.size.height/2.0);
activityIndicator.autoresizingMask = (UIView.AutoresizingMask(rawValue: UIView.AutoresizingMask.RawValue(UInt8(UIView.AutoresizingMask.flexibleRightMargin.rawValue) | UInt8(UIView.AutoresizingMask.flexibleLeftMargin.rawValue) | UInt8(UIView.AutoresizingMask.flexibleBottomMargin.rawValue) | UInt8(UIView.AutoresizingMask.flexibleTopMargin.rawValue))))
activityIndicator.hidesWhenStopped = true
activityIndicator.style = UIActivityIndicatorView.Style.whiteLarge
activityIndicator.color = UIColor.darkGray
self.view.addSubview(activityIndicator)
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
activityIndicator.startAnimating()
bgImage.startAnimating()
}
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
print("It is an error")
activityIndicator.stopAnimating()
bgImage.stopAnimating()
let alert = UIAlertController(title: "Network Error", message: "You have no internet connection", preferredStyle: .alert)
let restartAction = UIAlertAction(title: "Reload page", style: .default, handler: { (UIAlertAction) in
self.viewDidLoad()
})
alert.addAction(restartAction)
present(alert, animated: true, completion: nil)
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
activityIndicator.stopAnimating()
bgImage.stopAnimating()
bgImage.isHidden = true
}
}
What am I doing wrong? Please help.
You have to implement the webView(_:decidePolicyFor:decisionHandler:) function of WKNavigationDelegate protocol in order to allow following the links in your web view.
Here is the documentation
please use this webview as I shown in image
code:-
#IBOutlet weak var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
webView.delegate = self;
webView.loadRequest(URLRequest.init(url: URL(string: "https://mywebsite")!));
}
func webViewDidStartLoad(_ webView: UIWebView) {
SVProgressHUD.setDefaultMaskType(SVProgressHUDMaskType.custom)
SVProgressHUD.show();
}
func webViewDidFinishLoad(_ webView: UIWebView) {
SVProgressHUD.dismiss();
}

uiactivity and uiwebview delegate

I have a uiactivity view in my project.
I want to start animating while the page is loading and stop and hide when the webview finally loads.
this is not working in my case.
I have tried to use the UIWebViewDelegate, but it is deprecated.
class WebviewViewController: UIViewController {
#IBOutlet var webView: UIWebView!
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
let disposeBag = DisposeBag()
var specURL:String?
override func viewDidLoad() {
super.viewDidLoad()
configureUIActivityView()
_ = loadWebview()
.subscribe(onSuccess: { url in
DispatchQueue.main.async {
self.webView.loadRequest(URLRequest(url: url))
self.activityIndicator.stopAnimating()
self.activityIndicator.isHidden = true
}
})
}
func loadWebview() -> Single<URL> {
return Single<URL>.create { single in
guard let url = URL(string: self.specURL!.trimmingCharacters(in: .whitespacesAndNewlines)) else {
assertionFailure("no view available")
//single(.error(NetworkError.noImage))
return Disposables.create {}
}
single(.success(url))
return Disposables.create {}
}
}
}
It is better to use the WKWebView for achieving since as you mentioned that the UIWebViewDelegate is deprecated.
Here is a simple example for monitoring the loading status of the WKWebView using KVO.
import WebKit
class ViewController: UIViewController, WKUIDelegate {
private var webView: WKWebView!
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
view = webView
webView.addObserver(self, forKeyPath: "loading", options: .new, context: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
let myURL = URL(string: "http://www.apple.com")
let myRequest = URLRequest(url: myURL!)
webView.load(myRequest)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard let keyPath = keyPath, let change = change else { return }
switch keyPath {
case "loading":
if let loading = change[.newKey] as? Bool {
print("Is webview loading: \(loading)")
}
default:
break
}
}
deinit {
webView.removeObserver(self, forKeyPath: "loading")
}
}