I am at my wits end here, I have been working on this for days and cannont seem to resolve this issue. I am relitivly new to the coding world, so I am sure this is a rookie mistake, but I just can't afford to waste any more time on this, its been a week almost.
I am writing in XCode 8.3, Swift 3. I am following tutorials to the letter from Auth0's website. Before I entered the code I am pasting below, my app would complie, but it would not work. Auth0 said I was mising this code.
I am receiving the following error: Use of unresolved identifier 'accessToken' I have no other errors or red !'s but this will not go away. I have tried moving the code around, that doesn't work. I have tried let, else, if statements, that doesn't work. I have spent mind numbing hours googling, and still I just can't seem to grasp what I am doing wrong.
Here is the code:
import UIKit
import Lock
import Auth0
import SimpleKeychain
class HomeViewController: UIViewController {
// MARK: - IBAction
#IBAction func showLoginController(_ sender: UIButton) {
Lock
.classic()
.withOptions {
$0.oidcConformant = true
$0.scope = "openid profile"
}
.onAuth { credentials in
let keychain = A0SimpleKeychain(service: "Auth0")
guard let accessToken = credentials.accessToken else { return }
keychain.setString(accessToken, forKey: "access_token")
self.showSuccessAlert(accessToken)
}
.present(from: self)
Auth0
.authentication()
.userInfo(withAccessToken: accessToken)
.start { result in
switch(result) {
case .sucess(let profile): break
case .failure(let error): break
}
}
Auth0
.webAuth()
.scope("openid profile")
.audience("https://mycompany.auth0.com/userinfo")
.start {
switch $0 {
case .failure(let error):
// Handle the error
print("Error: \(error)")
case .success(let credentials):
// Do something with credentials e.g.: save them.
// Auth0 will automatically dismiss the hosted login page
print("Credentials: \(credentials)")
}
}
Auth0
.webAuth()
.scope("openid profile offline_access")
.start {
switch $0 {
case .failure(let error):
// Handle the error
print("Error: \(error)")
case .success(let credentials):
guard let accessToken = credentials.accessToken, let refreshToken = credentials.refreshToken else { return }
let keychain = A0SimpleKeychain(service: "Auth0")
keychain.setString(accessToken, forKey: "access_token")
keychain.setString(refreshToken, forKey: "refresh_token")
}
}
}
// MARK: - Private
fileprivate func showSuccessAlert(_ accessToken: String) {
let alert = UIAlertController(title: "Success", message: "accessToken: \(accessToken)", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
Strategies for Debugging Swift Code:
Thoroughly investigate LLDB debugger to see what happened
Read through existing code (all .swift files that you wrote code in) to check for any spelling errors, etc.
Open a new Xcode project and run each .swift file to pinpoint where the error is and/or use breakpoints in your existing Xcode project
Enable zombies
Code pesticides :P
Good luck with the rest of your project!
Related
I am trying to integrate a very basic single IAP in my game, here I am calling from my GameScene
let alert = UIAlertController(title: "Upgrade", message: "Would you like to remove ads?", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Remove Ads", style: .default, handler: { action in
print("Pressed Remove Ads")
GameViewController().buytheIAP()
}))
alert.addAction(UIAlertAction(title: "Restore Purchases", style: .default, handler: { action in
print("Pressed Restore")
GameViewController().restoretheIAP()
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { action in
print("Pressed Cancel")
}))
view?.window?.rootViewController?.present(alert, animated: true, completion: nil)
}
Those methods are called correctly, and refer to these inside GameViewController.swift;
func buytheIAP(){
iAPHelper.purchase()
print("OK Lets upgrade")
}
func restoretheIAP(){
iAPHelper.restorePurchase()
print("OK Lets restore")
}
func restoreDidSucceed() {
UserDefaults.setValue(true, forKey: iAPHelper.productID)
//this should have something like hide banner etc.
bannerView.isHidden = true
}
func purchaseDidSucceed() {
UserDefaults.setValue(true, forKey: iAPHelper.productID)
//as above this should have something like hide banner etc.
bannerView.isHidden = true
print("Purchased upgrade ENJOYYYYYYYY")
}
func nothingToRestore() {
}
func paymentCancelled() {
}
The test IAP goes through, it gets the correct information from the app store, and I use my sandbox details to purchase, it goes through correctly with a successful purchase message. However, the bannerView does not hide, and more importantly, upon restarting the game again, everything is forgotten and the game thinks nothing has been purchased. I am guessing it has to be some sort of check that is missing.
I have this in my viewDidLoad
if userDefaults.bool(forKey: iAPHelper.productID) {
bannerView.isHidden = true
print("It is purchased, so DO NOT show the ads")
} else{
bannerView.adSize = getAdaptiveSize()
bannerView.adUnitID = "ca-app-pub-3940256099942544/2934735716"
bannerView.delegate = self
bannerView.rootViewController = self
bannerView.load(GADRequest())
addBannerViewToView(bannerView)
print("Not purchased, so show the ads")
}
And it ALWAYS shows print("Not purchased, so show the ads")
The IAPHelper file, for purchasing is;
func purchase() {
SwiftyStoreKit.purchaseProduct(productID, quantity: 1, atomically: true) { [self] result in
switch result {
case .success:
delegate?.purchaseDidSucceed()
print("OK It's purchased")
case .error(let error):
switch error.code {
case .unknown: print("Unknown error. Please contact support")
case .clientInvalid: print("Not allowed to make the payment")
case .paymentCancelled:
delegate?.paymentCancelled()
case .paymentInvalid: print("The purchase identifier was invalid")
case .paymentNotAllowed: print("The device is not allowed to make the payment")
case .storeProductNotAvailable: print("The product is not available in the current storefront")
case .cloudServicePermissionDenied: print("Access to cloud service information is not allowed")
case .cloudServiceNetworkConnectionFailed: print("Could not connect to the network")
case .cloudServiceRevoked: print("User has revoked permission to use this cloud service")
default: print((error as NSError).localizedDescription)
}
}
}
}
}
And the log DOES show print("OK It's purchased") after the initial purchase - so I am struggling to see what is going wrong.
The IAP delegate functions are not (guaranteed to be) called on the UI/main thread, that's why your view doesn't hide.
Don't you see some iOS warning saying that you try to set a UIView property on non-main thread?
The fact that your custom purchase info was not saved in UserDefaults could be caused by killing the app prematurely from Xcode.
(UserDefaults does take of saving what's being set during normal app flow.)
OK, so I figured the answer, there was a missing line in my AppDelegate.swift section didFinishLaunchingWithOptions
UserDefaults.standard.register(defaults: ["adRemove" : false])
I renamed userDefaults.bool(forKey: iAPHelper.productID) to make it easier to use / understand. So in my original post that has been replaced by UserDefaults.standard.register(defaults: ["adRemove" : false]) instead.
You can then use this anywhere to check, such as;
if !userDefaults.bool(forKey: "adRemove") {
// Do something here
}
Hope this helps anyone in future with the same question!
My application recently started crashing after upgrading Xcode to 9.3 and updating my iPhone. Unfortunately, it gives me very little information when it does crash.
I have set up breakpoints and I know it crashes exactly on the line where I call loginManager.login().
/**
Defines what should happen when the sign in with facebook button is tapped.
If an error ocurrs, a hud is displayed to the user. If facebook authentication
is sucessful, firebase authentication is attempted.
*/
#objc func handleSignInWithFBonTapped() {
hud.textLabel.text = "Signing in with Facebook..."
hud.show(in: view, animated: true)
let loginManager = LoginManager()
loginManager.logIn(readPermissions: [.publicProfile, .email], viewController: self) { (result) in
switch result {
case .success(grantedPermissions: _, declinedPermissions: _, token: _):
self.signIntoFirebase()
case .failed(let err) :
print(err)
Service.dismissHud(self.hud, text: "Error", detailText: "Failed to retrieve user with error: \(err).", delay: 3)
case .cancelled :
Service.dismissHud(self.hud, text: "Cancelled", detailText: "Facebook login cancelled", delay: 1)
}
}
}
Has anyone else experienced this/upgraded to 9.3 with Facebook login still working ok? Any help is appreciated!
Cheers
I am using firebase Facebook auth. User is able to successfully login I am able to get user profile image from firebase after Facebook login but I need customized image for a better quality. I am unable to get user profile image using this code which uses UserProfile class. Although similar code for android works fine.
My Custom Facebook Button Code. Written in class SignUpFirst.
#IBAction func facebookLogin(_ sender: AnyObject) {
let loginManager = LoginManager()
loginManager.logIn([ .publicProfile,.email], viewController: self) { loginResult in
switch loginResult {
case .failed(let error):
print(error)
case .cancelled:
print("User cancelled login.")
case .success(let grantedPermissions, let declinedPermissions, let accessToken):
//print("Logged in! \(accessToken)")
let credential = FacebookAuthProvider.credential(withAccessToken: accessToken.authenticationToken)
Auth.auth().signIn(with: credential) { (user, error) in
if let error = error {
//show error if failed
print(error.localizedDescription)
return
}
checkUser(firebaseUser: user!)
}
}
}
}
Trying to get user profile image in class SignUpSecond.
UserProfile.current?.imageURLWith(UserProfile.PictureAspectRatio.normal, size: CGSize(width: 10.0, height: 10.0))
But this code is returning nil here. I have also tried adding this code in success of Facebooklogin button it was still returning nil. What is the solution.
After successful login, you would get token but not profile.
It means UserProfile.current still nil.
you must load profile. You can reference similair question
use https://graph.facebook.com/{use-id}/picture?type=square&width=10&height=10 to get avatar url directly. example:
https://graph.facebook.com/1410901795642099/picture?type=square&width=10&height=10
I am using email + password authentication with Firebase for my app. Login works, and I use observeAuthEventWithBlock to check if a user is logged in - in order not to bring up the Login page. If I press the home button and open the app again, there is no problem. The problem I am having is if I force-quit the app. When I re-open, I have to log-in again.
Some notes about the setup before I show my login code.
There is a LoginViewController - not embedded - built w/ Storyboard
This is connected to a Navigation Controller
Which is what the first screen is embedded in, and the rest of the app uses this Nav Controller.
Login code:
#IBAction func loginButtonPressed() {
let userEmail = emailTextField.text
self.ref.authUser(self.emailTextField.text, password: self.passwordTextField.text, withCompletionBlock: { (error, auth) -> Void in
guard error == nil else {
if let errorCode = FAuthenticationError(rawValue: error.code) {
switch (errorCode) {
case .EmailTaken:
self.displayMessage("Email Error", theMessage: "This email is taken")
case .InvalidEmail:
self.displayMessage("Email Error", theMessage: "This email is invalid")
case .UserDoesNotExist:
self.displayMessage("User Error", theMessage: "A user account for email: \(userEmail!) does not exist")
case .InvalidPassword:
self.displayMessage("Password Error", theMessage: "The password is incorrect")
case .NetworkError:
self.displayMessage("Network Error", theMessage: "Seems like there's a problem with your internet connection")
default:
return
}
}
return //set Unknown Error Alert here
}
print("LOGGED IN: segue from loginButtonPressed")
self.userLoggedIn = true
print("user is logged in? \(self.userLoggedIn)")
self.performSegueWithIdentifier("loginLocaleSegue", sender: self)
})
}
Check if user is logged in - if so segue to navcon, pop it and display embedded View Controller:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
if self.userLoggedIn.boolValue == true {
ref.observeAuthEventWithBlock { (authData) -> Void in
if authData != nil {
let navCon: UINavigationController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("MainNavigationController") as! UINavigationController
self.presentViewController(navCon, animated: false, completion: nil)
navCon.popViewControllerAnimated(false)
print("user is authenticated: \(authData.providerData["email"] as! String)")
print("segues from viewDidAppear")
} else {
return
}
}
}
}
I've seen questions related to Firebase auth which state that Authdata is stored in Keychain by default, which causes problems with Authdata persisting even after deletion of app, but I'm experiencing the total opposite issue. Any ideas?
From what I can tell, you're not writing "self.userLoggedIn = true" to any database, so it makes sense that it continues being "True" while you have the app on idle, but once you close the application, it then becomes nil (no value), this is because it's just chilling in the background while the app is open, but not completely closed. Try writing this to your Firebase database, as outlined in this tutorial, and see if that helps.
https://www.raywenderlich.com/109706/firebase-tutorial-getting-started
I am trying to check for missing permissions once a user has successfully logged into the app.
func checkUserPermission()
{
let loginResult: FBSDKLoginManagerLoginResult = FBSDKLoginManagerLoginResult()
var missingPermissions: [String] = []
if !loginResult.grantedPermissions.containsObject("public_profile")
{
missingPermissions.append("public_profile")
}
if !loginResult.grantedPermissions.containsObject("email")
{
missingPermissions.append("email")
}
if !loginResult.grantedPermissions.containsObject("user_friends")
{
missingPermissions.append("user_friends")
}
if !loginResult.grantedPermissions.containsObject("user_likes")
{
missingPermissions.append("user_likes")
}
println(missingPermissions)
}
This function is ran when the app state changes to make sure I have all the permissions I need to make the app functional.
I am currently receiving this error "fatal error: unexpectedly found nil while unwrapping an Optional value" but I cant seem to understand why. If the "FBSDKAccessToken.currentAccessToken()" is set then in theory the permissions should be set as well.
Found the issue, I assumed let loginResult: FBSDKLoginManagerLoginResult = FBSDKLoginManagerLoginResult() will store the permissions granted but to get the active permissions of the current logged in user you will have to rely on FBSDKAccessToken. So replacing loginResult with
let loginResult: FBSDKAccessToken = FBSDKAccessToken.currentAccessToken()
Should fix the issue. Also grantedPermissions will be changed to permissions. Here is the working function:
func checkUserPermission()
{
let loginResult: FBSDKAccessToken = FBSDKAccessToken.currentAccessToken()
var missingPermissions: [String] = []
if !loginResult.permissions.containsObject("public_profile")
{
missingPermissions.append("public_profile")
}
if !loginResult.permissions.containsObject("email")
{
missingPermissions.append("email")
}
if !loginResult.permissions.containsObject("user_friends")
{
missingPermissions.append("user_friends")
}
if !loginResult.permissions.containsObject("user_likes")
{
missingPermissions.append("user_likes")
}
println(missingPermissions)
//let login: FBSDKLoginManager = FBSDKLoginManager()
//login.logInWithReadPermissions([""], handler: <#FBSDKLoginManagerRequestTokenHandler!##(FBSDKLoginManagerLoginResult!, NSError!) -> Void#>)
//login.loginw
}
With the (current) version 0.2.0 of Facebook SDK for Swift, this works:
func loginButtonClicked() {
let loginManager = LoginManager()
loginManager.logIn([ .publicProfile, .email ], viewController: self) { loginResult in
switch loginResult {
case .failed(let error):
print(error)
case .cancelled:
print("User cancelled login.")
case .success(let grantedPermissions, let declinedPermissions, let accessToken):
print("Logged in!")
// Check for access to email address
if declinedPermissions.contains(FacebookCore.Permission.init(name: "email")) {
print("Email access declined")
}
}
}
}