I have written some code for my users to log in to my app, but email and password column doesn't appear - ios

With the help of Chris Coding on youtube, I have tried to open a authViewController where my users should be able to sign up. So when I try it out I can reach the authViewController but the email and password column doesn't appear in the screen. So does anyone have an idea where the problem may occur?
#IBAction func logInTapped(_ sender: Any) {
let authUI = FUIAuth.defaultAuthUI()
guard authUI != nil else {
return
}
authUI?.delegate = self
let authViewController = authUI?.authViewController()
present(authViewController!, animated: true, completion: nil)
}
extension ViewController: FUIAuthDelegate{
func authUI(_ authUI: FUIAuth, didSignInWith authDataResult: AuthDataResult?,error: Error?){
if error != nil {
return
}
performSegue(withIdentifier: "goHome", sender: self)
}
}

Related

How to determine when a user has succesfully logged in using FirebaseUI in swift?

To log a user in using the firebaseUI library you can do the following:
let authUI = FUIAuth.defaultAuthUI()
guard authUI != nil else {
return
}
authUI?.providers = [
FUIEmailAuth(), //works
FUIGoogleAuth(), //works
FUIOAuth.appleAuthProvider() //does not work
]
authUI?.delegate = self
authUI?.shouldHideCancelButton = true
let authViewController = authUI!.authViewController()
authViewController.modalPresentationStyle = .overCurrentContext
self.present(authViewController, animated: true, completion: nil)
and according to the documentation you include the following function on completion of user log in:
func authUI(_ authUI: FUIAuth,didSignInWith authDataResult: AuthDataResult?, error: Error?) {
if let user = authDataResult?.user{
print("Nice! You've signed in as \(user.uid)")
performSegue(withIdentifier: K.welcomeSegue, sender: self)
}
}
However, in my code, when I use the Apple sign-in option this function never runs. Do I need to call this function somewhere? If so how do I call it?
Here is the full code to my view controller:
class WelcomeViewController: UIViewController, FUIAuthDelegate {
#IBOutlet weak var titleLabel: UILabel!
override func viewWillAppear(_ animated: Bool){
if(Auth.auth().currentUser != nil){
self.performSegue(withIdentifier: K.welcomeSegue, sender: self)
}
}
#IBAction func loginPressed(_ sender: UIButton) {
let authUI = FUIAuth.defaultAuthUI()
guard authUI != nil else {
return
}
authUI?.providers = [
FUIEmailAuth(),
FUIGoogleAuth(),
FUIOAuth.appleAuthProvider()
]
authUI?.delegate = self
authUI?.shouldHideCancelButton = true
let authViewController = authUI!.authViewController()
authViewController.modalPresentationStyle = .overCurrentContext
self.present(authViewController, animated: true, completion: nil)
}
func authUI(_ authUI: FUIAuth,didSignInWith authDataResult: AuthDataResult?, error: Error?) {
if let user = authDataResult?.user{
print("Nice! You've signed in as \(user.uid)")
performSegue(withIdentifier: K.welcomeSegue, sender: self)
}
}
}

Only instance methods can be declared #IBAction error?

I am facing this error on build for the function shown in the code
Only instance methods can be declared #IBAction
this error is coming up only after I introduced google sign in method for similar functionality , earlier it not an error
#IBAction func SignInButtonAction(_ sender: Any) {
guard let email = emailField.text else { return }
guard let pass = passwordField.text else { return }
Auth.auth().signIn(withEmail: email, password: pass) { user, error in
if error == nil && user != nil {
let setupcheckref = Firestore.firestore().collection("users").document(Auth.auth().currentUser!.uid)
setupcheckref.getDocument{(document, error) in
if let document = document, document.exists{
let dataDescription = document.data().map(String.init(describing:)) ?? "nil"
self.checksetup = document.get("setupComplete") as! Bool
if self.checksetup == true {
if Auth.auth().currentUser!.isEmailVerified {
self.performSegue(withIdentifier: "toLoginFeed", sender: self)
}
else{
print("please verify your email")
try! Auth.auth().signOut()
}
}
else{
self.view.makeToast("Please Setup Your Account!", duration: 2.5)
self.performSegue(withIdentifier: "fromlogintosetup", sender: self)
SVProgressHUD.dismiss()
} }
}
// self.dismiss(animated: false, completion: nil)
} else {
print("Error logging in: \(error!.localizedDescription)")
// self.resetForm()
// SVProgressHUD.dismiss()
}
}
}
That means you can create #IBActions only as instance methods of a class.
You might be creating it of a class.
class VC: UIViewController {
#IBAction func SignInButtonAction(_ sender: Any) {
//your code...
}
}

