App crashes after user logs in with Facebook - ios

I got my app onto the App Store. Everything was working fine on my end, and apparently on the reviewers end.
After the app went live, some users reported crashing immediately after they log in with Facebook. Here's the code for where I think it's crashing (run right after users log in with Facebook):
import UIKit
import FBSDKCoreKit
import FBSDKLoginKit
protocol getUserDataDelegate {
func gotData()
}
public var userEmailForMixpanel = ""
public var userNameForInvites = ""
class GetUserData: NSObject {
var facebookid:String = ""
var userEmail:String = ""
var userFirstName:String = ""
var userLastName: String = ""
var userGender:String = ""
var userBirthday:String = ""
var delegate = getUserDataDelegate?()
func returnUserData() {
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, email, first_name, last_name, gender, birthday"])
graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in
if ((error) != nil)
{
print("Error: \(error)")
}
else
{
self.facebookid = (result.valueForKey("id") as? String)!
self.userEmail = (result.valueForKey("email") as? String)!
self.userFirstName = (result.valueForKey("first_name") as? String)!
self.userLastName = (result.valueForKey("last_name") as? String)!
self.userGender = (result.valueForKey("gender") as? String)!
//self.userBirthday = (result.valueForKey("birthday") as? String)!
userEmailForMixpanel = self.userEmail
userNameForInvites = self.userFirstName
NSUserDefaults.standardUserDefaults().setValue(userEmailForMixpanel, forKey: "userEmail")
NSUserDefaults.standardUserDefaults().setValue(userNameForInvites, forKey: "userName")
NSUserDefaults.standardUserDefaults().synchronize()
Mixpanel.sharedInstanceWithToken("abdc")
let mixpanel = Mixpanel.sharedInstance()
mixpanel.registerSuperProperties(["Gender":self.userGender])
print(self.facebookid)
print(self.userEmail)
print(self.userFirstName)
print(self.userLastName)
print(self.userGender)
//print(self.userBirthday)
self.checkIfUserExists()
}
})
}
func checkIfUserExists() {
showTutorial = true
let url:NSURL = NSURL(string: "url")!
let task:NSURLSessionDataTask = NSURLSession.sharedSession().dataTaskWithURL(url) { (data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in
let userTokenDataDictionary:NSDictionary = (try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)) as! NSDictionary
if userTokenDataDictionary ["token"] != nil {
userAccessToken = (userTokenDataDictionary["token"] as? String)!
NSUserDefaults.standardUserDefaults().setValue(userAccessToken, forKey: "userAccessToken")
NSUserDefaults.standardUserDefaults().synchronize()
print("Token for Existing User:\(userAccessToken)")
self.finishedGettingData()
}
if userTokenDataDictionary ["error"] != nil {
userAccessToken = (userTokenDataDictionary["error"] as? String)!
print(userAccessToken)
print("User needs to be created")
self.createNewUserFromFacebook()
}
}
task.resume()
}
func createNewUserFromFacebook() {
let url:NSURL = NSURL(string: "url")!
print(url)
let task:NSURLSessionDataTask = NSURLSession.sharedSession().dataTaskWithURL(url) { (data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in
let userTokenDataDictionary:NSDictionary = (try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)) as! NSDictionary
if userTokenDataDictionary ["token"] != nil {
userAccessToken = (userTokenDataDictionary["token"] as? String)!
NSUserDefaults.standardUserDefaults().setValue(userAccessToken, forKey: "userAccessToken")
NSUserDefaults.standardUserDefaults().synchronize()
}
if userTokenDataDictionary ["error"] != nil {
userAccessToken = (userTokenDataDictionary["error"] as? String)!
print(userAccessToken)
}
print("Token for New User:\(userAccessToken)")
self.finishedGettingData()
}
task.resume()
}
func checkIfUserHasUsedListenerApp() {
let accessToken = NSUserDefaults.standardUserDefaults().stringForKey("userAccessToken")!
let url:NSURL = NSURL(string: "url")!
print(url)
let task:NSURLSessionDataTask = NSURLSession.sharedSession().dataTaskWithURL(url) { (data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in
let adDataDict:NSDictionary = (try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)) as! NSDictionary
if adDataDict ["used_ListenerApp"] != nil {
let responseCode = adDataDict.valueForKey("used_ListenerApp") as! Bool
print(responseCode)
if responseCode == false {
Mixpanel.sharedInstanceWithToken("abc")
let mixpanel = Mixpanel.sharedInstance()
mixpanel.track("New User Signed Up", properties: ["distinct_id":userEmailForMixpanel])
}
if responseCode == true {
return
}
}
}
task.resume()
}
func finishedGettingData() {
self.checkIfUserHasUsedListenerApp()
Mixpanel.sharedInstanceWithToken("abc")
let mixpanel = Mixpanel.sharedInstance()
mixpanel.track("User Logged In", properties: ["distinct_id":userEmailForMixpanel])
if let actualdelegate = self.delegate {
actualdelegate.gotData()
}
}
}
It's only crashing for some users, not all. I even tried creating a loop that generates a bunch of user data to run it through this code, and I couldn't replicate the crash.
Any advice would be appreciated a lot.
UPDATE
It looks like it has to do with Facebook not returning an email address. I'll keep looking though.

