PFUser.becomeInBackground never returns in watchOS2 - ios

In watchOS2 I am getting the sessionToken from the iOS app with WCSession. That works great but when I try to call become in background it never returns. The console logs 1 and 2 but never makes it to print("3"). Any reason becomeInBackground wouldn't respond at all? Or is there a completely different way I should be going about this?
The sessionToken is coming from user.sessionToken in iOS.
print("1")
if let sessionToken = reply["sessionToken"] as? String {
print("2")
PFUser.becomeInBackground(sessionToken, block: { (user, error) in
print("3")
if let user = user as? User where error == nil {
print("success")
} else {
print(error)
}
})
}

Related

sign up flow segues to the wrong view controller and doesn't write to firestore either

So my goal is to have the correct user sign up and be shown the correct segue as well as the user info be written to Firestore. So I have a basic sign up function that gets triggered when the sign up button is pressed:
#IBAction func schoolSignupPressed(_ sender: UIButton) {
let validationError = validateFields()
let schoolName = schoolNameTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let schoolEmail = schoolEmailTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let schoolPassword = schoolPasswordTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let schoolID = schoolIDTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let schoolDistrict = schoolDistrictTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let dateCreated = Date()
if validationError != nil {
return
}
Auth.auth().createUser(withEmail: schoolEmail, password: schoolPassword) { (result, error) in
guard let signUpError = error?.localizedDescription else { return }
guard error == nil else {
self.showAlert(title: "Error Signing Up", message: "There was an error creating the user. \(signUpError)")
return
}
let db = Firestore.firestore()
guard let result = result else { return }
db.document("school_users/\(result.user.uid)").setData(["school_name":schoolName,
"school_id":schoolID,
"emailAddress": result.user.email ?? schoolEmail,
"remindersPushNotificationsOn": true,
"updatesPushNotificationsOn": true,
"schoolDistrict":schoolDistrict,
"time_created":dateCreated,
"userID": result.user.uid],
merge: true) { (error) in
guard let databaseError = error?.localizedDescription else { return }
guard error == nil else {
self.showAlert(title: "Error Adding User Info", message: "There was an error adding the user info. \(databaseError)")
return
}
}
let changeRequest = result.user.createProfileChangeRequest()
changeRequest.displayName = schoolName
changeRequest.commitChanges { (error) in
guard error == nil else {
return
}
print("School Name Saved!")
}
DispatchQueue.main.asyncAfter(deadline: .now()+1) {
self.performSegue(withIdentifier: Constants.Segues.fromSchoolSignUpToSchoolDashboard, sender: self)
}
}
}
This is the sign up function for the 'school' user, but the 'student' user is essentially the same thing just different fields and of course a different segue destination. Now maybe like a day ago or 2, I was testing this function out and it was working completely fine the user was succesfully signed up, the user info was written to firestore, the correct view controller was displayed, the only difference was I had some DispatchGroup blocks within the function because when i was running the method in TestFlight, there would be a couple of bugs that would crash the app.
So I figured since everything was working fine in the simulator, I archive the build, upload it to TestFlight and wait for it to be approved. It got approved last night and I ended up testing it out on my phone this morning to see it again, now when I try to sign up as either a school user or a student user, it segues to the wrong view controller every time and no info gets written to firestore, the user just gets saved in Firebase Auth and that is not the outcome I expect in my app.
I've checked the segue identifiers, I've checked the connections tab, and even though it was working amazing 24 hours ago, I still checked it all. I'm trying my best to really appreciate what Apple does for developers but I'm really starting to grow a hatred towards TestFlight, everything I do and run in the simulator works fantastic on Xcode, as soon as I run it in TestFlight, everything just goes out the window. I hate these types of bugs because you genuinely don't know where the issue is stemming from simply because you've used, if not very similar, the exact same method in every other previous situation.
The login process works fine on both student and school user, I'll show an example of the school user login method:
#IBAction func loginPressed(_ sender: UIButton) {
let validationError = validateFields()
let email = schoolEmailTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let password = schoolPasswordTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
if validationError != nil {
return
} else {
Auth.auth().signIn(withEmail: email, password: password) { (result, error) in
guard let signInError = error?.localizedDescription else { return }
let group = DispatchGroup()
group.enter()
guard error == nil else {
self.showAlert(title: "Error Signing In", message: "There was an issue trying to sign the user in. \(signInError)")
return
}
group.leave()
group.notify(queue: .main) {
DispatchQueue.main.asyncAfter(deadline: .now()+1) {
self.performSegue(withIdentifier: Constants.Segues.fromSchoolLoginToSchoolEvents, sender: self)
}
}
}
}
}
Pretty much the same for student users. If anyone can point out possible issues for this bug in the first code snippet that would be amazing. Thanks in advance.
Although it is helpful, removing the error.localizedDescription line brought everything back to normal.

Update Phone Number in Firebase Authentication - Swift

Is there a way to update the phone number in firebase auth? The thing is if the user entered a wrong number in registration then can I update the old number to new one then send the verification code in that new number? How can I achieve this?
There is a method on the User object called updatePhoneNumber, which seems to be what you want.
The documentation doesn't mention anything about what this does to the verification status, although I'd assume it indeed will require the new number to be verified too. Give it a try, and let me know if that isn't the case.
On the screen where the user has to enter their phone number:
var verificationId: String?
PhoneAuthProvider.provider().verifyPhoneNumber(phoneNumberTextField.text!, uiDelegate: nil) { (verificationID, error) in
if let error = error { return }
self.verificationId = verificationID else { return }
}
On the screen where the user has to enter the sms verification code:
guard let safeVerificationId = self.verificationId else { return }
let credential = PhoneAuthProvider.provider().credential(withVerificationID: safeVerificationId, verificationCode: smsTextField.text!)
Auth.auth().currentUser?.updatePhoneNumber(credential, completion: { (error) in
if let error = error { return }
})
You're welcome
Auth.auth().currentUser?.updatePhoneNumber(credential, completion: { (error) in
if error == nil {
print("succes")
}
})