Redirect the user to a specific page after signIn

Main issue is checking if user has a child in the Firebase database so that I know if he is signing up or logging in.
Part 1: Part 1 (Child Database (this works) and making that a user default (I'm not sure how to check it that worked)
Part 2: in different .Swift file (Check if the User Default (aka Education Child) exists. I have pretty much nothing, except I know it must go into viewDidAppear
Part 1
#IBAction func SubmitPressed(_ sender: Any) {
let databaseRef = Database.database().reference()
let uid = Auth.auth().currentUser!.uid
databaseRef.child("Education").child(uid).setValue(self.Education.text!)
UserDefaults.standard.set("Education", forKey: "Education")
Part 2
func viewDidAppear(_ animated: String) {
??????
}
No error for part 1, though not sure if it created the user default. For part 2, I have tried a bunch of stuff, but hasn't worked.
Here is the updated code after first answer:
import Foundation
import UIKit
import SwiftKeychainWrapper
import Firebase
import CoreFoundation
import AVFoundation
import FirebaseDatabase
var educationCache : String {
get {
return (UserDefaults.standard.string(forKey: "Education")!)
} set {
UserDefaults.standard.set(newValue, forKey: "Education")
}
}
relavant part of education/personal info enter page
#IBAction func SubmitPressed(_ sender: Any) {
let databaseRef = Database.database().reference()
let uid = Auth.auth().currentUser!.uid
databaseRef.child("Education").child(uid).setValue(self.Education.text!)
// The following line will save it in userDefault itself. And you dont have to call the whole UserDefault Everywhere
educationCache = "Education"
self.performSegue(withIdentifier: "tohome", sender: nil)
}
homepage
import Foundation
import UIKit
import SwiftKeychainWrapper
import Firebase
import CoreFoundation
import AVFoundation
import FirebaseDatabase
class homepage:UITableViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if educationCache.count < 0 {
self.performSegue(withIdentifier: "toFeed", sender: nil)
}
}
override func viewDidLoad() {
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Sign Out", style: .plain, target: self, action: #selector(signOut))
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#objc func signOut (_sender: AnyObject) {
KeychainWrapper.standard.removeObject(forKey: "uid")
do {
try Auth.auth().signOut()
} catch let signOutError as NSError {
print ("Error signing out: %#", signOutError)
}
dismiss(animated: true, completion: nil)
}
}
You dont want to check the condition is the viewController where you are performing specific actions. Also checking the userDefaults everytime is just putting extra views in heirarchy. Firebase provides .addStateDidChangeListener function to keep a check of it. Add the following code to your delegate. It will automatically switch between the users if there are any or not.
AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
observeUser()
return true
}
func observeUser(){
Auth.auth().addStateDidChangeListener { (auth, user) in
if (user != nil) {
// If the user is not nil. Perform this block
self.showInitController(with identifier: "<add_your_storyboard_reusableID_for_homepage>", animated: false)
// The storyboard Id belongs to the HOMEPAGE/FEED, the view where user goes on signIn
} else {
//If there is no user. This block will perform
self.showInitController(with identifier: "<add_your_storyboard_reusableID_for_loginpage>", animated: false)
// The storyboard Id belongs to the SIGNUP PAGE, the view where user goes on signIn
}
}
}
func showInitController(with identifier: String, animated: Bool = false) {
DispatchQueue.main.async {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: identifier)
var topRootViewController: UIViewController = (UIApplication.shared.keyWindow?.rootViewController)!
while((topRootViewController.presentedViewController) != nil){
topRootViewController = topRootViewController.presentedViewController!
}
topRootViewController.present(vc, animated: animated, completion: nil)
}
}
In your swift file one. do the following and never look back. You can automatically redirect to view if you applied the other functions.
#IBAction func SubmitPressed(_ sender: Any) {
let databaseRef = Database.database().reference()
let uid = Auth.auth().currentUser!.uid
databaseRef.child("Education").child(uid).setValue(self.Education.text!)
self.performSegue(withIdentifier: "tohome", sender: nil)
}
In the second view dont bother to do anything anywhere. Just leave it, if nothing in that view is required again.

