During SignUp on my app, I want to retrieve information, such as first name, from iCloud,I then want to store this in my own cloud kit database. How do I access user information from iCloud, without having to ask the user themselves for these relevant fields?
I was able to get it working with this in XCode 8 iOS 10 beta 2:
CKContainer.default().requestApplicationPermission(.userDiscoverability) { (status, error) in
CKContainer.default().fetchUserRecordID { (record, error) in
CKContainer.default().discoverUserIdentity(withUserRecordID: record!, completionHandler: { (userID, error) in
print(userID?.hasiCloudAccount)
print(userID?.lookupInfo?.phoneNumber)
print(userID?.lookupInfo?.emailAddress)
print((userID?.nameComponents?.givenName)! + " " + (userID?.nameComponents?.familyName)!)
})
}
}
Use CKContainer.discoverUserIdentity(withUserRecordID:) in combination with CKContainer.fetchUserRecordID to get a CKUserIdentity object for the current user. You can then use a PersonNameComponentsFormatter to get their name from the nameComponents property of the identity.
let container = CKContainer.defaultContainer()
container.fetchUserRecordIDWithCompletionHandler { (recordId, error) in
if error != nil {
print("Handle error)")
}else{
self.container.discoverUserInfoWithUserRecordID(
recordId!, completionHandler: { (userInfo, error) in
if error != nil {
print("Handle error")
}else{
if let userInfo = userInfo {
print("givenName = \(userInfo.displayContact?.givenName)")
print("familyName = \(userInfo.displayContact?.familyName)")
}else{
print("no user info")
}
}
})
}
}
Related
I'm new to firebase, singing with gmail on main view. after user singing, I'm saving the userinfo based on documentId, if the user already existed(already logged with gmail) person no need to save the information just update information of existed. So I tried some of the code, but I will not achieved what I'm expecting.
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
if let error = error{
print(error.localizedDescription)
return
}
guard let authentication = user.authentication else { return }
let credential = GoogleAuthProvider.credential(withIDToken: (authentication.idToken)!, accessToken: (authentication.accessToken)!)
Auth.auth().signIn(with: credential, completion: { (user, error) in
if let error = error {
print("Login erro \(error.localizedDescription)")
return
}
Here I check all document id in firestore
self.db.collection("pruser").getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in querySnapshot!.documents {
// print("\(document.documentID) => \(document.data())")
print("\(document.documentID)")
Here I have to check with existed Document id's and current user
Document id. If already existed update info, if not set the values on Document Id but when try with this code
self.ref = self.db.collection("pruser").document()
let doc = self.ref?.documentID
print("printdoucment id ",doc!)
}
}
}
}
userid: vnRsxNjJePfwRcAWOLy1iByhV352 Doucment id: PKKLapD9xE9kNNvntI8X
userId: vnRsxNjJePfwRcAWOLy1iByhV352 Doucment id:
pxjiVXEgbZgFke3Mijk5
when I logged with existed email also documentid coming different, every login time DocumentId is coming different how achieve this issue?
document() with no parameters generates a new document ID every time you call it. You have to pass it a parameter to specify the document ID, if that's what you want.
self.db.collection("pruser").document(user.uid)
Try adding this to viewDidLoad():
GIDSignIn.sharedInstance()?.presentingViewController = self
GIDSignIn.sharedInstance()?.delegate = self
And replace the 7-11 lines with:
Auth.auth().signIn(with: credentials) {
(authResult, error) in
if let error = error {
print(error.localizedDescription)
}else{
print("Log in successful")
This should sign in the user.
As for DocumentID, I don't think that in your code you've linked each user to each DocumentID. You need to change the or read the DocumentID based on the userid.
hello, i need some help with function and or possibly closures in that function. I want my function to check the firestore users collection for duplicate documents (usernames). If a duplicate is found i want to display a message, if a duplicate is not found, create a new user. i have folowing code:
func checkIfUserExists(username: String, completion: #escaping (Bool) -> Void) {
let docRef = db.collection("users").document(username)
docRef.getDocument { (document, error) in
if error != nil {
print(error)
} else {
if let document = document {
if document.exists {
completion(true)
} else {
completion(false)
}
}
}
}
}
and i call the function with:
if let username = textField.text, username.count > 8 { // Username needs to be more then 8 Char
checkIfUserExists(username: username) { (doesExist) in
if doesExist {
print("user exists")
} else {
print("new User can be created")
}
}
} else {
print("Username needs to be more then 8 char")
}
}
It works, but i have the feeling it is not good practice and i'm making detours. Is this the right way to do it ?
I think the way you're doing it now should work well, but another option to prevent you from having to do a read of the database before writing is to use security rules. For example, if this is the structure of your users collection...
users: [
username1: { // doc ID is the username
userid: abcFirebaseUserId, // a field for the uid of the owner of the username
//...etc
}
]
...then you can use the following rules:
match /users/{username} {
allow create: if request.auth.uid != null;
allow update, delete: if resource.data.userId = request.auth.uid;
}
This allows any authenticated user to create a new username, but only the owner of that username can update it or delete it. If you aren't allowing users to change their username, you wouldn't even have to worry about the second rule. Then, in the client, you go right to creating a username, like so:
func createUsername(username: String, completion: #escaping (String?) -> Void) {
guard let userId = Auth.auth().currentUser.uid else {
completion("no current user")
return
}
let docRef = db.collection("users").document(username)
docRef.setData(data:[userId: userId]) { error in
if let error = error {
completion(error.debugDescription)
} else {
completion(nil)
}
}
}
This would write the new username to the database and pass an error to the closure if there is one. If the username already exists, an insufficient permissions error would be present. When checking if the user exists, you could display the error or alert the user however you wanted.
createUsername(username: username) { err in
if let err = err {
print("user exists")
} else {
print("new User has been created")
}
}
Just a suggestion though. I think they way you're doing it now is fine, too!
How do I get the current UserId of user? I'm using the following code:
CKContainer.default().requestApplicationPermission(.userDiscoverability) { (status, error) in
CKContainer.default().fetchUserRecordID { (record, error) in
if #available(iOS 10.0, *) {
CKContainer.default().discoverUserIdentity(withUserRecordID: record!, completionHandler: { (userID, error) in
self.currentuserID = userID?.userRecordID
print("user record id")
print(userID)
})
} else {
// Fallback on earlier versions
}
}
However at the end currentUserID is set to nill? Does anyone know how to successfully gain permission and get the current user id?
As far as I know, you don't need permission from requestApplicationPermission to get the CloudKit user's unique ID. You can do this...
CKContainer.default().fetchUserRecordID() { recordID, error in
//...
}
Without ever calling this...
CKContainer.default().requestApplicationPermission(.userDiscoverability){ status, error in
//...
}
The .userDiscoverability is just so other app users can locate your unique user record through an email or phone number.
I hope that helps. :)
You should check the status value before fetch user information. It could be something like this...
CKContainer.default().requestApplicationPermission(.userDiscoverability) { (status, error) in
switch status
{
case .granted:
print("iCloud is OK")
case .initialState:
print("The user has not yet decided whether to grant this permission")
return
case .couldNotComplete:
print("An error occurred during the getting or setting of the app permission")
if let error = error
{
print("err # \(#function) -> \(error.localizedDescription)")
}
return
case .denied:
print("The user denied access to the permission.")
return
}
CKContainer.default().fetchUserRecordID { (record, error) in
if #available(iOS 10.0, *)
{
CKContainer.default().discoverUserIdentity(withUserRecordID: record!, completionHandler: { (userID, error) in
self.currentuserID = userID?.userRecordID
print("user record id")
print(userID)
})
}
else
{
// Fallback on earlier versions
}
}
I am trying to get the CloudKit User's first and last name.
Here is the code:
container.fetchUserRecordID { (recordID, error) in
guard error == nil else { return }
guard let recordID = recordID else { return }
self.container.discoverUserInfo(withUserRecordID: recordID) { (info, fetchError) in
// use info.firstName and info.lastName however you need
print(info?.displayContact?.givenName)
}
}
I am getting the following message when running the print line: [LogFacilityCK] Got a user discovery progress callback with no user identity: {
FetchInfo = ">";
}
The info variable is showing as nil when debugging.
Any thoughts?
Here's how I got the users' name:
CKContainer.default().requestApplicationPermission(.userDiscoverability) { (status, error) in
CKContainer.default().fetchUserRecordID { (record, error) in
CKContainer.default().discoverUserIdentity(withUserRecordID: record!, completionHandler: { (userID, error) in
userName = (userID?.nameComponents?.givenName)! + " " + (userID?.nameComponents?.familyName)!
print("CK User Name: " + userName)
})
}
}
I am not familiar with the new Firebase. How do I create new users? The code below I Signup and auth new user. If I need to create this new user under "Customers" in Firebase Database, what code do I need to add? Thanks!
FIRAuth.auth()?.createUserWithEmail(email, password: password, completion: { (user, err) in
if err != nil {
self.showAlert("Can't Register", msg: "Please enter email and password")
} else {
NSUserDefaults.standardUserDefaults().setValue(user?.uid, forKey: "uid")
FIRAuth.auth()?.signInWithEmail(email, password: password, completion: { (user, error) in
})
self.performSegueWithIdentifier("toSecondVC", sender: self)
}
})
FIRAuth.auth()?.createUserWithEmail(email, password: password, completion: { (user, err) in
if err != nil {
self.showAlert("Can't Register", msg: "Please enter email and password")
} else {
NSUserDefaults.standardUserDefaults().setValue(user?.uid, forKey: "uid")
FIRDatabase.database().reference().child("Customers").setValue([user!.uid : "true"])
//Or if you want to save the users Details too:-
/*
FIRDatabase.database().reference().child("Customers").setValue([user!.uid : ["email" : email,"password" : password]])
*/
self.performSegueWithIdentifier("toSecondVC", sender: self)
}
})
Also might i suggest reading this : Firebase iOS - Save Data
The answer above is correct, but I'd recommend doing it this way:
var values = [Any : Any] // This is a dictionary where you can store user details
values["userUID"] = // user's uid
values["usersName"] = // user's name
// etc.
let customerRef = databaseReference.child("Customers") // You could also add a child with the user's UID in order to identify each user
customerRef.updateChildValues(values, withCompletionBlock: { (error, ref) in
if error != nil {
// display error.code and error.localizedDescription to user if needed
} else if ref != [] {
// Success!
// If needed, save the user to NSUserDefaults and perfrom a segue to another ViewController
} else {
// There was an error, but not sure what happened. Let the user know how they can fix the problem (maybe add the details to the database later)
}
})