I figured it out. Part of the problem was that Facebook wasn't returning an email address for some users, so I checked for that and if it didn't return an email, I created one with their Facebook ID to get them through the login process (fbid#facebook.mywebsite.com).
Another part of the problem was that some users had logged into my website using an email address that was also assigned to their Facebook account, and tried logging in with Facebook on the app. I fixed this by having it merge their Facebook info with their existing account during the authorization process if an existing account is found.

Related

how to grab the image from FacebookLogin

How do I print out the image from
print((result! as AnyObject).value(forKey: "picture.data.url") as? Any)
I know that the following prints out the data and url but I just need the URL section.
print((result! as AnyObject).value(forKey: "picture") as? Any)
any advise?
I am using FacebookLogin SDK
NOTE: You can create the image URL on your own if you have the userId,
let facebookProfileUrl = "http://graph.facebook.com/\(userID)/picture?type=large"
Here is how you can get id,name,email and profile picture url from facebook login. I use this code in my app and it works.
func fetchFacebookFields() {
LoginManager().logIn(permissions: ["email","public_profile"], from: nil) {
(result, error) -> Void in
if let error = error {
print(error.localizedDescription)
return
}
guard let result = result else { return }
if result.isCancelled { return }
else {
GraphRequest(graphPath: "me", parameters: ["fields" : "first_name, last_name, email"]).start() {
(connection, result, error) in
if let error = error {
print(error.localizedDescription)
return
}
if
let fields = result as? [String:Any],
let userID = fields["id"] as? String,
let firstName = fields["first_name"] as? String,
let lastName = fields["last_name"] as? String,
let email = fields["email"] as? String
{
let facebookProfileUrl = "http://graph.facebook.com/\(userID)/picture?type=large"
print("firstName -> \(firstName)")
print("lastName -> \(lastName)")
print("email -> \(email)")
print("facebookProfileUrl -> \(facebookProfileUrl)")
APPDELEGATEOBJ.makeRootVC(vcName : "MainTabBarVC")
}
}
}
}
}

Application is crashing on facebook in apple review

We were unable to review your app as it crashed on launch. We have attached detailed crash logs to help troubleshoot this issue.
Specifically, your app still crashed on launch after the user logged in with facebook.
I m unable to catch the crash or any error.
Here's the code for where I think it's crashing (run right after users log in with Facebook)
#IBAction func Btn_facebook(_ sender: Any)
{
getFacebookUserInfo()
}
func getFacebookUserInfo()
{
let fbLoginManager : FBSDKLoginManager = FBSDKLoginManager()
fbLoginManager.logIn(withReadPermissions: ["public_profile","email"], from: self) { (result, error) -> Void in
if (error == nil)
{
let fbloginresult : FBSDKLoginManagerLoginResult = result!
// if user cancel the login
if (result?.isCancelled)!{
return
}
if(fbloginresult.grantedPermissions.contains("email"))
{
self.getFBUserData()
self.fbtoken = result!.token.tokenString
}
}
}
}
func getFBUserData()
{
if((FBSDKAccessToken.current()) != nil)
{
FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, email, picture"]).start(completionHandler: { (connection, result, error) -> Void in
if result != nil {
guard FBSDKAccessToken.current().tokenString != nil else {
debugPrint("failed to get access token")
return
}
guard let result = result as? NSDictionary, let user_id_fb = result["id"] as? String else {
print("error")
return
}
}
if (error == nil)
{
let fbDetails = result as! NSDictionary
let field = result! as? [String:Any]
if let imageURL = ((field!["picture"] as? [String: Any])?["data"] as? [String: Any])?["url"] as? String {
print(imageURL)
let url = URL(string: imageURL)
print(url!)
self.fburl = imageURL
print(self.fburl!)
}
let checkemail = fbDetails["email"] as? String
if(checkemail != nil)
{
print(" check email not nil ", checkemail as Any)
self.fbemail = (fbDetails["email"] as? String)
self.fbid = (fbDetails["id"] as? String)
self.fbname = (fbDetails["name"] as? String)
self.GandfLogin(name: self.fbname!, email: self.fbemail!, post_image: (self.fburl!))
}
else
{
print(" check email nil ",checkemail ?? String.self)
self.fbid = (fbDetails["id"] as? String)
self.fbname = (fbDetails["name"] as? String)
self.GandfLogin(name: self.fbname!, email: self.fbid!, post_image: (self.fburl!))
}
}
else
{
print(error?.localizedDescription ?? "Not found")
}
})
}
}
Use soft unwraps instead of ! in most cases
Because it can lead to crashes if Facebook does not send data which you a looking for back
Do it this way:
guard let fbDetails = result as NSDictionary else {
//Show error to user or something else
return
}