How to force new user or who just register have to fill the form first (FirebaseUI in IOS)

I'm using FirebaseUI as registration system, and now user can login by 2 way (facebook and phone number) but now problem is i want new user or first time login must fill the form before go to MainViewController. on the other hand, old user who ever fill the form will go to MainViewController without force to fill the form again.
Now I'm using Xcode 10.2 and FirebaseUI 6.2.1
Now I'm using Xcode 10.2 and FirebaseUI 6.2.1
import UIKit
import Firebase
import FirebaseUI
class UserLoginViewController: UIViewController, FUIAuthDelegate {
override func viewDidAppear(_ animated: Bool){
super.viewDidAppear(animated)
if Auth.auth().currentUser != nil {
//Old user go to segue withIdentifier "GoMain"
self.performSegue(withIdentifier: "GoMain", sender: nil)
//First time login go to segue withIdentifier "FillForm"
}
let authUI = FUIAuth.defaultAuthUI()
guard authUI != nil else {
return
}
authUI?.delegate = self
let providers: [FUIAuthProvider] = [
FUIFacebookAuth(),
FUIPhoneAuth(authUI:FUIAuth.defaultAuthUI()!),
]
authUI?.providers = providers
let authViewController = authUI!.authViewController()
authViewController.isNavigationBarHidden = true
present(authViewController, animated: true, completion: nil)
}
}
extension UserLoginViewController {
func authUI(_ authUI: FUIAuth, didSignInWith authDataResult: AuthDataResult?, error: Error?) {
if error != nil {
return
}
}
}

Firebase AuthUI - Find if existing user or new user

I'm making use of firebase AuthUI to signup/login users. Depending on if the user is new or an existng user I need to redirect them to different view controllers. Does firebase provide a function to check that?
Here is my current code that, irrespective of new or registered user, segues to 'signUpSegue'
#IBAction func phoneNumberLoginAction(_ sender: AnyObject) {
FUIAuth.defaultAuthUI()?.delegate = self as FUIAuthDelegate
let phoneProvider = FUIPhoneAuth.init(authUI: FUIAuth.defaultAuthUI()!)
FUIAuth.defaultAuthUI()?.providers = [phoneProvider]
// 1
print("clicked butto")
guard let authUI = FUIAuth.defaultAuthUI()
else { return }
// 2
authUI.delegate = self as FUIAuthDelegate
// 3
let authViewController = authUI.authViewController()
present(authViewController, animated: true)
}
#available(iOS 10.0, *)
extension WelcomeViewController: WelcomePageViewControllerDelegate, FUIAuthDelegate {
func authUI(_ authUI: FUIAuth, didSignInWith user: User?, error: Error?) {
print("handle user signup / login")
performSegue(withIdentifier: "signUpSegue", sender: nil)
}
func welcomePageViewController(_ welcomePageViewController: WelcomePageViewController,
didUpdatePageCount count: Int) {
pageControl.numberOfPages = count
}
func welcomePageViewController(_ welcomePageViewController: WelcomePageViewController,
didUpdatePageIndex index: Int) {
pageControl.currentPage = index
}
}
It is not documented, but there is a callback function didSignInWithAuthDataResult which returns an AuthDataResult which provides a way to tell if a user is new or existing via additionalUserInfo.newUser.
https://github.com/firebase/FirebaseUI-iOS/blob/a69aa9536a0f5312bdd2d408a761c7dd21698015/FirebaseAuthUI/FUIAuth.h#L54
Are you saving the user to the database under a "Users" node, with their Auth ID? If you are, just do a query with the returned UID to see if they exist like this...
func checkIfUserExistsAlready(_ uid: String, complete: #escaping ((_ doesExist: Bool) -> Void)) {
//userRef if a Database Reference to "Users" node
userRef.child(uid).observeSingleEvent(of: .value) { (snapshot) in
if snapshot.exists() {
complete(true)
} else {
complete(false)
}
}
}
You can call this and check in the FUIAuthDelegate function
func authUI(_ authUI: FUIAuth, didSignInWith user: User?, error: Error?) {
//Call does exists function here with user.uid
//Have if statement here and perform segues accordingly
performSegue(withIdentifier: "signUpSegue", sender: nil)
}
a) Try log in the Firebase whit the the phone number.
b) If the Firebase return error, check the error?.localizedDescription
c) If the error is an inexistent user, your user is new.
d) If the error is a wrong password, try a different password.

Resources