So I have managed to set it up so the whole login system works. It closes out of the browser once logged in but does not advance to the next viewController.
This is my AppDelegate.swift:
import UIKit
import CoreData
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
public func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
// Override point for customization after application launch.
return FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
}
public func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(
app,
open: url as URL!,
sourceApplication: options[UIApplicationOpenURLOptionsKey.sourceApplication] as! String,
annotation: options[UIApplicationOpenURLOptionsKey.annotation]
)
}
public func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(
application,
open: url as URL!,
sourceApplication: sourceApplication,
annotation: annotation)
}
}
This is my ViewController.swift:
import UIKit
import FBSDKCoreKit
import FBSDKLoginKit
class ViewController: UIViewController, FBSDKLoginButtonDelegate {
var fbLoginSuccess = false
override func viewDidLoad() {
if (FBSDKAccessToken.current() != nil && fbLoginSuccess == true)
{
print("Logged In...")
} else {
print("Not Logged In...")
}
let loginButton = FBSDKLoginButton()
loginButton.readPermissions = ["public_profile", "email"]
loginButton.center = self.view.center
loginButton.delegate = self
self.view.addSubview(loginButton)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// Facebook Login.
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {
if error != nil
{
print(error)
} else if result.isCancelled {
// Handle
} else {
fbLoginSuccess = true
print("User logged in...")
self.performSegue(withIdentifier: "showNew", sender: self)
}
}
func loginButtonDidLogOut(_ loginButton: FBSDKLoginButton!) {
print("User logged out...")
}
}
I have a storyboard Identifier 'showNew' and I cannot figure out why it doesn't trigger.
Related
I have a very simple setup:
//AppDelegate.swift
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
window = UIWindow(frame:UIScreen.main.bounds) //puts a rectange the same size of the screen
window?.rootViewController = MainController()
window?.makeKeyAndVisible() //make the window and keyboard available for window
FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
return true
}
public func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
let handled = FBSDKApplicationDelegate.sharedInstance().application(app, open: url, sourceApplication: options[UIApplicationOpenURLOptionsKey.sourceApplication] as! String!, annotation: options[UIApplicationOpenURLOptionsKey.annotation])
return handled
}
.....
}
//Main Controller
import Foundation
import UIKit
import Alamofire
class MainController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(SplashController().view)
Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(changeView), userInfo: nil, repeats: false)
}
func changeView() {
let authController = Authenticate()
view.addSubview(authController.view)
}
}
//View Controller
import Foundation
import UIKit
import FacebookLogin
import FBSDKLoginKit
class Authenticate: UIViewController,FBSDKLoginButtonDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let loginButton = FBSDKLoginButton()
loginButton.delegate = self
loginButton.center = view.center
view.addSubview(loginButton)
}
func loginButtonDidLogOut(_ loginButton: FBSDKLoginButton!) {
print("DID LOG OUT!!!")
}
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {
print("Login Delegate callback")
if error != nil {
print(error)
return
}
print("successfully logged into facebook")
}
func loginButtonWillLogin(_ loginButton: FBSDKLoginButton!) -> Bool {
print("WILL LOGIN")
return true
}
}
Everything appears generally to work fine with the login process (I get the FB prompt, login, am brought back to the app, etc.)
However, the delegates methods NEVER fire. I never see "DID LOG OUT" or "Login Delegate Callback" or "successfully logged into facebook".
What am I missing?
Thanks in advance for help/suggestions.
How to go to the another viewcontroller after facebook login? What should be done in Main.storyboard?
Here is my AppDelegate.swift
import UIKit
import FBSDKCoreKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
return true
}
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(app, open: url, sourceApplication: options[UIApplicationOpenURLOptionsKey.sourceApplication] as! String!, annotation: options[UIApplicationOpenURLOptionsKey.annotation])
}
func applicationDidBecomeActive(_ application: UIApplication) {
FBSDKAppEvents.activateApp()
}
}
Here is ViewController.swift
import UIKit
import FBSDKLoginKit
class ViewController: UIViewController, FBSDKLoginButtonDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let loginButton = FBSDKLoginButton()
loginButton.center = self.view.center
view.addSubview(loginButton)
}
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {
if error != nil {
print("Something went wrong... \(error)" )
return
}
print("Successfully logged in!")
}
func loginButtonDidLogOut(_ loginButton: FBSDKLoginButton!) {
print("Successfully logged out!")
}
}
You're probably looking for something like this:
if(FBSDKAccessToken.currentAccessToken() != nil) {
let storyboard = UIStoryboard(name: "MyStoryboardName", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "myViewController")
self.navigationController?.push(vc, animated: true)
}
What that snippet does, is check whether the user is logged in via Facebook (I assume you're using the SDK), and if they are, instantiate a VC from the storyboard, and push it with the Navigation Controller. Where you want to put that, whether you want to present the VC in a different way, etc..., is up to you, as the flow of your app will heavily inform it.
Try this in your ViewController.swift:
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {
if error == nil && !result.isCancelled{
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let vc = storyboard.instantiateInitialViewController(){
self.present(vc, animated: true, completion: nil)
}
}
}
I am in beta testing and so far 5 users have complete success for login and function of the app. However 3 users Facebook information is not getting saved to Parse and the app crashes when they try to move onto the VC that loads the user profile. I don't understand what is happening. Here is my login code it will come across as very amateurish and messy so apologies up front! (Newb but trying)
App delegate:
import UIKit
import Bolts
import Parse
import ParseUI
import FBSDKCoreKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// code in here to check devices just left it out as it was too much information to paste.
}
// parse info and connection
Parse.enableLocalDatastore()
Parse.setApplicationId("",
clientKey: "")
PFFacebookUtils.initializeFacebookWithApplicationLaunchOptions(launchOptions)
PFUser.enableAutomaticUser()
let defaultACL = PFACL();
defaultACL.setPublicReadAccess(true)
PFACL.setDefaultACL(defaultACL, withAccessForCurrentUser:true)
if application.applicationState != UIApplicationState.Background {
let preBackgroundPush = !application.respondsToSelector("backgroundRefreshStatus")
let oldPushHandlerOnly = !self.respondsToSelector("application:didReceiveRemoteNotification:fetchCompletionHandler:")
var noPushPayload = false;
if let options = launchOptions {
noPushPayload = options[UIApplicationLaunchOptionsRemoteNotificationKey] != nil;
}
if (preBackgroundPush || oldPushHandlerOnly || noPushPayload) {
PFAnalytics.trackAppOpenedWithLaunchOptions(launchOptions)
}
}
if application.respondsToSelector("registerUserNotificationSettings:") {
let userNotificationTypes: UIUserNotificationType = [UIUserNotificationType.Alert, UIUserNotificationType.Badge, UIUserNotificationType.Sound]
let settings = UIUserNotificationSettings(forTypes: userNotificationTypes, categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
} else {
let types: UIRemoteNotificationType = [UIRemoteNotificationType.Badge, UIRemoteNotificationType.Alert, UIRemoteNotificationType.Sound]
application.registerForRemoteNotificationTypes(types)
}
return FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
let installation = PFInstallation.currentInstallation()
installation.setDeviceTokenFromData(deviceToken)
installation.saveInBackground()
PFPush.subscribeToChannelInBackground("") { (succeeded: Bool, error: NSError?) in
if succeeded {
print("ParseStarterProject successfully subscribed to push notifications on the broadcast channel.");
} else {
print("ParseStarterProject failed to subscribe to push notifications on the broadcast channel with error = %#.", error)
}
}
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
if error.code == 3010 {
print("Push notifications are not supported in the iOS Simulator.")
} else {
print("application:didFailToRegisterForRemoteNotificationsWithError: %#", error)
}
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
PFPush.handlePush(userInfo)
if application.applicationState == UIApplicationState.Inactive {
PFAnalytics.trackAppOpenedWithRemoteNotificationPayload(userInfo)
}
}
func application(application: UIApplication,
openURL url: NSURL,
sourceApplication: String?,
annotation: AnyObject) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(application, openURL: url, sourceApplication: sourceApplication, annotation: annotation)
}
func applicationDidBecomeActive(application: UIApplication) {
FBSDKAppEvents.activateApp()
}
}
View contorller:
import UIKit
import Parse
import FBSDKCoreKit
import FBSDKShareKit
import FBSDKLoginKit
import ParseUI
class LoginViewController: UIViewController {
var firstName: String!
var lastName: String!
#IBAction func logInWithFacebook(sender: AnyObject) {
let permissions = ["public_profile", "email"]
PFFacebookUtils.logInInBackgroundWithReadPermissions(permissions, block: {
(user: PFUser?, error: NSError?) -> Void in
if let error = error {
print(error)
} else {
// user successfully signed in:
if let user = user {
self.performSegueWithIdentifier("registerFacebookSegue", sender: self)
}
}
})
}
override func viewDidAppear(animated: Bool) {
//to log user out
// PFUser.logOut()
// segue if user is logged in:
if let username = PFUser.currentUser()?.username {
self.performSegueWithIdentifier("loggedInProfileSegue", sender: self)
}
}
override func viewDidLoad() {
super.viewDidLoad()
if(FBSDKAccessToken.currentAccessToken() != nil) {
print("user logged in")
} else {
print("user not logged in")
}
}
override func prefersStatusBarHidden() -> Bool {
return true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Got facebook passwords from a user that wasn't working and tried to log in with xcode and phone connected got this error:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Can't use nil for keys or values on PFObject. Use NSNull for values.'
* First throw call stack:
(0x183608f48 0x1980cbf80 0x183608e90 0x1000e49a8 0x1000e8e98 0x10012d344 0x1000e8eec 0x100062ec8 0x1000976f4 0x10009e1c0 0x10009df90 0x10009da44 0x1834ff990 0x1834ff800 0x10009d800 0x10009cd00 0x10009aed4 0x100097eb8 0x100097e10 0x100098288 0x182e9b6a8 0x182e9b638 0x182e9b7ac 0x182d074fc 0x182df5b38 0x101461c68 0x10146b40c 0x182cf3ce4 0x1834ec6cc 0x182cf3bc8 0x182cf3a88 0x182cf38b4 0x1835c0544 0x1835bffd8 0x1835bdcd8 0x1834ecca0 0x18e728088 0x188c04ffc 0x10006e488 0x19891a8b8)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
The problem was that I was asking for email in my requests and not all facebook accounts have a. a valid email addresses and b. any email address linked at all. So I had to remove this request and ask the user to input their email address separately.
I have been attempting to create a fb login in my application, the problem is that once logged in the isCancelled value of the FBSDKLoginManagerLoginResult in the didCompleteWithResults is true. I have seen other people get this error but their problem was with their AppDelegate.swift which I see no problem with mine.
Here is my ViewController.swift:
import UIKit
import FBSDKCoreKit
import FBSDKShareKit
import FBSDKLoginKit
class ViewController: UIViewController, FBSDKLoginButtonDelegate {
var loginbutton = FBSDKLoginButton()
override func viewDidLoad() {
super.viewDidLoad()
//facebook login
if(FBSDKAccessToken.currentAccessToken()==nil){
println("Not Logged In..")
}else{
println("Logged In")
}
loginbutton.readPermissions = ["public_profile","email","user_friends"]
loginbutton.center = CGPointMake(self.view.center.x, self.view.center.y+(self.view.frame.height/4))
self.loginbutton.delegate = self
FBSDKProfile.enableUpdatesOnAccessTokenChange(true)
self.view.addSubview(loginbutton)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//Facebook Login
func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError!) {
if error==nil{
println("declined:\(result.declinedPermissions)")
println("granted:\(result.grantedPermissions)")
println("isCan:\(result.isCancelled)")
println("token:\(result.token)")
let accessToken = FBSDKAccessToken.currentAccessToken()
}else{
println(error.localizedDescription)
}
}
Here is my AppDelegate.swift:
import UIKit
import FBSDKCoreKit
import FBSDKShareKit
import FBSDKLoginKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
}
func application(application:UIApplication, openURL url:NSURL, sourceApplicaiton:String?, annotation:AnyObject) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(application, openURL: url, sourceApplication: sourceApplicaiton, annotation: annotation)
}
func applicationDidBecomeActive(application: UIApplication) {
FBSDKAppEvents.activateApp()
}
I am using FBSDKGraphRequest to implement Facebook login in my iOS app.
But after the login is done and the user confirms, I am not redirected to my app.
Here is my code:
FBSDKGraphRequest(graphPath: "me", parameters: nil).startWithCompletionHandler({
(connection, result, error: NSError!) -> Void in
if error == nil {
println("\(result)")
} else {
println("\(error)")
self.performSegueWithIdentifier("home", sender: self)
}
})
In your appdelegate :
import UIKit
import FBSDKCoreKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
}
func applicationWillResignActive(application: UIApplication) {
FBSDKAppEvents.activateApp()
}
func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject?) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(application, openURL: url, sourceApplication: sourceApplication, annotation: annotation)
}
}
In your view controller :
import UIKit
import FBSDKLoginKit
class ViewController: UIViewController {
var dict : NSDictionary!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func btnFBLoginPressed(sender: AnyObject) {
var fbLoginManager : FBSDKLoginManager = FBSDKLoginManager()
fbLoginManager .logInWithReadPermissions(["email"], handler: { (result, error) -> Void in
if (error == nil){
var fbloginresult : FBSDKLoginManagerLoginResult = result
if(fbloginresult.grantedPermissions.containsObject("email"))
{
self.getFBUserData()
fbLoginManager.logOut()
}
}
})
}
func getFBUserData(){
if((FBSDKAccessToken.currentAccessToken()) != nil){
FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, first_name, last_name, picture.type(large), email"]).startWithCompletionHandler({ (connection, result, error) -> Void in
if (error == nil){
self.dict = result as NSDictionary
println(result)
println(self.dict)
NSLog(self.dict.objectForKey("picture")?.objectForKey("data")?.objectForKey("url") as String)
}
})
}
}
}
Add properties in your plist.info file.
Add URL Types, FacebookAppID, and FacebookDisplayName Properties
For more you can go through the steps of https://developers.facebook.com/docs/ios/getting-started
You have to add handle URL code in your app delegate like this-
- (BOOL)application: (UIApplication *)application
openURL: (NSURL *)url
sourceApplication: (NSString *)sourceApplication
annotation: (id)annotation
{
if ([[url scheme] isEqualToString:FACEBOOK_SCHEME])
return [FBSession.activeSession handleOpenURL:url];
return NO;
}
And you have to add URL schemes in target settings->Info->Url Types