Session Authentication Token Swift

I am relatively new to integrating APIs into Swift. I have a login page and I am trying to authenticate a user and create a session when they sign in. I found a code online that supposedly works for a lot of people, but I am having trouble actually getting the whole thing to work. I have concluded that something is going wrong beginning near this line which you will see in the code below because at the line before it I am able to get the auth token.
if let data_block = server_response["accessToken"] as? NSDictionary
I am including all of the relevant code and I would like to know what is going wrong, how to successfully authenticate and create the session, and get the segue to actually work.
override func viewDidLoad() {
super.viewDidLoad()
_login_button = "Login"
let preferences = UserDefaults.standard
if(preferences.object(forKey: "session") != nil)
{
LoginDone()
}
else
{
LoginToDo()
}
}
#IBAction func signIn() {
let username = emailLoginTextField.text
let password = passwordLoginTextField.text
if(username == "" || password == "")
{
return
}
if(_login_button == "Logout")
{
let preferences = UserDefaults.standard
preferences.removeObject(forKey: "session")
LoginToDo()
return
} else {
DoLogin(username!, password!)
}
}
func DoLogin(_ user:String, _ psw:String)
{
let url = URL(string: "http://agile-castle-10059.herokuapp.com/authentication")
let session = URLSession.shared
let request = NSMutableURLRequest(url: url!)
request.httpMethod = "POST"
let paramToSend = "username=" + user + "&password=" + psw + "&strategy=" + "local"
request.httpBody = paramToSend.data(using: String.Encoding.utf8)
let task = session.dataTask(with: request as URLRequest, completionHandler: {
(data, response, error) in
guard let _:Data = data else
{
return
}
let json:Any?
do
{
json = try JSONSerialization.jsonObject(with: data!, options: [])
}
catch
{
return
}
guard let server_response = json as? NSDictionary else
{
return
}
//problem occurs around here, nothing happens (assuming the data_block isn't being created for some reason)
if let data_block = server_response["data"] as? NSDictionary
{
if let session_data = data_block["session"] as? String
{
let preferences = UserDefaults.standard
preferences.set(session_data, forKey: "session")
DispatchQueue.main.async (
execute:self.LoginDone
)
}
}
})
task.resume()
}
func LoginToDo()
{
_login_button = "Login"
}
func LoginDone()
{
self.shouldPerformSegue(withIdentifier: "showHomeViewControllerFromSignIn", sender: self)
_login_button = "Logout"
}
I fixed a few things and figured it out
guard let server_response = json as? NSDictionary else
{
return
}
if let session_data = server_response["accessToken"] as? String
{
let preferences = UserDefaults.standard
preferences.set(session_data, forKey: "accessToken")
DispatchQueue.main.async (
execute:self.LoginDone
)
}
})
task.resume()
}

