Why WKWebView not returning all cookies? - ios

Hi I replaced UIWebview with WKWebview. Because on multiple frame loading UIWebview keyborad is dismissing. So i used WKWebView. my issue was gone now.
But on WKWebView im not getting cookies. it is returning only JSESSIONID cookie, Where as on UIWebView im getting all the cookies.
Please help me on this.
Here is my code snippet for start WKWebView.
func startWebView() {
URLCache.shared.removeAllCachedResponses()
if webView == nil {
let source =
"var meta = document.createElement('meta'); " +
"meta.name = 'viewport'; " +
"meta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'; " +
"var head = document.getElementsByTagName('head')[0]; " +
"head.appendChild(meta);"
let script = WKUserScript(source:source,
injectionTime: .atDocumentEnd,
forMainFrameOnly: true)
let userContentController = WKUserContentController()
userContentController.addUserScript(script)
let configuration = WKWebViewConfiguration()
configuration.userContentController = userContentController
let prefs = WKPreferences()
prefs.javaScriptEnabled = true
configuration.preferences = prefs
webView = WKWebView(frame: CGRect.zero, configuration: configuration)
webView.navigationDelegate = self
webView.allowsBackForwardNavigationGestures = true
webContainerView.addSubview(webView)
webView.translatesAutoresizingMaskIntoConstraints = false
let vdict = ["WV": webView!]
webContainerView.addConstraints(
NSLayoutConstraint.constraints(withVisualFormat: "H:|[WV]|",
options: [], metrics: nil,
views: vdict)
)
webContainerView.addConstraints(
NSLayoutConstraint.constraints(withVisualFormat: "V:|[WV]|",
options: [], metrics: nil,
views: vdict)
)
}
var urlstr = LoginServer.url.absoluteString
//#if DEBUG
let url : URL = URL(string: urlstr)!
var urlRequest = URLRequest(url: url,
cachePolicy: NSURLRequest.CachePolicy.reloadIgnoringLocalCacheData,
timeoutInterval: 60.0)
if Reachability.shared.isNetworkAvailable(){
urlRequest.cachePolicy = .reloadRevalidatingCacheData
_ = webView.load(urlRequest)
}
else{
loadingIndicator.stopAnimating()
loadingIndicator.isHidden = true
}
}
Here is the code for fetch cookies
func webView(_ webView: WKWebView,
decidePolicyFor navigationResponse: WKNavigationResponse,
decisionHandler: #escaping (WKNavigationResponsePolicy) -> Swift.Void)
{
if let httpResponse = navigationResponse.response as? HTTPURLResponse {
if let headers = httpResponse.allHeaderFields as? [String: String], let url = httpResponse.url {
let cookies = HTTPCookie.cookies(withResponseHeaderFields: headers, for: url)
for cookie in cookies {
print(cookie.description)
print("found cookie " + cookie.name + " " + cookie.value)
}
}
}
decisionHandler(.allow)
}

You should be able to access all the cookies with the following code
let cookies = HTTPCookieStorage.shared.cookies
for cookie in cookies! {
print(cookie.description)
print("found cookie " + cookie.name + " " + cookie.value)
}
Below is a summary of my web view controller
class MyWebViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler {
override func viewDidLoad() {
super.viewDidLoad()
// create WKWebViewConfiguration
let webViewConfig = WKWebViewConfiguration()
let userContentController = WKUserContentController();
userContentController.add(self, name: "myApp")
webViewConfig.userContentController = userContentController
// init and load request in webview.
webView = WKWebView(frame: self.view.frame, configuration:webViewConfig)
webView.navigationDelegate = self
webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.view.addSubview(webView)
let request = URLRequest(url: webAddress)
webView.load(request)
}
//
// WKNavigationDelegate
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler:#escaping ((WKNavigationActionPolicy) -> Void)) {
print("decidePolicyForNavigationAction with url:\(String(describing: navigationAction.request.url!))")
if let url = navigationAction.request.url {
// url request is outside of my website, then use safari to view address
if webAddress.host != url.host {
UIApplication.shared.open(url)
decisionHandler(.cancel)
}
}
decisionHandler(.allow)
}
func webView(_ webView: WKWebView,
decidePolicyFor navigationResponse: WKNavigationResponse,
decisionHandler: #escaping (WKNavigationResponsePolicy) -> Swift.Void)
{
let cookies = HTTPCookieStorage.shared.cookies
for cookie in cookies! {
print(cookie.description)
print("found cookie " + cookie.name + " " + cookie.value)
}
decisionHandler(.allow)
}
func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
print("Navigation error :\(error.localizedDescription)")
}
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
print("Loading error :\(error.localizedDescription)")
}
//
// WKScriptMessageHandler
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
}
var webView: WKWebView!
var config = ResolveConfig()
let webAddress = URL(string:"https://mywebaddr.com")!
}

Related

Checking if request URL contains swift webview

