Swift & Firebase - How to Store More User Data Other Than Email and Password

Swift & Firebase - How to store more user data other than email and password?

Yes, you need to use the realtime database to store your user data. So after creating it you can call the setValue().

FIRAuth.auth()!.createUserWithEmail(email, password: pwd, completion: { authData, error  in
if error == nil {
let userData = ["name": name,
"surname ": surname]
let ref = FIRDatabase.database().reference()
ref.child('users').child(authData!.uid).setValue(userData)
} else {
// handle error
}
})

Error saving user data to firebase in swift

In the Authentication section click on sign-in method. then in the bottom there is a option Manage sign-up quota. change the Current quota per hour . make it 1000. it may help you.

How can I create a user with multiple attributes in Firebase with Swift?

Traditionally, you would create a /users node in Firebase that contains any other info you want to store about that user.

Use the uid (user_id) as the node name for each user.

users
uid_0
name: "Bill"
food: "Pizza"
uid_1
name: "Ted"
food: "Tacos"

This question has been asked before so please try searching for questions similar to yours before asking.

A bit more info here Firebase Users Node

Swift / Firebase: How do I properly store a Facebook user into Firebase database when they create an account?

You should only update the values when the completion block graphRequest.startWithCompletionHandler is executed because that's when you will get your data from the Facebook!.
usersReference.updateChildValues needs to be inside graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in the completion block. I have attached it below. Try it!!

func showLoginView() {
let loginManager = FBSDKLoginManager()
loginManager.logInWithReadPermissions(fbPermissions, fromViewController: self, handler: { (result:FBSDKLoginManagerLoginResult!, error:NSError!) -> Void in

if ((error) != nil) {
print("Error loggin in is \(error)")
} else if (result.isCancelled) {
print("The user cancelled loggin in")
} else {
// No error, No cancelling:
// using the FBAccessToken, we get a Firebase token
let credential = FIRFacebookAuthProvider.credentialWithAccessToken(FBSDKAccessToken.currentAccessToken().tokenString)

// using the credentials above, sign in to firebase to create a user session
FIRAuth.auth()?.signInWithCredential(credential) { (user, error) in
print("User logged in the firebase")

// adding a reference to our firebase database
let ref = FIRDatabase.database().referenceFromURL("https://project-12345.firebaseio.com/")

// guard for user id
guard let uid = user?.uid else {
return
}

// create a child reference - uid will let us wrap each users data in a unique user id for later reference
let usersReference = ref.child("users").child(uid)

// performing the Facebook graph request to get the user data that just logged in so we can assign this stuff to our Firebase database:
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, email"])
graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in

if ((error) != nil) {
// Process error
print("Error: \(error)")
} else {
print("fetched user: \(result)")

// Facebook users name:
let userName:NSString = result.valueForKey("name") as! NSString
self.usersName = userName
print("User Name is: \(userName)")
print("self.usersName is \(self.usersName)")

// Facebook users email:
let userEmail:NSString = result.valueForKey("email") as! NSString
self.usersEmail = userEmail
print("User Email is: \(userEmail)")
print("self.usersEmail is \(self.usersEmail)")

// Facebook users ID:
let userID:NSString = result.valueForKey("id") as! NSString
self.usersFacebookID = userID
print("Users Facebook ID is: \(userID)")
print("self.usersFacebookID is \(self.usersFacebookID)")

//graphRequest.startWithCompletionHandler may not come back during serial
//execution so you cannot assume that you will have date by the time it gets
//to the let values = ["name":
//By putting it inside here it makes sure to update the date once it is
//returned from the completionHandler
// set values for assignment in our Firebase database
let values = ["name": self.usersName, "email": self.usersEmail, "facebookID": self.usersFacebookID]

// update our databse by using the child database reference above called usersReference
usersReference.updateChildValues(values, withCompletionBlock: { (err, ref) in
// if there's an error in saving to our firebase database
if err != nil {
print(err)
return
}
// no error, so it means we've saved the user into our firebase database successfully
print("Save the user successfully into Firebase database")
})
}
})


}
}
})
}

Save User's name in Firebase - Swift

You will create a new data table that stores that info. It won't be done in the create user function.

// create a reference to  the DB
ref = Database.database().reference(fromURL: "https://your-project-name.firebaseio.com/")
//variables to store data
var myID : String?
var myName : String?
var myNumber : String?
var myEmail : String?

// creating the save user function
func saveUser(_ completion: @escaping(_ error: Error?) -> Void) {
if PageDataSource.sharedInstance.crudIsAvailable == true {
let usersRef = ref.child("users")
let myUserRef = usersRef.child(id)
myUserRef.updateChildValues(["User ID": id,
"Name": myName,
"Email": myEmail,
"Phone": .myNumber], withCompletionBlock: { (error, ref) in
if error != nil {
completion(error!)
} else {
completion(nil)
}
})
} else {
completion(NSError(domain: "Unavailable", code: 0, userInfo: nil))
}
}