Get Photo URL Given a Photo ID: Facebook Graph API for iOS (Swift)

My problem boils down to this: fetch a photo URL given a photo ID. Ultimately, I need to do this for all of the photos a user of my iOS app is tagged in. I am able to get the IDs of the photos with the code:
// Create request for user's Facebook data
let request = FBSDKGraphRequest(graphPath:"me", parameters:["fields": "photos"])
request.startWithCompletionHandler {
(connection, result, error) in
if error != nil { }
else if let userData = result as? [String:AnyObject] {
let userPhotos = userData["photos"]
}
}
In the returned user data, I have access to the ID of each photo. Now, I defined a function which should (ideally) return the URL of a photo given it's ID. However, I really do not know how to correctly call the Facebook Graph API. This is what I have (note: hardcoded photo ID).
// Create request for user's Facebook data
let request = FBSDKGraphRequest(graphPath:"/{photo-id}?id=xxxxxxxxxxxxxxxxx", parameters:["fields": "link"])
request.startWithCompletionHandler {
(connection, result, error) in
if error != nil { }
else if let userData = result as? [String:AnyObject] {
let link = userData["link"]
print(link)
}
}
I'm quite confident the the graphPath parameter is wildly wrong. I made some "intelligent" guesses based on this: https://developers.facebook.com/docs/graph-api/reference/photo/
Any help you could give me would be much appreciated. Thanks!
Ok here is a simple answer, thanks for the answer above #user2585945
import UIKit
class FacePhotosViewController: UIViewController{
#IBOutlet weak var imgTest: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
if (FBSDKAccessToken.currentAccessToken() != nil)
{
print("We are good!")
}
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"photos,picture"])
graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in
if ((error) != nil)
{
// Process error
print("Error: \(error)")
}
else
{
print(result)
let resultdict = result.objectForKey("photos") as! NSDictionary
let data : NSArray = resultdict.objectForKey("data") as! NSArray
for i in 0..<data.count {
let valueDict : NSDictionary = data[i] as! NSDictionary
let id = valueDict.objectForKey("id") as! String
let created_time = valueDict.objectForKey("created_time") as! String
print("id: \(id) created_time: \(created_time) ")
}
}
})
let graphRequestPhoto : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "10156292340905363?type=large", parameters: ["fields":"picture, name, album, place"])
graphRequestPhoto.startWithCompletionHandler({ (connection, result, error) -> Void in
print(result)
if ((error) != nil)
{
// Process error
print("Error: \(error)")
}
else if let userData = result as? [String:AnyObject] {
let url = userData["picture"] as? String
print("link: \(url)")
let imgURL: NSURL! = NSURL(string: url!)
//lets' download profile photo
let session = NSURLSession.sharedSession()//session
let request: NSURLRequest = NSURLRequest(URL: imgURL!)//request
let dataTask = session.dataTaskWithRequest(request) { (data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in //session calls the request
if let noerror = data {
dispatch_async(dispatch_get_main_queue()) {
let image = UIImage(data: noerror)
self.imgTest.image = image
}
}
else {
print("Error: \(error!.localizedDescription)", terminator: "")
}
}
dataTask.resume()
}
})
}
}
let requestPhotos = FBSDKGraphRequest(graphPath:id_num, parameters:["fields":"picture, name, album, place"])
Where id_num is the ID number of the Facebook photo. Very simple.

