I have this in my Appdelegate.swift
case .reddit:
if (url.host == "oauth-callback") {
AuthorizationManager.removeRedditToken()
print("Oauth Request..")
let urlc = URLComponents(url: url, resolvingAgainstBaseURL: false)
let bearerToken = urlc?.queryItems?.first(where: { $0.name == "code" })?.value
let tokenPromise = TokenManager.sharedInstance.fetchAccesTokenPromise(withBearerToken: bearerToken ?? "")
tokenPromise.done { (token) in
TokenManager.sharedInstance.accessToken = token.accessToken
TokenManager.sharedInstance.refrestToken = token.refreshToken
print("Access Token")
print(token.accessToken)
print("_______")
print(token.refreshToken)
AuthorizationManager.saveRedditToken(token: token.accessToken)
AuthorizationManager.saveRedditRefreshToken(token: token.refreshToken!)
}.catch { (error) in
print(error)
}
And I want to close the web view that opens during the open url function, but I can't figure out how to do it. The only way the Web View dismisses is by pressing "Done". It should close when I receive successfully the token. Dunno what can I do
Related
Here is the code I currently have however, it does not seem to be working. This example says I want to open the calc app. My goal is to open an app once a widget is clicked.
#main App Code:
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL { url in
print("Received deep link: \(url)")
}
}
}
Widget Code:
Gauge(value: 50), in: 0.0...100.0) {
} currentValueLabel: {
Text(Open App)
}
.gaugeStyle(.accessoryCircularCapacity)
.widgetURL(URL(string: "calc://")!)
Then you need to do this in a 2 step process. First, you need to set up your app to receive custom URLs from your widget. This is shockingly well explained by Apple here. Once you have your app's custom url scheme set up, it is time to set up your widget. Essentially what you are going to do is send a URL with a query that is the URL you want to open. Back in your app, you receive that URL, parse it out, and then call openUrl() with the URL you want to open, and that app will open.
Your code above is close. Following Apple's example above, try this:
In your widget create a deep link URL:
func createDeeplinkForCalc() -> URL {
var components = URLComponents()
components.scheme = "myphotoapp"
components.host = "com.example.myphotoapp"
components.path = "/calc"
components.queryItems = [
URLQueryItem(name: "open", value: "calc://")
]
return components.url!
}
Then, in .widgetURL, pass this:
.widgetURL(createDeeplinkForCalc())
In your main app:
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL { url in
handleURL(url: URL)
}
}
}
func handleURL(_ url:URL) {
// This makes sure you got the correct URL
guard url.scheme == "myphotoapp",
url.host == "com.example.myphotoapp"
else { return }
let query = parseQuery(url: url)
guard let urlString = query["open"],
!urlString.isEmpty else { return } // make sure something exists in the value
if let calcURL = URL(string: urlString) {
openURL(calcURL) // this calls "calc://" and opens the calculator
}
private func parseQuery(url: URL) -> Query {
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true),
let queryItems = components.queryItems
else { return ["":""] }
return queryItems.reduce(into: Query()) { (result, item) in
result[item.name] = item.value
}
}
}
The above has not been tested, but should work.
I made app which login in SFSafariViewController. It works well when login. but after I logout if I try to login it again, I'm already logged in. This is because my automatic login information is stored in SFSafariViewController. I tried to delete cache and cookies but it doesn't work. :(
this is my login code.
func requestCode() {
let scope = "user"
let urlString = "https://github.com/login/oauth/authorize?client_id=\(clientId)&scope=\(scope)"
guard let url = URL(string: urlString) else {
return
}
URLCache.shared.removeAllCachedResponses()
if let cookies = HTTPCookieStorage.shared.cookies {
for cookie in cookies {
HTTPCookieStorage.shared.deleteCookie(cookie)
}
}
let safariViewController = SFSafariViewController(url: url)
safariViewController.delegate = self
safariViewController.modalPresentationStyle = .automatic
if let topViewController = UIApplication.shared.connectedScenes.compactMap({ $0 as? UIWindowScene }).flatMap({ $0.windows }).first(where: { $0.isKeyWindow }) {
topViewController.rootViewController?.present(safariViewController, animated: true, completion: nil)
}
}
prefersEphemeralWebBrowserSession = true
it makes your browser to private mode!!!
so you don't need to logout.
I am using scheme in my app to pass data from a second app to my app.
I am already able to open my app using it's scheme from second app.
But now I will like to parse the URL data that was sent from the second app. I found a tutorial online about implementing a method as seen below in my viewController class but this method is never triggered. Do i need to place it somewhere specific ? right now it's just in the viewController class.
I just started coding in Swift this week to create a POC, I have more of an Android background.
func application(app: UIApplication,
open url: URL,
options: [UIApplication.OpenURLOptionsKey : Any] = [:] ) -> Bool {
// Determine who sent the URL.
let sendingAppID = options[.sourceApplication]
print("source application = \(sendingAppID ?? "Unknown")")
// Process the URL.
guard let components = NSURLComponents(url: url, resolvingAgainstBaseURL: true),
// let ro_response = components.path,
let params = components.queryItems else {
print("Invalid")
return false
}
if let serial = params.first(where: { $0.name == "serial" })?.value {
self.SERIAL = serial as String
} else {
return false;
}
if let otp = params.first(where: { $0.name == "otp" })?.value {
self.OTP = otp as String
} else {
return false;
}
return true
}
This is a method from UIApplicationDelegate so you have to implement it in your AppDelegate.
I am working in the edit profile portion of my application. When I try to change and update a users profile photo. The app crashes and I get this error
reason: 'URL scheme must be one of gs://, http://, or https://
When I create a new profile and add a profile photo or if I upload a photo it works fine but when I try to change the profile photo I get this. It will first remove the profile photo and update ( leaving the image view gray when a user doesn't have a photo) then when I try to rechange the photo again it will crash.
Here is the code I have.
func updateProfileImage() {
guard imageChanged == true else { return }
guard let currentUid = Auth.auth().currentUser?.uid else { return }
guard let user = self.user else { return }
Storage.storage().reference(forURL: user.profileImageUrl).delete(completion: nil)
let filename = NSUUID().uuidString
guard let updatedProfileImage = profileImageView.image else { return }
guard let imageData = updatedProfileImage.jpegData(compressionQuality: 0.3) else { return }
STORAGE_PROFILE_IMAGES_REF.child(filename).putData(imageData, metadata: nil) { (metadata, error) in
if let error = error {
print("Failed to upload image to storage with error: ", error.localizedDescription)
}
STORAGE_PROFILE_IMAGES_REF.downloadURL(completion: { (url, error) in
USER_REF.child(currentUid).child("profileImageUrl").setValue(url?.absoluteString, withCompletionBlock: { (err, ref) in
guard let userProfileController = self.userProfileController else { return }
userProfileController.fetchCurrentUserData()
self.dismiss(animated: true, completion: nil)
})
})
}
}
}
The first thing you check URL is valid or not using a guard.
guard let urlis = yourUrl else{
// url is nill.
return
}
if let url = NSURL(string: urlis) {
// your image code
}
else{
// url is invalid.
return
}
Add Exception Breakpoint: This quick tip will save you a lot of debugging time!. So Xcode will stop where the exception is caught.
In your project, go to the Breakpoint Navigator, click on the ’+’ button and ’Add Exception Breakpoint…’
I am developing an App for the iPhone using Xwebview which enables me to download a page then interact with the javascript on the downloaded page.
All works, but if the internet connection drops, a default local page is loaded, informing the user there is no internet connection. The page displays a retry button that, when pressed checks, the internet connection: if the connection is made the app tries to connect again to the external page and load the page into the webview.
I cannot get this to work: the code downloads the page (I can see this in my session data) but I can't get that page to load back into the webview.
override func viewDidLoad() {
super.viewDidLoad()
login()
}
func login()
{
// *********** Get stored hashkey **************
let hashcode = getHashcode()
// ********** Check network connection *********
let netConnection = Connection.isConnectedToNetwork()
print("net connection: ", netConnection)
if netConnection == true
{
if hashcode != "00000"
{
print("local key found", hashcode)
// We dont have local key
let webview = WKWebView(frame: view.frame, configuration: WKWebViewConfiguration())
//webview.loadRequest(NSURLRequest(URL: NSURL(string: "about:blank")!))
view.addSubview(webview)
webview.loadPlugin(jsapi(), namespace: "jsapi")
let url:NSURL = NSURL(string: serverLocation + onlineLoginApi)!
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringCacheData
let paramString = "/?username=username&password=password"
request.HTTPBody = paramString.dataUsingEncoding(NSUTF8StringEncoding)
let task = session.downloadTaskWithRequest(request) {
(
let location, let response, let error) in
guard let _:NSURL = location, let _:NSURLResponse = response where error == nil else {
print("error")
return
}
let urlContents = try! NSString(contentsOfURL: location!, encoding: NSUTF8StringEncoding)
guard let _:NSString = urlContents else {
print("error")
return
}
print(urlContents)
}
task.resume()
// you must tell webview to load response
webview.loadRequest(request)
}
else{
print("local key found", hashcode)
// ********* Found local key go to site pass key over ************
let webview = WKWebView(frame: view.frame, configuration: WKWebViewConfiguration())
view.addSubview(webview)
webview.loadPlugin(jsapi(), namespace: "jsapi")
let req = NSMutableURLRequest(URL: NSURL(string:serverLocation + onlineLoginApi + "?hashcode=\(hashcode)")!)
req.HTTPMethod = "POST"
req.HTTPBody = "/?hashcode=\(hashcode)".dataUsingEncoding(NSUTF8StringEncoding)
NSURLSession.sharedSession().dataTaskWithRequest(req)
{ data, response, error in
if error != nil
{
//Your HTTP request failed.
print(error!.localizedDescription)
} else {
//Your HTTP request succeeded
print(String(data: data!, encoding: NSUTF8StringEncoding))
}
}.resume()
webview.loadRequest(req)
}
}
else{
// No connection to internet
let webview = WKWebView(frame: view.frame, configuration: WKWebViewConfiguration())
view.addSubview(webview)
webview.loadPlugin(jsapi(), namespace: "jsapi")
let root = NSBundle.mainBundle().resourceURL!
let url = root.URLByAppendingPathComponent("/www/error-no-connection.html")
webview.loadFileURL(url, allowingReadAccessToURL: root)
print("No internet connection")
}
}
class jsapi: NSObject {
// Reconnect button on interface
func retryConnection()
{
print("Reconnect clicked")
dispatch_async(dispatch_get_main_queue())
{
let netConnections = Connection.isConnectedToNetwork()
if netConnections == true {
let netalert = UIAlertView(title: "Internet on line", message: nil, delegate: nil, cancelButtonTitle: "OK")
netalert.show()
let url = self.serverLocation + self.onlineLoginApi
let hashcode = ViewController().getHashcode()
if(hashcode != "00000") {
let url = url + "?hashcode=\(hashcode)"
print("url: ", url)
}
ViewController().loadPagelive(url)
}
else{
let netalert = UIAlertView(title: "Internet off line", message: nil, delegate: nil, cancelButtonTitle: "OK")
netalert.show()
}
}
print("retryConnect end")
}
}
You try to perform the loadPagelive(url) on a new instance of your ViewController, not on the current one shown on the screen, that's why you don't see any update.
You should create a delegate or a completion block in order to execute code on you ViewController instance loaded on the screen: every time you do ViewController(), a new object is created.
You can try using the delegate pattern, which is simple to achieve. I will try to focus on the important part and create something that can be used with your existing code:
class ViewController: UIViewController {
let jsapi = jsapi() // You can use only 1 instance
override func viewDidLoad() {
super.viewDidLoad()
// Set your ViewController as a delegate, so the jsapi can update it
jsapi.viewController = self
login()
}
func loadPagelive(_ url: URL) {
// Load page, probably you already have it
}
}
class jsapi: NSObject {
weak var viewController: ViewController?
func retryConnection() {
// We check if the delegate is set, otherwise it won't work
guard viewController = viewController else {
print("Error: delegate not available")
}
[... your code ...]
// We call the original (and hopefully unique) instance of ViewController
viewController.loadPagelive(url)
}
}