Firebase DataBase - ios

Problem: For some reason the data is not being sent to my database in firebase. Can anyone figure out why the information is not being sent?
I highlighted the code with //******** to show where I am sending it.
Rules:
{
"rules": {
".read": "true",
".write": "true"
}
}
import UIKit
import Firebase
import FirebaseDatabase
import KeychainSwift
class SignUpController: UIViewController {
//INPUT - from keyboard email & password
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passwordField: UITextField!
//Data Base Initialization
//var ref: FIRDatabaseReference!
let dataRef = FIRDatabase.database().reference()
override func viewDidLoad() {
super.viewDidLoad()
}
//PROCESS - Checks is user has already been logged in
override func viewDidAppear(_ animated: Bool) {
let currentUser = FIRAuth.auth()?.currentUser
if currentUser != nil {
performSegue(withIdentifier: "SignIn", sender: nil)
}
}
func CompleteSignIn(id: String){
let keyChain = DataService().keyChain
keyChain.set(id , forKey: "uid")
}
//If SignUp button is pressed user will be directed to sign up page
#IBAction func LoginPressed(_ sender: Any) {
self.performSegue(withIdentifier: "BackToLogin", sender: nil)
}
/*If both password and email contain text lets put them into string variables
called email & password. Creates user and authorizes sign in */
#IBAction func SignIn(_ sender: Any){
if let email = emailField.text, let password = passwordField.text {
FIRAuth.auth()?.signIn(withEmail: email, password: password) { (user, error) in
if error == nil {
self.CompleteSignIn(id: user!.uid) //Completese Database Sign in
//************************************************
//Send information to Database
let userEmail : String = self.emailField.text!
let userPassword : String = self.passwordField.text!
let userID : String = user!.uid
self.dataRef.child("Users").child(userID).setValue(["Email": userEmail, "Password" : userPassword])
//************************************************
print("Sign in Test")
self.performSegue(withIdentifier: "SignIn", sender: nil)
} else {
FIRAuth.auth()?.createUser(withEmail: email, password: password) { (user, error) in
if error != nil {
Alerts().invalidSignUpAlert(sender: self) //Alert for invalid email & Password
print("cant sign in user") //Programmer Debugging
} else {
self.CompleteSignIn(id: user!.uid)
self.performSegue(withIdentifier: "SignIn", sender: nil)
}
}
}
}
}
}
}

Add "Users" in the rules as shown below:
"rules": {
"Users":{
".read": "true",
".write": "true"
}
}

You need as Boolean, not as string "true"
{
"rules": {
".read" : true,
".write":true
}
}

Related

How to add a user with setValue from Firebase Reading and writing data in ios