iOS 12 - NSFaceIDUsageDescription all of a sudden not working

I was using NSFaceIDUsageDescription in my app and it was working. I deleted my app from my device and and re-uploaded (plugging my device into my mac and running from xcode) it and now I don't get the alert that my app would like to use FaceID, how come the alert is not appearing anymore? This is preventing me from using FaceID in my app.
class TouchIDAuth {
let context = LAContext()
func canEvaluatePolicy() -> Bool {
return context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil)
}
func authenticateUser(completion: #escaping (NSNumber?) -> Void) {
guard canEvaluatePolicy() else {
completion(0)
return
}
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: "Logging in with Touch ID") { (success, evaluateError) in
if success {
DispatchQueue.main.async {
completion(nil)
}
} else {
let response: NSNumber
switch evaluateError?._code {
case Int(kLAErrorAuthenticationFailed):
response = 2
case Int(kLAErrorUserCancel):
response = 3
case Int(kLAErrorUserFallback):
response = 4
default:
response = 1
}
completion(response)
}
}
}
}
And when I do this:
let touchMe = TouchIDAuth()
print(touchMe.canEvaluatePolicy())
The print returns false.
Is this an issue with my device? Or with NSFaceIDUsageDescription?
When your device exceeds the limit of incorrect attempts it usually returns false.
Try locking your device, then unlocking with face/touch ID and it starts working again in your app.
It should also return an error code why it is failling for evaluateError
Hope this was your case and solves the issue.

Cannot delete user during the registration when ios APP is killed firebase

I am now currently working on an IOS app. So I want to delete the user account during the registration when app get killed such as crash, or users force to close.
So I create NSNotification (appWillTerminate). As you can see from the code below, whenever app is closed at this page, the notification will get triggered, because I can see my print statement "hello world" in the console. I do not think there are any syntax error or anything. But it just can't delete the user from Authentication.
#objc func deleteAccount(notification: NSNotification){
print("hello world")
guard let userID = Auth.auth().currentUser?.uid else {return}
Database.database().reference().child("users").child(userID).removeValue(completionBlock: { (error, ref) in
if(error != nil){
print(error)
}
let user = Auth.auth().currentUser
user?.delete { error in
if let error = error {
print(error.localizedDescription)
// An error happened.
} else {
print("delete success")
do{
try Auth.auth().signOut()
}catch let logoutError{
print(logoutError)
}
}
}
})
}

App crashes after deleting user

So in my app I just made it so that the user can choose to delete their account, and that works out beautifully. However after the account is deleted the app crashes. I think this is because it is trying to search for a user but it's not there.
Here is my code:
let loginController = LoginController()
func deleteAccount() {
let user = Auth.auth().currentUser
let userId = Auth.auth().currentUser?.uid
let databaseUser = Database.database().reference().child("users").child(userId!)
user?.delete { error in
if let error = error {
print(error)
} else {
self.present(self.loginController, animated: true, completion: nil)
}
}
databaseUser.removeValue(completionBlock: { (error, ref) in
if error != nil {
print(error)
} else {
self.present(self.loginController, animated: true, completion: nil)
} //Without doing this the user's account only gets deleted in the Authentication, not the whole database. I think this is the problem here?
})
}
Thank you so much in advance!
First you need to delete the users database as to do that you would need the let userId = Auth.auth().currentUser?.uid which is only active if the user itself is on your backend, Then you go on to delete the auth.
func deleteAccount() {
let user = Auth.auth().currentUser
let userId = Auth.auth().currentUser!.uid
let databaseUser = Database.database().reference().child("users").child(userId)
databaseUser.removeValue(completionBlock: { (error, ref) in
if error != nil {
print(error)
} else {
user?.delete { error in
if let error = error {
print(error)
} else {
self.present(self.loginController, animated: true, completion: nil)
}
}
})
}
If this still doesn't work track down the lifecycle of the user using debugging tools....
You are implicitly unwrapping an optional in this line with !:
let databaseUser = Database.database().reference().child("users").child(userId!)
You should check whether it's nil in the first place with a guard statement:
guard let userId = Auth.auth().currentUser?.uid else {
return
}
let databaseUser = Database.database().reference().child("users").child(userId)
[...]
Moreover, your code logic is likely to be wrong, as you are getting nil for the userId before you can work with it.
The code order is not ideal because deleting the user also logs them out. So the code may be trying to access the users node after the user was logged out.
Also remember that Firebase is asynchronous and the only way to know a function has completed is when the code inside the closure executes i.e. in this case the databaseUser.removeValue may be firing before the delete user or sometimes it may not.
Code is faster than the internet so it's best to leverage the closures so you know when it's safe to proceed.
Try this sequence; noting that we don't try to delete the Firebase user until we know for sure the data in the users node was deleted. There could use more error checking but you get the idea.
let userRef = self.ref.child("users").child(uid)
userRef.setValue(nil, withCompletionBlock: { snapshot in
Auth.auth().currentUser?.delete(completion: { err in
if err != nil {
print(err?.localizedDescription)
}
})
})

Resources