I am trying to check if the URL contains "external" something like "www.example.com/?external=1" then it should open in a external browser otherwise open locally below is the code please help me to get this fix. Thanks
class ViewController: UIViewController, WKNavigationDelegate {
let webView = WKWebView()
override func viewDidLoad() {
super.viewDidLoad()
webView.frame = view.bounds
webView.navigationDelegate = self
let url = URL(string: "https://www.example.com")!
let urlRequest = URLRequest(url: url)
webView.load(urlRequest)
webView.autoresizingMask = [.flexibleWidth,.flexibleHeight]
view.addSubview(webView)
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
if navigationAction.navigationType == .linkActivated {
if let url = navigationAction.request.url,
let host = url.host, !host.hasPrefix("external"),
UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
print(url)
print("Redirected to browser. No need to open it locally")
decisionHandler(.cancel)
return
} else {
print("Open it locally")
decisionHandler(.allow)
return
}
} else {
print("not a user click")
decisionHandler(.allow)
return
}
}
}
I tried to change the code like:
url.hasPrefix("external")
But it's giving error "Value of type URL has no member 'hasPrefix'"

How to show call dialog when click on action tag?

[![enter image description here][1]][1]
[1]: https://i.stack.imgur.com/7FUgg.png
I want to open a phone number Alertsheet (like + 91-1234567890) when click call button(phone icon).
my image shows page of web, which is called in my app and i have use WebKit in my code.
what i have tried,
i'm new to webkit help me out.
import UIKit
import WebKit
import Alamofire
class ContinueViewController: UIViewController, WKUIDelegate {
func getPostString(params:[String:Any]) -> String{
var data = [String]()
for(key, value) in params
{
data.append(key + "=\(value)")
}
return data.map { String($0) }.joined(separator: "&")
}
#IBOutlet weak var activityView: UIActivityIndicatorView!
#IBOutlet weak var webview: WKWebView!
var url: URL?
var id = 0, skill = 0
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if #available(iOS 14.0, *) {
webview.configuration.defaultWebpagePreferences.allowsContentJavaScript = true
}else {
let preferences = WKPreferences()
preferences.javaScriptEnabled = true
let configuration = WKWebViewConfiguration()
configuration.websiteDataStore = WKWebsiteDataStore.nonPersistent()
configuration.preferences = preferences
}
webview.navigationDelegate = self
self.navigationController?.navigationBar.isHidden = true
webview.uiDelegate = self
}
override func viewDidLoad() {
super.viewDidLoad()
activityView.startAnimating()
guard let url = self.url else { return }
var req = URLRequest(url: url)
let params = ["id" : id,"skill" : skill]
let postString = self.getPostString(params: params)
req.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
req.httpMethod = "POST"
req.httpBody = postString.data(using: .utf8)
self.webview.load(req)
}
}
extension ContinueViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
activityView.stopAnimating()
}
}
In your WKNavigationDelegate implementation, you can do something like the following:
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
if let url = navigationAction.request.url, url.scheme == "tel" {
UIApplication.shared.open(url)
decisionHandler(.cancel)
}else {
decisionHandler(.allow)
}
}

How to fetch cookies values from WKWebView in Swift 4?

I'm not able to get cookies from this website - "https://bødekontrol.dk"
I'm using Xcode 9.4.1 and iOS 11.
I have followed below code,
import UIKit
import WebKit
class ViewController: UIViewController {
var urlString = "https://bødekontrol.dk"
var webView: WKWebView!
fileprivate var webViewIsInited = false
override func viewWillLayoutSubviews() {
if !webViewIsInited {
webViewIsInited = true
if webView == nil {
webView = WKWebView(frame: UIScreen.main.bounds, configuration: WKWebViewConfiguration())
}
view.addSubview(webView)
webView.navigationDelegate = self
webView.uiDelegate = self
webView.loadUrl(string: urlString)
}
}
}
extension ViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: #escaping (WKNavigationResponsePolicy) -> Void) {
decisionHandler(.allow)
if let httpResponse = navigationResponse.response as? HTTPURLResponse {
if let headers = httpResponse.allHeaderFields as? [String: String], let url = httpResponse.url {
let cookies = HTTPCookie.cookies(withResponseHeaderFields: headers, for: url)
for cookie in cookies {
print(cookie.description)
print("found cookie " + cookie.name + " " + cookie.value)
}
}
}
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
print("didFinish navigation")
}
}
extension ViewController: WKUIDelegate {
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 ?? "http://google.com"
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
}
}
extension WKWebView {
func loadUrl(string: String) {
if let encoded = string.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
let url = URL(string: encoded)
{
if self.url?.host == url.host {
self.reload()
} else {
load(URLRequest(url: url))
}
}
}
}
Implement this protocol WKHTTPCookieStoreObserver and check function of this protocol.
cookiesDidChange

Allow document upload in input file on WKWebView