I am a newbie in Swift and I am learning by building a social media application.
I am struck at trying to implement self.ref.child("users").child(user.uid).setValue(["username": username]) in my code (from https://firebase.google.com/docs/database/ios/read-and-write).
I have been following the instructions of Kasey Schlaudt and at this point of the tutorial https://youtu.be/GrRggN41VF0?t=619 he tried to add a user with setValue as shown in the Firebase documentation I have linked. The errors I get in the line self.ref.child("users").child(user.uid).setValue(["username": username]) are
Use of unresolved identifier 'user' and Use of unresolved identifier 'username'.
My code so far (with some little changes from the original code in the video in my signInPress function) is
import UIKit
import Firebase
import SwiftKeychainWrapper
class ViewController: UIViewController {
#IBOutlet weak var UserImageView: UIButton!
#IBOutlet weak var usernameField: UITextField!
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passwordField: UITextField!
override func viewDidLoad()
{
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool)
{
if let _ : Bool = KeychainWrapper.standard.string(forKey: "uid") != nil
{
self.performSegue(withIdentifier: "toFeed", sender: nil)
}
}
func storeUserData(userID: String)
{
//---------------------------problematic line---------------------------
//from https://firebase.google.com/docs/database/ios/read-and-write
//from https://youtu.be/GrRggN41VF0?t=619
self.ref.child("users").child(user.uid).setValue(["username": username])
([
"username": usernameField.text
])
}
#IBAction func signInPress(_ sender: Any)
{
//this way you make sure there is a property inside emailField.text and you have a variable you can easily use
if let email = emailField.text, let password = passwordField.text
{
Auth.auth().signIn(withEmail: email, password: password)
{ (result, error) in
if error != nil && self.usernameField.text!.isEmpty && self.UserImageView.image != nil
{
Auth.auth().createUser(withEmail: email, password: password)
{ (result, error) in
self.storeUserData(userID: (result?.user.uid)!)
KeychainWrapper.standard.set((result?.user.uid)!, forKey: "KEY_UID")
self.performSegue(withIdentifier: "toFeed", sender: nil)
}
} else
{
KeychainWrapper.standard.set((result?.user.uid)!, forKey: "KEY_UID")
self.performSegue(withIdentifier: "toFeed", sender: nil)
}
}
}
}
}
I would very much appreciate any indication as to why the error does not occur for Kasey and what I might need to change to do the same process.
Thank you in advance !
You're actually pretty close, more of a typo issue. See that your storeUserData function is expecting a string called userID? That's what's needed in the line to store that data instead of user.uid
func storeUserData(userID: String) {
let username = self.usernameField.text
self.ref.child("users").child(userID).setValue(["username": username])
here ^^^^^^ userID instead of user.uid
}

Closing and opening my app goes straight to homepage without verifying the user email

When I create a new user it does everything it should do and saves the users detail and goes back to the login page waiting for the email to be verified before allowing it to be used. The coding works so it doesn't allowing you to proceed until email has been verified but I've realised when I slide the app to close it and then reopen it (before verifying the email), it goes straight to the homepage bypassing the login page even if the email hasn't been verified?
import UIKit
import Firebase
import SwiftKeychainWrapper
class ViewController: UIViewController {
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passwordField: UITextField!
var userUid: String!
override func viewDidLoad(){
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(_ animated: Bool) {
func Keychain() {
KeychainWrapper.standard.set(userUid, forKey: "uid")
}
if let _ = KeychainWrapper.standard.string(forKey: "uid"){
LoggedIn()
}
}
func goToCreateUserVC() {
performSegue(withIdentifier: "CreateAProfile", sender: nil)
}
func LoggedIn() {
performSegue(withIdentifier: "LoginSuccessful", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "CreateAProfile" {
if let destination = segue.destination as? CreatUsers {
if userUid != nil {
destination.userUid = userUid
}
if emailField.text != nil {
destination.emailField = emailField.text
}
if passwordField.text != nil {
destination.passwordField = passwordField.text
}
}
}
}
func DisplayAlertMessage(MessageToDisplay: String) {
let alertController = UIAlertController(title: "Alert", message: MessageToDisplay, preferredStyle: .alert)
let OKAction = UIAlertAction(title: "OK", style: .default) { (action:UIAlertAction!) in
// Code in this block will trigger when OK button tapped.
print("Ok button tapped");
}
alertController.addAction(OKAction)
self.present(alertController, animated: true, completion:nil)
}
#IBAction func signIntapped(_ sender: Any) {
if let email = emailField.text, let password = passwordField.text {
Auth.auth().signIn(withEmail: email, password: password, completion:
{(user,error) in
if let user = Auth.auth().currentUser {
if user.isEmailVerified {
self.userUid = user.uid
print("Email Verified")
self.LoggedIn()
} else {
self.DisplayAlertMessage(MessageToDisplay: "Need To Verify Email Address")
}
} else {
self.DisplayAlertMessage(MessageToDisplay: "Incorrect Username/Password")
}
});
}
}
#IBAction func NotaMemberisTapped(_ sender: Any) {
self.goToCreateUserVC()
}
}
Only happens when I close the app and reopen it to find it cheats its way through - trying to figure out how to prevent it from happening.
You’re calling your LoggedIn() function based on whether or not there is a value in the keychain. I’m assuming you’re saving that information to the keychain whether or not validation has been performed.

Swift - Login with FireBase - Can't retrieve user data after login

Firebase Authentication - Can't retrieve user data after login.
I'm trying to retrieve the users email after sign in (logincontroller) and display it in a UILABEL on another controller (maincontroller). When you create a user or use an existing one, it works fine the first time after launching the app, but when you sign out and try to use another email it does not work.
I have two view controllers:
import UIKit
import Firebase
import FirebaseAuth
import FirebaseDatabase
class LoginViewController: UIViewController {
var ref: FIRDatabaseReference!
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
ref = FIRDatabase.database().reference()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func signInButton(sender: AnyObject) {
FIRAuth.auth()?.signInWithEmail(emailTextField.text! , password: passwordTextField.text!, completion: { (user, error) in
if error != nil {
print(error!.localizedDescription)
}
})
self.performSegueWithIdentifier("MainViewSegue", sender: self)
}
#IBAction func createAccountButton(sender: AnyObject) {
FIRAuth.auth()?.createUserWithEmail(emailTextField.text!, password: passwordTextField.text!, completion: { (user, error) in
if error != nil {
print(error!.localizedDescription)
} else {
print("User Created.")
let userID: String = user!.uid
let userEmail:String = self.emailTextField.text!
self.ref.child("users").child(userID).setValue(["email": userEmail])
}
})
}
}
and:
import Foundation
import UIKit
import Firebase
import FirebaseDatabase
class MainViewController: UIViewController {
var ref: FIRDatabaseReference!
var refHandle: UInt!
#IBOutlet weak var userEmailLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
ref = FIRDatabase.database().reference()
refHandle = ref.observeEventType(FIRDataEventType.Value, withBlock: { (snapshot) in
let dataDict = snapshot.value as! [String: AnyObject]
print((dataDict))
})
let userID: String = (FIRAuth.auth()?.currentUser?.uid)!
ref.child("users").child(userID).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
let userEmail = snapshot.value!["email"] as! String
self.userEmailLabel.text = userEmail
})
}
#IBAction func signOutButton(sender: AnyObject) {
try! FIRAuth.auth()!.signOut()
if let storyboard = self.storyboard {
let viewController = storyboard.instantiateViewControllerWithIdentifier("LoginViewController")
self.presentViewController(viewController, animated: false, completion: nil)
}
}
}
This is where I get the error EXC_BAD_INSTRUCTION:
let userID: String = (FIRAuth.auth()?.currentUser?.uid)!
CMD+CLICK on signInWithEmail in FIRAuth.auth()?.signInWithEmail(emailT... and you will be directed to its documentation, above that function in its documentation you will see :-
#param completion Optionally; a block which is invoked when the sign in flow finishes, or is
canceled. Invoked asynchronously on the main thread in the future.
which means your completionBlock is invoked when your user is either signed in or signInWithEmail function has given some error.But in your case self.performSegueWithIdentifier("MainViewSegue", sender: self) will get called even before your completionBlock: is called.
Try this:-
#IBAction func signInButton(sender: AnyObject) {
FIRAuth.auth()?.signInWithEmail(emailTextField.text! , password: passwordTextField.text!, completion: { (user, error) in
if error != nil {
print(error!.localizedDescription)
}else if error == nil{
self.performSegueWithIdentifier("MainViewSegue", sender: self)
}
})
}
Also replace :-
let userID: String = (FIRAuth.auth()?.currentUser?.uid)!
with
let userID: String = FIRAuth.auth()!.currentUser!.uid
No need to forcefully unwrap an optional value which you know does exist

