Ayox
Ayox

Reputation: 761

Facebook AccessToken nil after killing App (iOS)

I am developing an iOS app using the FacebookSDK to login.

After logging in and killing the App, the currentAccessToken is always nil. It only works if I press the home button and re-open the app while it's still running in the background.

I started using alert since logs are not working properly after killing the App.

AppDelegate.swift

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

    FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)

    let accessToken = FBSDKAccessToken.current()
    if accessToken == nil {
        Auth.auth().addStateDidChangeListener { (auth, user) in
            alert(title: user?.uid ?? "1")
        }
        alert(title: "2")
    } else {
        alert(title: accessToken?.userID ?? "3")
    }
}

It always displays "1" in the Alert.

It is a similar problem to: FBSDKAccessToken currentAccessToken nil after quitting app or iOS 9 Facebook Access Token is nil on future app launches

I have been tried:

  1. Keychain Not working
  2. Downgrading to 4.17 not possible via Cocoapods
  3. Changing Transport Security not working as well

Help/Suggestions,

Thanks in advance.

Upvotes: 5

Views: 1535

Answers (1)

staticVoidMan
staticVoidMan

Reputation: 20274

AccessToken.current does not persist and hence you would have to manually save the access token string and recreate it on consecutive launches.

Basically:

  1. Save when you get Access token

    let strAuthenticationToken = accessToken.authenticationToken
    UserDefaults.standard.set(strAuthenticationToken,
                          forKey: "AccessToken_Facebook")
    
  2. Get Access Token string and recreate the AccessTokenobject on next launch

    if let strAuthenticationToken = UserDefaults.standard.string(forKey: "AccessToken_Facebook") {
    //Create AccessToken for facebook login
    let accessToken = AccessToken(authenticationToken: strAuthenticationToken)
    
    //...Skip Login and directly proceed to get facebook profile data with the AccessToken
    }
    

NOTE: For the ease of this example, the Facebook Access Token string is being saved to UserDefaults but ideally it should be saved to the Keychain.


In Example:

func loginWithFacebook() {
    //Check for previous Access Token
    if let accessToken  = AccessToken.current {
        //AccessToken was obtained during same session
        getAccountDetails(withAccessToken: accessToken)
    }
    else if let strAuthenticationToken = UserDefaults.standard.string(forKey: "AccessToken_Facebook") {
        //A previous access token string was saved so create the required AccessToken object
        let accessToken = AccessToken(authenticationToken: strAuthenticationToken)

        //Skip Login and directly proceed to get facebook profile data with an AccessToken
        getAccountDetails(withAccessToken: accessToken)
    }
    else {
        //Access Token was not available so do the normal login flow to obtain the Access Token
        doFacebookLogin()
    }
}

func doFacebookLogin() {
    LoginManager().logIn(readPermissions: [.publicProfile, .email], viewController: nil) { loginResult in
        switch loginResult {
        case .failed(let error):
            print(error)

        case .cancelled:
            print("User cancelled login.")

        case .success(let grantedPermissions,
                      let declinedPermissions,
                      let accessToken):

            //Save Access Token string for silent login purpose later
            let strAuthenticationToken = accessToken.authenticationToken
            UserDefaults.standard.set(strAuthenticationToken,
                                      forKey: "AccessToken_Facebook")

            //Proceed to get facebook profile data
            self.getAccountDetails(withAccessToken: accessToken)
        }
    }
}

func getAccountDetails(withAccessToken accessToken: AccessToken) {
    let graphRequest: GraphRequest = GraphRequest(graphPath     : "me",
                                                  parameters    : ["fields" : "id, name, email"],
                                                  accessToken   : accessToken,
                                                  httpMethod    : GraphRequestHTTPMethod.GET,
                                                  apiVersion    : GraphAPIVersion.defaultVersion)
    graphRequest.start { (response, result) in
        switch result {
        case .success(let resultResponse):
            print(resultResponse)
        case .failed(let error):
            print(error)
        }
    }
}

(Swift 4 / Facebook SDK 4.30)

Upvotes: 2

Related Questions