I have an html input type="file" upload form on a page loaded through wkwebview, and I'm trying to allow the ability to upload common document files (pdf, docx, etc). Currently I have the ability to take pictures and browse for images, but documents are greyed out and unavailable. I'm a web developer, and swift is greek to me, so any help would be greatly appreciated!
Here is my view controller
import UIKit
import WebKit
import IJProgressView
import FirebaseMessaging
class ViewController: UIViewController, WKNavigationDelegate {
let webView = WKWebView()
var initialstart = true
override func viewDidLoad() {
webView.backgroundColor = UIColor(red:0.17, green:0.24, blue:0.31, alpha:1.0)
webView.isOpaque = false
webView.allowsBackForwardNavigationGestures = true
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.receivedUrlFromPushNotification(notification:)), name: NSNotification.Name(rawValue: "ReceivedPushNotification"), object: nil)
// Do any additional setup after loading the view, typically from a nib.
guard let url = URL(string: "https://www.website.com/users/account") else { return};
webView.frame = view.bounds;
webView.navigationDelegate = self;
webView.load(URLRequest(url: url));
webView.autoresizingMask = [.flexibleWidth, .flexibleHeight];
view.addSubview(webView)
}
func receivedUrlFromPushNotification (notification: Notification) {
let notification: [AnyHashable : Any] = notification.userInfo!
let url = URL(string: notification["url"] as! String);
webView.load(URLRequest(url: url!))
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
if navigationAction.navigationType == .linkActivated {
if let url = navigationAction.request.url,
let host = url.host, !host.hasPrefix("www.website.com"),
UIApplication.shared.canOpenURL(url) {
if #available(iOS 10.0, *) {
UIApplication.shared.open(url)
} else {
// Fallback on earlier versions
UIApplication.shared.openURL(url)
}
decisionHandler(.cancel)
} else {
decisionHandler(.allow)
}
} else {
decisionHandler(.allow)
}
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
let url = webView.url;
let path = url?.path;
UIApplication.shared.isNetworkActivityIndicatorVisible = false
IJProgressView.shared.hideProgressView()
view.isOpaque = true
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
if (initialstart == true) {
initialstart = false
} else {
UIApplication.shared.isNetworkActivityIndicatorVisible = true
IJProgressView.shared.showProgressView(view)
}
}
}
For OSX, You can try to implement the delegate method
runOpenPanelWithParameters. It is a WKUIDelegate method.
Check the accepted answer for a similar question: Input type=file not working in WebView of OS X application
In my case, after file gets uploaded, the page was getting redirected to the base url.The problem was that I was calling
webview.load(request)
from the viewDidAppear() function.
Moving the call to the viewDidLoad() fixed my problem.
Click here to see more details

Some WKWebView links not clickable

I am having a challenge with a WKWebView-based iOS application: some of the links on the page are not clickable. When I try them with a Safari view controller, they work. Please can anyone help me?
This is my source code:
import UIKit
import WebKit
class ViewController: UIViewController, WKUIDelegate, WKNavigationDelegate {
var webView: WKWebView! //declare the webview has to be optional
var activityIndicator: UIActivityIndicatorView!
override func loadView() {
super.loadView()
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
webView.navigationDelegate = self
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
let myURL = URL(string: "https://stolenandfound.com/")
let myRequest = URLRequest(url: myURL!)
webView.load(myRequest)
activityIndicator = UIActivityIndicatorView() //declare the progress indicator
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 = (UIViewAutoresizing(rawValue: UIViewAutoresizing.RawValue(UInt8(UIViewAutoresizing.flexibleRightMargin.rawValue) | UInt8(UIViewAutoresizing.flexibleLeftMargin.rawValue) | UInt8(UIViewAutoresizing.flexibleBottomMargin.rawValue) | UInt8(UIViewAutoresizing.flexibleTopMargin.rawValue))))
//activityIndicator.center = CGPoint(x: UIScreen.main.bounds.size.width/2, y: UIScreen.main.bounds.size.height/2)
activityIndicator.hidesWhenStopped = true
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.whiteLarge
activityIndicator.color = UIColor.darkGray
self.view.addSubview(activityIndicator)
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
activityIndicator.startAnimating()
}
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
print("it is an error")
activityIndicator.stopAnimating()
let alert = UIAlertController(title: "Network Error", message: "You have no internet coonection", 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()
}
#IBAction func backButton(_ sender: UIBarButtonItem) {
webView.goBack()
}
#IBAction func refreshButton(_ sender: UIBarButtonItem) {
webView.reload()
}
}
If the links open in a new tab in Safari, you will have to implement the WKUIDelegate function func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? and handle the request there. At that point you can load the request in the existing webView or create a new webView or open it in Safari.
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
guard let theURL = navigationAction.request.url else {
return nil
}
if loadInCurrentWebview{
_ = webView.load(navigationAction.request) //loads the link in the current webView
} else if loadInNewWebview{
return WKWebView()
}else {
//loads in safari
if #available(iOS 10.0, *) {
UIApplication.shared.open(theURL, options: [:], completionHandler: nil)
} else {
UIApplication.shared.openURL(theURL)
}
}
return nil
}

Resources