I have been searching since few days on how I can get user details based on his/her Twitter account ,I'm using twitter login in my application
& I haven't found anything about this in Swift, so i'm asking!
How can I get the username & email & uprofile Image of a logged in User with Parse from Twitter in order to save them on parse cloud?
You can access the username and userID of the logged-in user pretty easily. Inside most Twitter login methods you'll see something like this:
#IBAction func loginTwitter(sender: UIBarButtonItem) {
Twitter.sharedInstance().logInWithCompletion {
(session, error) -> Void in
if (session != nil) {
print(session?.userName)
print(session?.userID)
} else {
print("error")
}
}
}
Twitter does not expose the email address of users as far as I'm aware.
For the profile image you'll need to send a GET request. Here is some code that may not be up to date with the latest TwitterKit version but should at least give you a sense of how the request should be formatted.
func getUserInfo(screenName : String){
if let userID = Twitter.sharedInstance().sessionStore.session()!.userID {
let client = TWTRAPIClient(userID: userID)
let url = "https://api.twitter.com/1.1/users/show.json"
let params = ["screen_name": screenName]
var clientError : NSError?
let request = Twitter.sharedInstance().APIClient.URLRequestWithMethod("GET", URL: url, parameters: params, error: &clientError)
client.sendTwitterRequest(request) { (response, data, connectionError) -> Void in
if let someData = data {
do {
let results = try NSJSONSerialization.JSONObjectWithData(someData, options: .AllowFragments) as! NSDictionary
print(results)
} catch {
}
}
}
}
}
You'll need to go through the JSON that gets returned and find "profile_image_url_https" a couple levels down.
Good Luck!
in Swift 4.2 and Xcode 10.1
It's getting email also.
import TwitterKit
#IBAction func onClickTwitterSignin(_ sender: UIButton) {
TWTRTwitter.sharedInstance().logIn { (session, error) in
if (session != nil) {
let name = session?.userName ?? ""
print(name)
print(session?.userID ?? "")
print(session?.authToken ?? "")
print(session?.authTokenSecret ?? "")
let client = TWTRAPIClient.withCurrentUser()
client.requestEmail { email, error in
if (email != nil) {
let recivedEmailID = email ?? ""
print(recivedEmailID)
}else {
print("error--: \(String(describing: error?.localizedDescription))");
}
}
//To get profile image url and screen name
let twitterClient = TWTRAPIClient(userID: session?.userID)
twitterClient.loadUser(withID: session?.userID ?? "") {(user, error) in
print(user?.profileImageURL ?? "")
print(user?.profileImageLargeURL ?? "")
print(user?.screenName ?? "")
}
let storyboard = self.storyboard?.instantiateViewController(withIdentifier: "SVC") as! SecondViewController
self.navigationController?.pushViewController(storyboard, animated: true)
}else {
print("error: \(String(describing: error?.localizedDescription))");
}
}
}
For logout
#IBAction func onClickTwitterSignout(_ sender: UIButton) {
let store = TWTRTwitter.sharedInstance().sessionStore
if let userID = store.session()?.userID {
print(store.session()?.userID ?? "")
store.logOutUserID(userID)
print(store.session()?.userID ?? "")
self.navigationController?.popToRootViewController(animated: true)
}
}
Related
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
}
I'm writing some code for a login page where we take a username and find the associated password. Temporarily I've said "if email exists under username, complete segue". However when I call the method getEmail which checks for email, it never seems to exit properly with a full email address. print(email) returns the right email address so I know I've retrieved it and it's correct. I never seem to make it out of the method though. Really stuck here! Heres my code:
func getEmail(name: String) -> String{
var email = ""
ref = Database.database().reference()
self.ref.child("Users").child(name).observeSingleEvent(of: .value, with: { (snapshot) in
if let user = snapshot.value as? [String:Any] {
print("email retrieved");
email = user["email"] as! String;
print(email)
return;
}
else{
print("email could not be retrieved from the user.");
}
}){ (error) in
print("Could not retrieve object from database because: ");
print((Any).self);
}
return email;
}
func validate(){
if(Username.text == ""){
EmptyStringAlert();
}
let email = getEmail(name: Username.text!);
print(email)
if(email == ""){
return;
}
performSegue(withIdentifier: "LoginSuccess", sender: nil)
}
The call to Firebase is asynchronous, so you have to use completion in your function to get the data. Try something like this:
func getEmail(name: String, completion: #escaping (Bool, Any?, Error?) -> Void) {
var email = ""
ref = Database.database().reference()
self.ref.child("Users").child(name).observeSingleEvent(of: .value, with: { (snapshot) in
if let user = snapshot.value as? [String:Any] {
email = user["email"] as! String
completion(true, email, nil)
}
else {
completion(false, nil, nil)
}
}){ (error) in
completion(false, nil, error)
}
}
func validate(){
if(Username.text == ""){
EmptyStringAlert();
}
getEmail(name: Username.text!) { (success, response, error) in
guard success, let email = response as? String else {
print(error ?? "Failed getEmail..")
return
}
if(email == "") {
return
}
performSegue(withIdentifier: "LoginSuccess", sender: nil)
}
}
Well this is general question, what I want that If anyone login on my using Google-Auth/Email-Password login and I can gets it Facebook profile info's too? Is these steps are correct:
Login with google and insert the entry in Firebase.
On Profile Edit there is button named "Get Your Facebook Data".
On clicking button with the help of FBSDKLoginManager I connect with user fb's profile and make FBSDKGraphRequest.
After getting result save it to database.
Suggest any other way if its possible?!
Here is Working code of Xcode 8.3 along with Swift 3.1 :
Follow these steps to get Facebook data :-
Step 1:
import FBSDKCoreKit
import FBSDKLoginKit
Step 2: Conforms delegate .
FBSDKLoginButtonDelegate
Step 3: Login Button IBAction Method .
//Facebook Login Action
#IBAction func facebookLoginAction(_ sender: Any) {
//Fb login process
let fbLoginManager : FBSDKLoginManager = FBSDKLoginManager()
fbLoginManager.loginBehavior = .native
fbLoginManager.logOut()
fbLoginManager.logIn(withReadPermissions: ["email"], from: self) { (result, error) -> Void in
if (error == nil){
let fbloginresult : FBSDKLoginManagerLoginResult = result!
if fbloginresult.isCancelled {
}
else if (fbloginresult.declinedPermissions != nil){
if(fbloginresult.grantedPermissions.contains("email")) {
self.getFBUserData()
}
}
}
}
}
Step 4: Get Facebook Data following way .
func getFBUserData(){
if((FBSDKAccessToken.current()) != nil){
FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"first_name, last_name,email, picture.type(large),gender"]).start(completionHandler: { (connection, result, error) -> Void in
if (error == nil){
let newResult = result as AnyObject
let email = newResult["email"] as? String ?? ""
print("Your Email = \(email)")
let firstName = newResult["first_name"] as? String ?? ""
let lastName = newResult["last_name"] as? String ?? ""
print(FBSDKAccessToken.current())
let gender = newResult["gender"] as? String ?? ""
let id = newResult["id"] as? String ?? ""
print("the access token is \(FBSDKAccessToken.current().tokenString)")
let accessToken = FBSDKAccessToken.current().tokenString
//self.signInUser()
}
})
}
}
Feel free to comment on this , Hope it solve your issue. Thanks
I am having some trouble in my code. I gave the permission of "user_photos" in "loginwithreadpermission" but still not getting the users album. I also tried this "fbuserid/albums" but this is also not working for me. Please help me what I am doing wrong.
This is my Login Code:
#IBAction func facebookLogin(sender: AnyObject)
{
let facebookLogin = FBSDKLoginManager()
facebookLogin.logOut()
facebookLogin.logInWithReadPermissions(["email" , "user_photos"], fromViewController: nil) { (facebookResult, facebookError) in
if facebookError != nil {
print("Login Failed. Error: \(facebookError)")
}
else {
if !(facebookResult.isCancelled)
{
let accessToken = FBSDKAccessToken.currentAccessToken().tokenString
if accessToken != nil
{
token = accessToken
let credential = FIRFacebookAuthProvider.credentialWithAccessToken(accessToken)
print("1")
FIRAuth.auth()?.signInWithCredential(credential)
{
(user, error) in
if error != nil
{
print("Error Firebase: \(error)")
}
else
{
if self.userEmails.contains(user!.email!)
{
print("User Already Exist")
NSUserDefaults.standardUserDefaults().setValue(user?.uid, forKey: KEY_UID)
USER_UID = (user?.uid)!
print("id:\(USER_UID)")
LOGIN_FLAG = 1
FaceBookFlag = 1
self.performSegueWithIdentifier("fbLogin", sender: nil)
}
else if user!.email != nil
{
print("Creating a User Data in FB")
var request = FBSDKGraphRequest(graphPath:"me", parameters: ["fields":"email,first_name,age_range"]);
request.startWithCompletionHandler({ (connection, result, error) in
if error == nil
{
print("res: \(result)")
if let dob = result.valueForKey("age_range") as? [String: AnyObject]
{
print("dd: \(dob["min"]!)")
self.dateOfBirth = String(dob["min"]!)
print("dob: \(dob) , date: \(self.dateOfBirth)")
print(" date: \(self.dateOfBirth!)")
}
}
else
{
print("error:: \(error)")
}
let displayName = user?.displayName!.componentsSeparatedByString(" ")
let firstName = displayName![0]
let lastName = displayName![1]
print("url: \(user?.photoURL)")
let profilePicUrl = user?.photoURL
let picture = String(profilePicUrl!)
let userEmail = user!.email!
let _user = ["username": "\(firstName+lastName)","emailAddress": "\(userEmail)", "dateOfBirth": "\(self.dateOfBirth!)"]
ref.child("users").child(user!.uid).setValue(_user)
ref.child("users").child(user!.uid).child("images").setValue([picture])
NSUserDefaults.standardUserDefaults().setValue(user?.uid, forKey: KEY_UID)
USER_UID = (user?.uid)!
LOGIN_FLAG = 1
FaceBookFlag = 1
//Segue to reveal view controller
self.performSegueWithIdentifier("fbLogin", sender: nil)
})
}
}
}
}
}
}
}
}
And This is my Code where I am requesting to give me the albums of current user :
func getAlbums()
{
//for sake of running i hardcoded the FBuserId.
let fbid = "758111074330935"
//169682503464671/photos
let graphRequest = FBSDKGraphRequest(graphPath: "/\(fbid)/albums", parameters: ["fields":"photos,picture"] , HTTPMethod: "GET")
graphRequest.startWithCompletionHandler { (connection, result, error) in
if error != nil
{
print(error)
}
else
{
print("rr:\(result)")
let value = result.valueForKey("data")
print("value:\(value) ... \(result["data"])")
if let graphData = result.valueForKey("data") as? [AnyObject]
{
print("array of Any")
for obj in graphData
{
print("id: \(obj.valueForKey("id")!)")
let id = String(obj.valueForKey("id")!)
self.albumsId.append(id)
//Also save the album link here to.
}
}
}
You have a wrong set of fields for this type of request.
Check this doc to verify the fields that are available: https://developers.facebook.com/docs/graph-api/reference/v2.7/album
In particular, I'm getting the following error (which is self-explained):
{
"error": {
"message": "(#100) Unknown fields: email,first_name.",
"type": "OAuthException",
"code": 100,
"fbtrace_id": "G0POfi9dWkb"
}
}
I've linked my app to both the Facebook SDK and Parse, but now I'm trying to integrate Facebook's login with Parse but keep running into issues. My current issue is that the app runs, but when I press the FBSDKLoginButton, it will go to safari and ask for permissions (as it should), but then when pressing okay, it simply returns to the app's login screen like nothing happened and does not perform the segue to the rest of the app. I also checked Parse and it did not create a new PFUser. I will post the code I think may be relevant from my LoginViewController below (that means the code will be missing sections like my viewDidLoad for it has nothing in it that affects the login process):
import UIKit
import Parse
import FBSDKCoreKit
import FBSDKLoginKit
protocol LoginViewControllerDelegate {
func onRegister(loginViewController : LoginViewController)
func onFacebookLogin(loginViewController : LoginViewController)
func onLogin(loginViewController : LoginViewController)
}
class LoginViewController: UIViewController {
#IBAction func onFacebookLogin(sender: AnyObject?) {
// Set permissions required from the facebook user account
let permissions = [ "user_about_me", "user_relationships", "user_location", "user_birthday", "public_profile", "user_friends", "user_email", "user_gender"]
// Login PFUser using Facebook
PFFacebookUtils.logInInBackgroundWithReadPermissions(permissions, block: {
(user: PFUser?, error: NSError?) -> Void in
if let user = user {
if user.isNew {
println("User signed up and logged in through Facebook!")
self.loadData()
self.performSegueWithIdentifier("loggedIn", sender: self)
} else {
println("User logged in through Facebook!")
self.performSegueWithIdentifier("loggedIn", sender: self)
}
if self.delegate != nil {
self.delegate!.onFacebookLogin(self)
}
} else {
println("Uh oh. The user cancelled the Facebook login.")
}
})
}
func loadData(){
let request:FBSDKGraphRequest = FBSDKGraphRequest()
request.startWithCompletionHandler { (connection:FBSDKGraphRequestConnection!, result:AnyObject!, error:NSError!) -> Void in
if error == nil{
if let dict = result as? Dictionary<String, AnyObject>{
let name:String = dict["first_name"] as AnyObject? as! String
let facebookID:String = dict["id"] as AnyObject? as! String
let email:String = dict["email"] as AnyObject? as! String
let birthday:String = dict["birthday"] as AnyObject? as! String
let gender:String = dict["gender"] as AnyObject? as! String
let hostCount:Int = 0
let attendCount:Int = 0
let pictureURL = "https://graph.facebook.com/\(facebookID)/picture?type=large&return_ssl_resources=1"
var URLRequest = NSURL(string: pictureURL)
var URLRequestNeeded = NSURLRequest(URL: URLRequest!)
NSURLConnection.sendAsynchronousRequest(URLRequestNeeded, queue: NSOperationQueue.mainQueue(), completionHandler: {(response: NSURLResponse!,data: NSData!, error: NSError!) -> Void in
if error == nil {
var picture = PFFile(data: data)
PFUser.currentUser()!.setObject(picture, forKey: "profilePicture")
PFUser.currentUser()!.saveInBackground()
}
else {
println("Error: \(error.localizedDescription)")
}
})
PFUser.currentUser()!.setValue(name, forKey: "name")
PFUser.currentUser()!.setValue(email, forKey: "email")
PFUser.currentUser()!.setValue(birthday, forKey: "birthday")
PFUser.currentUser()!.setValue(gender, forKey: "gender")
PFUser.currentUser()!.setValue(hostCount, forKey: "hostCount")
PFUser.currentUser()!.saveInBackground()
}
}
}
}
}
I use this solution, hope it helps you. If you have a question on it, I can answer :)
func notLoggedIn() -> Bool {
let user = PFUser.currentUser()
// here I assume that a user must be linked to Facebook
return user == nil || !PFFacebookUtils.isLinkedWithUser(user)
}
func loggedIn() -> Bool {
return !notLoggedIn()
}
func performNewUser(){
if notLoggedIn() {
return
}
let user = PFUser.currentUser() // Won't be nil because is logged in
// RETURN IF WE ALREADY HAVE A USERNAME AND FBID (note that we check the fbId because Parse automatically fills in the username with random numbers)
if let fbId = user["fbId"] as? String {
if !fbId.isEmpty {
displayAlert("Erreur", error: "Il existe déjà un utilisateur avec ce compte Facebook")
println("we already have a username and fbId -> return")
return
}
}
// REQUEST TO FACEBOOK
println("performing request to FB for username and IDF...")
if let session = PFFacebookUtils.session() {
if session.isOpen {
println("session is open")
FBRequestConnection.startForMeWithCompletionHandler({ (connection: FBRequestConnection!, result: AnyObject!, error: NSError!) -> Void in
println("done me request")
if error != nil {
println("facebook me request - error is not nil :(")
} else {
println("facebook me request - error is nil :)")
println(result)
println(result.name)
println(result.objectID)
// Save to Parse:
var FBSession = PFFacebookUtils.session()
var currentUser = PFUser.currentUser()
var userToSave = PFObject(className: "Utilisateurs")
var accessToken = FBSession.accessTokenData.accessToken
let url = NSURL(string: "https://graph.facebook.com/me/picture?type=large&return_ssl_resources=1&access_token="+accessToken)
let urlRequest = NSURLRequest(URL: url!)
NSURLConnection.sendAsynchronousRequest(urlRequest, queue: NSOperationQueue.mainQueue(), completionHandler: {
response, data, error in
let image = UIImage(data: data)
currentUser["image"] = data
currentUser.save()
self.performSegueWithIdentifier("connexionApplicationInscriptionViaFacebook", sender: self)
})
let firstName = result["first_name"] as String
let status = "Client"
currentUser.username = result["last_name"] as String
currentUser.email = result.email
userToSave.setObject(currentUser.username, forKey: "nom")
userToSave.setObject(currentUser.username, forKey: "username")
userToSave.setObject(firstName, forKey: "prenom")
userToSave.setObject(status, forKey: "status")
currentUser.setValue(self.tfPrenom.text, forKey: "name")
currentUser.setValue(result.objectID, forKey: "fbId")
currentUser.saveEventually() // Always use saveEventually if you want to be sure that the save will succeed
}
})
}
}
}
After updating to Parse 1.7.4 and deleting the old PFFacebookUtils Framework (keeping the PFFacebookUtilsV4) seems to have fixed the problem by itself! I hope this answer helps other people with the same problem.