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")
}
}
Related
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
}
Given the code below. I can't get the web page "https://baycare.clearstep.health/covid19" to show up. It shows up okay in Safari and I can get other pages to show up in the WKWebView. I have tried implementing all of the navigation and ui delegate methods to try and track down the problem but have failed to find anything.
The URL used to work, but the company has changed something and now it doesn't. Any help is appreciated.
The below is a complete program:
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let controller = UIViewController()
.setup { viewController in
WKWebView(frame: viewController.view.bounds)
.setup {
viewController.view.addSubview($0)
$0.uiDelegate = WebViewUIDelegate.instance
$0.navigationDelegate = WebViewDelegate.instance
$0.autoresizingMask = [.flexibleWidth, .flexibleHeight]
$0.load(URLRequest(url: URL(string: "https://baycare.clearstep.health/covid19")!))
}
}
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = controller
window?.makeKeyAndVisible()
return true
}
}
extension NSObjectProtocol {
#discardableResult
func setup(_ fn: (Self) -> Void) -> Self {
fn(self)
return self
}
}
final class WebViewUIDelegate: NSObject, WKUIDelegate {
static let instance = WebViewUIDelegate()
}
final class WebViewDelegate: NSObject, WKNavigationDelegate {
static let instance = WebViewDelegate()
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
print("This doesn't fire so no error?", error)
}
}
WKWebView is depricated version but still webview will works fine, I had same issue and I was doing same but then instead of WKWenView I used web view
import UIKit
import WebKit
class PolicyVC: UIViewController {
#IBOutlet weak var webView: UIWebView!
var isPolicyView = false
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(type: UIButton.ButtonType.custom)
button.setImage(UIImage(named: "ic_arrow_left"), for: .normal)
button.addTarget(self, action:#selector(popView), for: .touchUpInside)
button.frame=CGRect(x: 0, y: 0, width: 20, height: 20)
let barButton = UIBarButtonItem(customView: button)
self.navigationItem.leftBarButtonItems = [barButton]
setUpUI()
}
#objc func popView(){
self.navigationController?.popViewController(animated: true)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.navigationBar.isTranslucent = true
self.navigationController?.navigationBar.isHidden = false
self.navigationController?.navigationBar.backgroundColor = .black
}
func setUpUI(){
if isPolicyView{
let url = URL(string: "https://www.termsfeed.com/privacy-policy/68c4cdaeba7e146a7d72bf57654520e7")
let urlRequest = URLRequest(url: url!)
webView.loadRequest(urlRequest)
}else{
let url = URL(string: "https://www.termsfeed.com/terms-conditions/0001db2c7a1061a55e2f933bb94102de")
let urlRequest = URLRequest(url: url!)
webView.loadRequest(urlRequest)
}
}
}
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 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 ?
Can I open a link using the button and textfield on which the link is listed on another page within the app itself and not with Safari?
I'm using Swift 4
You have to open webview in destination view controller and send url string from first view controller to destination like below:
class ViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
#IBAction func action(_ sender: Any) {
if let mainVC = storyboard?.instantiateViewController(withIdentifier: "second") as? DestinationViewController {
mainVC.urlStr = textField.text
self.navigationController?.pushViewController(mainVC, animated: true)
}
}
}
Destination View controller:
class DestinationViewController: UIViewController {
var urlStr: String?
override func viewDidLoad() {
super.viewDidLoad()
let webView = UIWebView(frame: self.view.frame)
self.view.addSubview(webView)
if let urlString = urlStr, let url = URL(string: urlString) {
webView.loadRequest(URLRequest(url: url))
}
}
}
Just Use WKWebView to open the link on Button action using this
Import WebKit
import WebKit
In your FirstViewController pass the URL while pushing to
SecondViewController
FirstViewController
if let secondVC = (UIStoryboard.init(name: "Main", bundle: nil)).instantiateViewController(withIdentifier: "secondVCID") {
secondVC.url = textFiled.text // OR send the URL you want to send
self.navigationController?.pushViewController(secondVC, animated: true)
}
In SecondViewController
Import Webkit
declare the delegate
class SecondViewController: UIViewController,WKNavigationDelegate {
declare the URL var so that u cab access it n FirstVC
var url: String?
#IBOutlet weak var webView: WKWebView!
In ViewDidLoad Of SecondVC
let webUrl = NSURL(string: url!)
let request = NSURLRequest(URL: webUrl)
// load request in webview.
webView.navigationDelegate = self
webView.loadRequest(request)
and Implement all delegate methods of WKWebview
//MARK:- WKNavigationDelegate
func webView(webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: NSError) {
print(error.localizedDescription)
}
func webView(webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
print("Strat to load")
}
func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) {
print("finish to load")
}