// call the method like this to perform the save
func storeUser(completion: @escaping(_ completed: Bool, _ error: NSError?)-> Void) {
if let user = Auth.auth().currentUser {
myID = user.uid
myName = user.displayName
myEmail = user.email
// etc.,
completion(true,nil)
} else {
completion(false,NSError(domain: "No Current User", code: 1, userInfo: nil))
}
}

how to save username and email to firebase

if you want to save the users by their username yes you can do as follow

@IBAction func SignUp(_ sender: Any) {
if username.text != "", email.text != "", password.text != "", fullname.text != "" {

activityIndicator.startAnimating()

Auth.auth().createUser(withEmail: email.text!, password: password.text!, completion: { (user, error) in
if error != nil {
AlertController.showAlert(self, titel: "Error", message:".Fill all fields\n .User do exists\n .Network error ")
self.activityIndicator.stopAnimating()
return
}
let uid = user?.uid // here you are providing userID
let storageRef = Storage.storage().reference(forURL: "gs://.........com").child("profile_image").child(uid!)
if let profileImg = self.selectedImage, let imageData = UIImageJPEGRepresentation(profileImg, 0.1){
storageRef.putData( imageData, metadata: nil, completion: { (metadata, error) in
if error != nil{
return
}
let profileImageUrl = metadata?.downloadURL()?.absoluteString
let ref = Database.database().reference()
let usersReferance = ref.child("users")
// let newUserReferance = usersReferance.child(uid!) //here in ref you are creating a node with UID

//use your username
let newUserReferance = usersReferance.child(username.text!)

//set child values here as you doing
newUserReferance.setValue(["fullname": self.fullname.text, "username": self.username.text, "email": self.email.text, "password": self.password.text, "profileImageUrl": profileImageUrl])
})
}
self.dismiss(animated: true, completion: nil)
self.activityIndicator.stopAnimating()
})
}
}

For 2 . 1) I do not think it will be a bette approach as if you set node with username if while signUp other user filled same username data will be replaced with new data

2) if you use some checks that username is valid or not it will work , but just for concern need a additional reference in database for it to check username is available or not

-- Do as check in whole database that username is taken or not

-- or make a node with list of usernames and and get all those in array and check offline for a fast response with textfield validations or can even put observe event

Account linking with different emails

You don't really know they are the same users if their emails differ (anyone can create an email that is similar to another email). So you shouldn't want to build functionality that automatically links the 2 users.

That said, you can manually use the linkWithCredential API to link the Apple credential to the email/password user provided that user is already signed in, but I think you shouldn't require this unless the email/password user wants to do so (via some button to link their Apple account).

Notify User of New Signin with Firebase - Swift/Xcode

Super simple; have a field in your user document that stores a device name along with its status.

You app will be observing this users document and when something changes, all of the users devices will be notified of that change.

Let me set this up; here's a basic Firestore structure

users
uid_0
userName: "Jay"
devices:
device_0: offline
device_1: offline

When the app starts, it will add an observer to this users document (using the uid as the documentId)

func observeUser() {
let usersCollection = self.db.collection("users")
usersCollection.document("uid_0").addSnapshotListener { (documentSnapshot, err) in

guard let document = documentSnapshot else {
print("Error fetching document: \(err!)")
return
}

let device = document.get("devices") as! [String: String]
print(device)
}
}

Now in the Firestore closure shown above, if a users device changes status, offline to online for example, it outputs all of the devices to console. You would take whatever action is needed when the device changes status.

Keep in mind that if a NEW device is added, that event will also fire so you could present a message in the UI "A new device was added!"

So then some testing code that toggles the device_0 status from offline to online. I have a button click that does self.status = !self.status and then calls the toggleStatus function

var status = false
func toggleStatus() {
var isOnline = ""
if self.status == false {
isOnline = "online"
} else {
isOnline = "offline"

}
let userCollection = self.db.collection("users")
let thisDevice = "device_0"

let devicesDict = [
"devices":
[thisDevice: isOnline] //sets device_0 to offline or online
]

let document = usersCollection.document("uid_0").setData(devicesDict, merge: true)
}

In a nutshell, when a user authenticates with a device for the first time, it would perhaps ask for a device name, or craft one from the devices mac address or something under the hood. That device name is stored in the users document/devices with it's online status.

The device name would be stored locally as well, in user defaults for example so it's automatically sent up to Firestore upon login.

The end result here is that if any users devices change status; offline to online or vice versa, or any device is added or removed all of the devices are notified of that event.



Related Topics



Leave a reply



Submit