Clear Cache in a web view Swift 3.3 - ios

New to programming, learning from Youtube and from You Guys ! Thanks a lot.
After intentionally entering wrong credentials on the webpage login inside the web view , the webpage normally shows an error of login. I added a reset button on the app interface to reload the MAIN WebApp web view.
It reloads and shows the same webpage login error. (instead of reloading the main webpage cache free to allow entering the proper credentials again)
I tried to add clear cache function with no success.
#IBAction func RefreshApp(_ sender: UIButton) {
viewdidload()
}
In viewdidload, i have included :
URLCache.shared.removeAllCachedResponses()
URLCache.shared.diskCapacity = 0
URLCache.shared.memoryCapacity = 0
with no success

This is working in Swift 3.1 , XCode 8.3.1 :
//Delete Cookies
if let cookies = HTTPCookieStorage.shared.cookies {
for cookie in cookies {
NSLog("\(cookie)")
}
}
let storage = HTTPCookieStorage.shared
for cookie in storage.cookies! {
storage.deleteCookie(cookie)
}

Related

How to send a message (tokens) from an iOS App to its Safari Extension?

I tried looking for a solution in posts such as this and this where people had a very similar problem: How to send a message from iOS App to a Safari Extension?
I even read this article where the author was explaining how to use SafariExtensionHandler to send a message from the browser to the app and back to the browser after selecting the context menu, but it's not quite what I was looking for.
Sending a Token from iOS App to Safari Extension
In the app, the user has to enter an email and password to log into their account. Once they log in, I save their information in UserDefaults like this:
class AuthDataService {
{...}
URLSession.shared.dataTaskPublisher(for: urlRequest)
.tryMap { data, response -> Data in
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200,
let accessToken = httpResponse.value(forHTTPHeaderField: "Access-Token"),
let clientId = httpResponse.value(forHTTPHeaderField: "Client"),
let uid = httpResponse.value(forHTTPHeaderField: "Uid")
else {
throw CustomError.cannotExecuteRequest
}
let sharedDefaults = UserDefaults(suiteName: "group.com.MyCompany.MyProject")
sharedDefaults?.set(accessToken, forKey: "Access-Token")
sharedDefaults?.set(clientId, forKey: "Client")
sharedDefaults?.set(uid, forKey: "Uid")
return data
}
{...}
}
App-Group
From my understanding of this article, I need to create an App Group, in order to share the data between the iOS App and the Safari Extension. I named the group: "group.com.MyCompany.MyProject" (just like the suiteName in UserDefaults).
Home View
The screen that the user sees when they log in, is a SwiftUI View that has a Link which takes the user to Safari so they can open the extension themselves:
struct HomeView: View {
#EnvironmentObject var viewModel: AuthViewModel
var body: some View {
Link(destination: URL(string: "https://www.apple.com/")!) {
Text("Take me to Safari")
}
}
}
SafariWebExtensionHandler
Now, all the articles that I read were talking about how to send data from the Safari Extension to the iOS app through SafariWebExtensionHandler's beginRequest(with:).
However, I'm trying to send the Tokens in UserDefaults either whenever the user logs in the app, or when they open the Safari Extension.
I tried retrieving the data from UserDefaults to see if I could at least read it in the terminal, but the debugger never gets to the print statements:
import SafariServices
import os.log
let SFExtensionMessageKey = "message"
class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling {
func readData() {
let sharedDefaults = UserDefaults(suiteName: "group.com.lever.clientTokens")
print(sharedDefaults?.object(forKey: "Access-Token")) //<-- This line never gets executed
}
func beginRequest(with context: NSExtensionContext) {
let item = context.inputItems[0] as! NSExtensionItem
let message = item.userInfo?[SFExtensionMessageKey]
os_log(.default, "Received message from browser.runtime.sendNativeMessage: %#", message as! CVarArg)
let response = NSExtensionItem()
response.userInfo = [ SFExtensionMessageKey: [ "Response to": message ] ]
readData()
context.completeRequest(returningItems: [response], completionHandler: nil)
}
}
Question
macOS vs iOS
This documentation from Apple has a section called Send messages from the app to JavaScript which is pretty much what I want to do. The documentation even mentions SFSafariApplication.dispatchMessage(withName:toExtensionWithIdentifier:userInfo:completionHandler:) which in theory sends a message to the JavaScript script, but it says it only works in macOS:
You can’t send messages from a containing iOS app to your web
extension’s JavaScript scripts.
This excellent Medium article talks about sending an APIKey from the app to the Safari Extension using an API from openai.com. It seems that it also uses SFSafariApplication to communicate with SafariWebExtensionHandler, but again it looks like it only works for macOS.
Safari Extension to webPage
I also read this other Apple documentation thinking it would help, but it only talks about passing messages from the Safari Extension's popup to the webpage.
Conclusion
So my question is:
Is writing code in SafariWebExtensionHandler the right way to send data from the iOS App to my Safari Extension? Can this be done in iOS? Or is it only available for macOS?
I read some other articles that were talking about using the JavaScript files in the Resources folder in order to "listen" to changes. But I'm a little confused as to how I can send those changes from my App in order for the Safari Extension to listen to them.
What I am trying to achieve is for the user to be already logged-in in the Safari Extension after they are redirected from the HomeView in the iOS App, instead of having to sign in another time.
Thank you for your time and help!