How to get the cover photo from Facebook + Swift + Parse

I have a log in system in my app swift 2.0 integrated with Facebook, I'm able to get some user informations and profile_picture.
I'm wondering how to get the cover Image from the User logged :
let requestParameters = ["fields": "id, email, first_name, last_name, name, gender, cover"]
let userDetails = FBSDKGraphRequest(graphPath: "me", parameters: requestParameters)
userDetails.startWithCompletionHandler { (connection, result, error:NSError!) -> Void in
if(error != nil)
{
print("\(error.localizedDescription)")
return
}
if(result != nil)
{
let userId:String = result["id"] as! String
let userFirstName:String? = result["first_name"] as? String
let userLastName:String? = result["last_name"] as? String
let userEmail:String? = result["email"] as? String
let userName:String? = result["name"] as? String
let userGender:String? = result["gender"] as? String
let userCover:UIImage? = result["cover"] as? UIImage
print(requestParameters)
print(userDetails)
print(userCover)
print("\(userEmail)")
let myUser:PFUser = PFUser.currentUser()!
// Save first name
if(userFirstName != nil)
{
myUser.setObject(userFirstName!, forKey: "firstNameColumn")
}
//Save last name
if(userLastName != nil)
{
myUser.setObject(userLastName!, forKey: "lastNameColumn")
}
// Save email address
if(userEmail != nil)
{
myUser.setObject(userEmail!, forKey: "email")
}
// Save email address
if(userGender != nil)
{
if (userGender == "male"){
myUser.setObject("Masculino", forKey: "genderColumn")
} else {
myUser.setObject("Feminino", forKey: "genderColumn")
}
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
// Get Facebook profile picture
let userProfile = "https://graph.facebook.com/" + userId + "/picture?type=large"
let profilePictureUrl = NSURL(string: userProfile)
let profilePictureData = NSData(contentsOfURL: profilePictureUrl!)
if(profilePictureData != nil)
{
let profileFileObject = PFFile(data:profilePictureData!)
myUser.setObject(profileFileObject!, forKey: "photoUserColumn")
}
myUser.saveInBackgroundWithBlock({ (success:Bool, error:NSError?) -> Void in
if(success)
{
print("User details are now updated")
}
})
}
This code its not working just for the cover Image.
Any ideas?
Here's a working example using fb sdk in swift. I posted this answer in the other question as well but because this answer came up first for me on google I thought it'll be nice to put it here as well.
I needed to get the cover photo of a page so in the graphPath I used page id. This parameter can be easily changed to fit users / events / etc...
let request = FBSDKGraphRequest(graphPath: "\\(page.id)?fields=cover", parameters: [
"access_token": "your_access_token"
], HTTPMethod: "GET")
request.startWithCompletionHandler({(connection , result , error) in
if ((error) != nil) {
print("Error in fetching cover photo for \\(page.id): \(error)", terminator: "")
}
else {
if let data = result["cover"] as? NSDictionary {
self.fetchImageFromUrl(data["source"] as! String, cb: {(image: UIImage) -> Void in
//do something with image
})
}
})
func fetchImageFromUrl(url: String, cb: (UIImage) -> Void) {
let urlObj = NSURL(string: url)!
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
let data = NSData(contentsOfURL: urlObj)
dispatch_async(dispatch_get_main_queue(), {
let image = UIImage(data: data!)!
cb(image)
});
}
}
P.S - I'm a newbie in swift / ios so this code might not be the best. Comments will be appreciated.
It can be useful.
let emailRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"email,name, id,cover"], tokenString: result?.token.tokenString, version: nil, httpMethod: "GET")
_ = emailRequest?.start(completionHandler: { (nil, resultParameters, error) in
if(error == nil) {
if let cover = (params?["cover"] as? NSDictionary)["source"]{
var coverUrl = cover as? String
}
}
})

Resources