Firebase automatic login on iOS

Is there a better way to make a user automatically login to the app as long as they have logged in in the past; other than saving their login details directly to the storage which may be insecure?
Thanks
PS: I'm using Firebase and Swift for iOS
EDIT: Here's the code
import UIKit
import Firebase
class loginVC: UIViewController {
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
#IBOutlet weak var errorLabel: UILabel!
override func viewDidAppear(animated: Bool) {
automaticLogin()
}
#IBAction func loginTapped(sender: AnyObject) {
errorLabel.text = ""
FIRAuth.auth()?.createUserWithEmail(emailTextField.text!, password: passwordTextField.text!, completion: {
user, error in
if error != nil {
FIRAuth.auth()?.signInWithEmail(self.emailTextField.text!, password: self.passwordTextField.text!, completion: { (user, error) in
if error == nil {
self.login()
} else if error != nil {
self.errorLabel.text = ("Invalid email address or password")
print(error)
}
})
} else {
print("user created")
self.login()
print(user?.displayName)
}
})
}
#IBAction func forgotPasswordTapped(sender: AnyObject) {
let email = emailTextField.text
errorLabel.text = ""
FIRAuth.auth()?.sendPasswordResetWithEmail(email!) { error in
if error != nil {
self.errorLabel.text = ("Invalid email address")
print(error)
} else {
self.errorLabel.text = ("Password reset email successfully sent")
print("password reset email sent")
}
}
}
func login() {
FIRAuth.auth()?.signInWithEmail(emailTextField.text!, password: passwordTextField.text!, completion: {
user, error in
if error != nil {
self.errorLabel.text = ("Invalid email address or password")
print(error)
} else {
print("login successful")
self.checkIfUserIsNew()
}
})
}
func checkIfUserIsNew() {
if FIRAuth.auth()?.currentUser?.displayName != nil || FIRAuth.auth()?.currentUser?.displayName == "" {
self.performSegueWithIdentifier("showChatVC", sender: self)
} else {
self.performSegueWithIdentifier("showOptionsVC", sender: self)
}
}
func automaticLogin() {
FIRAuth.auth()?.addAuthStateDidChangeListener { auth, user in
if user == user {
print("still signed in")
} else {
print("not signed in")
}
}
}
I also used this to logout the user:
#IBAction func logOutTapped(sender: AnyObject) {
try! FIRAuth.auth()?.signOut()
performSegueWithIdentifier("showLoginVC", sender: self)
print(FIRAuth.auth()?.currentUser?.displayName)
}
You might want to use NSUserDefaults. To do this in your login() function you might want to save your user's data once they signed in or create an account. Inside your login function you can start by creating new variable to grab your user's email / password.
let userDefaults = UserDefaults.standard
userDefaults.setValue(self.emailField.text!, forKey: "email")
userDefaults.setValue(self.passField.text!, forKey: "password")
Next, you also need to implement a new function called viewWillAppear, which will be called before the view controller. And you might also put some arguments inside your login function.
override func viewWillAppear(_ animated: Bool) {
let userDefaults = UserDefaults.standard
if userDefaults.string(forKey: "email") != nil {
let email = userDefaults.string(forKey: "email")
let password = userDefaults.string(forKey: "password")
login(email: email!, password: password!)
}
}
the if statement will check wether your user already registered their email account or not yet. Lastly you need to update your login function to have two parameters, to pass in the email and password of the user.