WKWebView does not open https://itunes.apple.com/app/id123456 link

Here is a little problem I just noticed in one of my iOS apps.
I use Xcode Version 10.1 and Swift 4.2.
The app has a button which when pushed brings up a view controller, this VC is in charge of opening a link to the app itself in itunes. I have done this many times with no problems in the past.
But this time, a blank pages opens up and nothing else. I have tried to replace only the URL I am interested in by "https://www.google.com/" and it works perfectly as expected (i.e. the Google page shows up). Of course I have verified that my URL is correct.
Can anybody see what could be the issue?
Thanks in advance for any relevant tip.
Here is the code for the whole view controller.
import UIKit
import WebKit
class appStore_ViewController: UIViewController, WKNavigationDelegate {
let appDelegate:AppDelegate = UIApplication.shared.delegate as! AppDelegate
var webView: WKWebView!
override func loadView() {
webView = WKWebView()
webView.navigationDelegate = self
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
let appStoreURL = URL(string: "https://itunes.apple.com/app/id\ (appDelegate.applicationID)?mt=8")
//let appStoreURL = URL(string: "https://www.google.com/") // This works as expected.
print("The link: \(appStoreURL!.absoluteString)") // This shows what is expected (a working URL).
webView.load(URLRequest(url: appStoreURL!))
}
}
You should see what happen while visiting the AppStore Url with safari browser in your iPhone. then you will find the it still show blank page but show an alert to open the Appstore.
If you want to do the same function in your app with webView. you have to handle the alert the by yourself.
You need to implement the decidePolicyForNavigationAction method of WKNavigationDelegate for this to work.
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)
(WKNavigationActionPolicy))decisionHandler {
/* Code to handle other schemes such as file, https, http, etc. if required
*/
if ([[[navigationAction.request URL] scheme] isEqual:#"itms-appss"])
{
[[UIApplication sharedApplication] openURL:[navigationAction.request URL]];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
}
WKWebview does not inherently support different schemes such as "itms-appss" and you need to check and implement the url scheme you want to support.
You also need to check if you are running in iPadOS and set WKWebpagePreference to use mobile content mode if you do so.

Xamarin IoS 12 update: WKWebView custom renderer issue

I'm facing with a very weird issue with a Xamarin Forms application on IoS after the latest OS update. Basically this application uses a WebView renderer to navigate a company's intranet portal which has NTLM authentication. I implemented the web renderer to handle the authentication process and it was working fine till few week ago but after Apple's last update the webview has stopped working.
Unfortunately there is no error code, exception or explicit message from the SDK, and the authentication process is working (I can see it from the logs), by the way the webview's content is all blank.
I have tried to navigate to other websites (with no authentication) too (bing.com, google.com, xamarin.com) but the issue was still there.
Anyone has some suggestion or hint?
UPDATE
After a deep investigation I've finally found the problem! Actually it seems that after the deprecation of UIWebview when using a custom renderer to handle authentication scenarios you cannot skip the HTTP 200 response (as suggested before) otherwise the component won't load the html contents!
So this is what I had before in my custom renderer:
public override void DecidePolicy(WKWebView webView, WKNavigationResponse navigationResponse, Action<WKNavigationResponsePolicy> decisionHandler)
{
var url = navigationResponse?.Response?.Url;
if (url == null) return;
if (navigationResponse.Response is NSHttpUrlResponse)
{
var resp = navigationResponse.Response as NSHttpUrlResponse;
if (resp.StatusCode == 200) return;
HandleHttpResponse(resp);
decisionHandler(WKNavigationResponsePolicy.Allow);
}
else if (navigationResponse.Response is NSUrlResponse)
{
//todo handle this case too if we want to open excel files in webview
//UIApplication.SharedApplication.OpenUrl(url);
decisionHandler(WKNavigationResponsePolicy.Cancel);
}
}
and this is what I have changed:
var resp = navigationResponse.Response as NSHttpUrlResponse;
//if (resp.StatusCode == 200) return;
HandleHttpResponse(resp);
decisionHandler(WKNavigationResponsePolicy.Allow);
Just commenting the if for StatusCode 200 and let contine with decisionHandler it works... Very very weird!

How to session Expire in UIWebview in Swift 3?

i want to logout from the webview after logged in uiwebview but some Sites Provides Logout Button to Logout ,
and Some Website Or Blogs have not Logout button So i want To switch User With Same Device And Same Webview Without Delete App.
So Any Idea About To Clear Session Or Expire Session From WebView. Because M using UiWebview
If you want to clear the cashed data in the web view:
func clearCookies()
{
if let cookies = HTTPCookieStorage.shared.cookies
{
URLCache.shared.removeAllCachedResponses()
URLCache.shared.diskCapacity = 0
URLCache.shared.memoryCapacity = 0
for cookie in cookies
{
HTTPCookieStorage.shared.deleteCookie(cookie)
}
}
}

Login impossible with Spotify iOS 9

I can't login with ios sdk spotify.
I followed the Brian's tutorial (https://www.youtube.com/watch?v=GeO00YdJ3cE) and there is a difference with the current spotify tutorial :
In the video it talks about token exchange and show a spotify webpage. However on current spotify webpage the paragraph is missing.
Does this exchange token must be installed ?
I defined all elements in my spotify app account.
I also defined in the URL schemes : "spotify-action", "my-app-Name" but I can't sucess login.
Anyone help please ?
There are two options:
1) Implicit Grant Flow - grants users access tokens that will expire in 60 minutes - it is much simpler but has it's limits if you want to build a usable application. I will give you a simple example with spotify's updated sdk framework (you don't have to use safari)..
class ViewController: UIViewController, SPTAuthViewDelegate {
let kclientID = ""
let kcallbackURL = ""
#IBAction func loginSpotify(sender: AnyObject){
SPTAuth.defaultInstance().clientID = kclientID
SPTAuth.defaultInstance().redirectURL = NSURL(string: kcallbackURL)
SPTAuth.defaultInstance().requestedScopes = [SPTAuthStreamingScope]
SPTAuth.defaultInstance().sessionUserDefaultsKey = "SpotifySession"
SPTAuth.defaultInstance().tokenSwapURL = NSURL(string: ktokenSwapURL) //you will not need this initially, unless you want to refresh tokens
SPTAuth.defaultInstance().tokenRefreshURL = NSURL(string: ktokenRefreshServiceURL)//you will not need this unless you want to refresh tokens
spotifyAuthViewController = SPTAuthViewController.authenticationViewController()
spotifyAuthViewController.delegate = self
spotifyAuthViewController.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
spotifyAuthViewController.definesPresentationContext = true
presentViewController(spotifyAuthViewController, animated: false, completion: nil)
}
func authenticationViewController(authenticationViewController: SPTAuthViewController!, didLoginWithSession session: SPTSession!) {
print("Logged In")
}
func authenticationViewController(authenticationViewController: SPTAuthViewController!, didFailToLogin error: NSError!) {
print("Failed to Log In")
print(error)
authenticationViewController.clearCookies(nil)
}
func authenticationViewControllerDidCancelLogin(authenticationViewController: SPTAuthViewController!) {
print("User Canceled Log In")
authenticationViewController.clearCookies(nil)
}
}
2) Authorization Code Flow - Spotify's authentication server sends an encrypted refresh token which you store, for example,
SPTAuth.defaultInstance().sessionUserDefaultsKey = "SpotifySession". When that sessions expires you must trigger a function on your server... Hope this helps you get started

Resources