Error while registering a new user on Firebase

When I try to register a new user, I get an error saying value of type 'FIRDatabaseReference' has no member 'createuser'. See image below.
FIRAuth.auth()?.createUserWithEmail(<email: String>, password: <String>, completion: <FIRAuthResultCallback?(FIRUser?, NSError?) -> Void#>)
Here is a screenshot of how the code looks like picture of the code and the imageview:
Try this code it is working absolutely fine for me
//
// ViewController.swift
// FirebaseExample
//
// Created by Belal Khan on 03/10/16.
// Copyright © 2016 Belal Khan. All rights reserved.
//
import UIKit
//importing firebase
import Firebase
class ViewController: UIViewController {
//Textfields for email and password
#IBOutlet weak var textFieldEmail: UITextField!
#IBOutlet weak var textFieldPassword: UITextField!
//label for displaying message
#IBOutlet weak var labelMessage: UILabel!
//button for registration
#IBAction func buttonRegister(sender: UIButton) {
//do the registration operation here
//first take the email and password from the views
let email = textFieldEmail.text
let password = textFieldPassword.text
FIRAuth.auth()?.createUserWithEmail(email!, password: password!, completion: { (user: FIRUser?, error) in
if error == nil {
self.labelMessage.text = "You are successfully registered"
}else{
self.labelMessage.text = "Registration Failed.. Please Try Again"
}
})
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//initialising firebase
FIRApp.configure()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Source: swift firebase tutorial
The code does not match. ref.createUser is different from FIRAuth.auth()?.createUserWithEmail
This is a working piece of code I tried a few days ago in XCode 7.3.1 I am not sure which version of XCode you are using. However, there's no pre-defined function as you tried!
func buttonHandleRegister() {
guard let email = emailTextField.text, password = passwordTextField.text, name = nameTextField.text else {
print("Form is not valid")
return
}
FIRAuth.auth()?.createUserWithEmail(email, password: password, completion: { (user: FIRUser?, error) in
if error != nil {
print("Error")
return
}
guard let uid = user?.uid else {
return
}
//successfully logged in
let ref = FIRDatabase.database().referenceFromURL("https://some-random-name.firebaseio.com/")
let usersReference = ref.child("users").child(uid)
let values = ["name" : name, "email": email, "password": password]
usersReference.updateChildValues(values, withCompletionBlock: { (err, ref)
in
if err != nil {
print(err)
return
}
print("Saved user succesfully")
})
})
}

Resources