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

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)
}
}
}

Related

issue with alamofire pod on xcode 9

hello everyone I install the alamofire and google places pod to autocomplete the places search
but it gives me the error:
The “Swift Language Version” (SWIFT_VERSION) build setting must be set to a
supported value for targets that use Swift. This setting can be set in the
build settings editor.
my code:
class SetLocationViewController: UIViewController {
private var placesClient = GMSPlacesClient()
#IBOutlet weak var setLocationTf: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
placesClient = GMSPlacesClient.shared()
}
#IBAction func onClickTf(_ sender: Any) {
setLocationTf.resignFirstResponder()
let acController = GMSAutocompleteViewController()
acController.delegate = self
let filter = GMSAutocompleteFilter()
filter.type = .establishment
filter.countries = ["BR"]
acController.autocompleteFilter = filter
let field: GMSPlaceField = [.name, .placeID]
acController.placeFields = field
present(acController, animated: true, completion: nil)
}
}
extension SetLocationViewController: GMSAutocompleteViewControllerDelegate {
func viewController(_ viewController: GMSAutocompleteViewController, didAutocompleteWith place: GMSPlace) {
if let name = place.name {
setLocationTf.text = name
}
dismiss(animated: true, completion: nil)
}
func viewController(_ viewController: GMSAutocompleteViewController, didFailAutocompleteWithError error: Error) {
print("Error: ", error.localizedDescription)
}
func wasCancelled(_ viewController: GMSAutocompleteViewController) {
dismiss(animated: true, completion: nil)
}
}
The error I got:

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

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)
}
}

User variable is nil when creating a user with Firebase

I am following a tutorial and cannot seem to register my user as the user variable in the Firebase .createUser method appears to be nil. Therefore, when I unwrap it, I get an error.
I have read through a lot of the documentation as well as checked many other questions similar to mine but nothing seems to work
import UIKit
import Firebase
import SwiftKeychainWrapper
class ViewController: UIViewController {
#IBOutlet weak var userImgView: UIImageView!
#IBOutlet weak var usernameField: UITextField!
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passwordField: UITextField!
var imagePicker: UIImagePickerController!
var selectedImage: UIImage!
override func viewDidLoad() {
super.viewDidLoad()
imagePicker = UIImagePickerController()
imagePicker.allowsEditing = true
imagePicker.delegate = self
}
override func viewDidAppear(_ animated: Bool) {
if let _ = KeychainWrapper.standard.string(forKey: "uid") {
self.performSegue(withIdentifier: "toFeed", sender: nil)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func setupUser(userUid: String) {
if let imageData = self.userImgView.image!.jpegData(compressionQuality: 0.2) {
let imgUid = NSUUID().uuidString
let metaData = StorageMetadata()
Storage.storage().reference().child(imgUid).putData(imageData, metadata: metaData) { (metadata, error) in
let downloadURL = metadata
let userData = [
"username": self.usernameField.text!,
"userImg": downloadURL!
] as [String : Any]
Database.database().reference().child("users").child(userUid).setValue(userData)
self.performSegue(withIdentifier: "toFeed", sender: nil)
}
}
}
#IBAction func signInPressed(_ sender: Any) {
if let email = emailField.text, let password = passwordField.text {
Auth.auth().signIn(withEmail: email, password: password) { user, error in
if error != nil && !(self.usernameField.text?.isEmpty)! {
Auth.auth().createUser(withEmail: email, password: password) { (user, error) in
self.performSegue(withIdentifier: "toFeed", sender: nil)
let userID = (user?.user.uid)!
self.setupUser(userUid: userID)
KeychainWrapper.standard.set(userID, forKey: "uid")
}
} else {
if let userID = (user?.user.uid) {
KeychainWrapper.standard.set((userID), forKey: "uid")
self.performSegue(withIdentifier: "toFeed", sender: nil)
}
}
}
}
}
#IBAction func getPhoto (_ sender: AnyObject) {
present(imagePicker, animated: true, completion: nil)
}
}
extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
internal func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[.originalImage] as? UIImage {
userImgView.image = image
} else {
print("image wasnt selected")
}
imagePicker.dismiss(animated: true, completion: nil)
}
}
The error I am getting is one the "let userID = (user?.user.uid)!". It is
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
The completion block for createUser(withEmail:,password:) gets called with either a AuthResult.user or an error. That why, as Joshua commented, you should check if error is nil before accessing any of the user properties.
From the auth quickstart for Swift:
Auth.auth().createUser(withEmail: email, password: password) { authResult, error in
strongSelf.hideSpinner {
guard let user = authResult?.user, error == nil else {
strongSelf.showMessagePrompt(error!.localizedDescription)
return
}
print("\(user.email!) created")
strongSelf.navigationController?.popViewController(animated: true)
}
}

how can I use a variable from another function swift?

I have a variable by the name of email in the contact picker function. I am trying to use that variable in the IBAction function for the MFMailComposeViewController. I want to apply it to toRecipient. How would I go about using a variable from another function?
import UIKit
import Contacts
import ContactsUI
import MessageUI
class ViewController: UIViewController, CNContactPickerDelegate, MFMailComposeViewControllerDelegate, UITextFieldDelegate {
//Message Setup
#IBOutlet weak var nameTextField: UITextField!
#IBOutlet weak var companyTextField: UITextField!
#IBOutlet weak var lblDetails: UILabel!
#IBAction func btnSelectEmployee(_ sender: Any) {
let entityType = CNEntityType.contacts
let authStatus = CNContactStore.authorizationStatus(for: entityType)
if authStatus == CNAuthorizationStatus.notDetermined {
let contactStore = CNContactStore.init()
contactStore.requestAccess(for: entityType, completionHandler: { (success, nil) in
if success {
self.openContacts()
}
else {
print("Not Authorized")
}
})
}
else if authStatus == CNAuthorizationStatus.authorized {
self.openContacts()
}
}
func openContacts() {
let contactPicker = CNContactPickerViewController.init()
contactPicker.delegate = self
self.present(contactPicker, animated: true, completion: nil)
}
func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
picker.dismiss(animated: true) {
}
}
func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
//When user select any contact
let fullName = "\(contact.givenName) \(contact.familyName)"
var email = "Not Available"
if !contact.emailAddresses.isEmpty {
let emailString = (((contact.emailAddresses[0] as AnyObject).value(forKey: "labelValuePair") as AnyObject).value(forKey: "value"))
email = emailString! as! String
self.lblDetails.text = "\(fullName)\n \(email)"
}
}
//Mail View
#IBAction func sendAction(_ sender: Any) {
let mailVC = MFMailComposeViewController()
mailVC.mailComposeDelegate = self
mailVC.setSubject("Hello. You have a visitor in the lobby.")
let mailContent = "\(nameTextField.text!) from \(companyTextField.text!) is here to see you."
mailVC.setMessageBody(mailContent, isHTML: false)
let toRecipient = "somebody5555555#gmail.com"
mailVC.setToRecipients([toRecipient])
self.present(mailVC, animated: true) {
self.nameTextField.text = ""
self.companyTextField.text = ""
}
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true, completion: nil)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
nameTextField.resignFirstResponder()
companyTextField.resignFirstResponder()
return true
}
}
Define the var outside the function
var email = "Not Available"
func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
//When user select any contact
let fullName = "\(contact.givenName) \(contact.familyName)"
if !contact.emailAddresses.isEmpty {
let emailString = (((contact.emailAddresses[0] as AnyObject).value(forKey: "labelValuePair") as AnyObject).value(forKey: "value"))
email = emailString! as! String
self.lblDetails.text = "\(fullName)\n \(email)"
}
}
Now you can use the variable inside your class wherever you want.
To get more basics, read documentation Apple Documentation

ViewController loads but does not show

I'm using the Spotify iOS SDK. When a user logs into Spotify using the app, on call back loginVC transitions to musicPlayerVC. But, when a user logs into the app using a web view, once the web view dismisses and the loginVC is shown, the musicPlayerVC is loaded (print statements from viewDidLoad occur), but loginVC does not dismiss and musicPlayerVC does not show.
loginVC:
class loginVC: UIViewController, SPTStoreControllerDelegate, WebViewControllerDelegate {
#IBOutlet weak var statusLabel: UILabel!
var authViewController: UIViewController?
var firstLoad: Bool!
var Information: [String:String]?
override func viewDidLoad() {
super.viewDidLoad()
// NotificationCenter.default.addObserver(self, selector: #selector(self.sessionUpdatedNotification), name: NSNotification.Name(rawValue: "sessionUpdated"), object: nil)
self.statusLabel.text = ""
self.firstLoad = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(self.sessionUpdatedNotification), name: NSNotification.Name(rawValue: "sessionUpdated"), object: nil)
let auth = SPTAuth.defaultInstance()
// Uncomment to turn off native/SSO/flip-flop login flow
//auth.allowNativeLogin = NO;
// Check if we have a token at all
if auth!.session == nil {
self.statusLabel.text = ""
return
}
// Check if it's still valid
if auth!.session.isValid() && self.firstLoad {
// It's still valid, show the player.
print("View did load, still valid, showing player")
self.showPlayer()
return
}
// Oh noes, the token has expired, if we have a token refresh service set up, we'll call tat one.
self.statusLabel.text = "Token expired."
if auth!.hasTokenRefreshService {
self.renewTokenAndShowPlayer()
return
}
// Else, just show login dialog
}
override var prefersStatusBarHidden: Bool {
return true
}
func getAuthViewController(withURL url: URL) -> UIViewController {
let webView = WebViewController(url: url)
webView.delegate = self
return UINavigationController(rootViewController: webView)
}
func sessionUpdatedNotification(_ notification: Notification) {
self.statusLabel.text = ""
let auth = SPTAuth.defaultInstance()
self.presentedViewController?.dismiss(animated: true, completion: { _ in })
if auth!.session != nil && auth!.session.isValid() {
self.statusLabel.text = ""
print("Session updated, showing player")
self.showPlayer()
}
else {
self.statusLabel.text = "Login failed."
print("*** Failed to log in")
}
}
func showPlayer() {
self.firstLoad = false
self.statusLabel.text = "Logged in."
self.Information?["SpotifyUsername"] = SPTAuth.defaultInstance().session.canonicalUsername
OperationQueue.main.addOperation {
[weak self] in
self?.performSegue(withIdentifier: "ShowPlayer", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowPlayer" {
if let destination = segue.destination as? PlayController {
destination.Information = self.Information
}
}
}
internal func productViewControllerDidFinish(_ viewController: SPTStoreViewController) {
self.statusLabel.text = "App Store Dismissed."
viewController.dismiss(animated: true, completion: { _ in })
}
func openLoginPage() {
self.statusLabel.text = "Logging in..."
let auth = SPTAuth.defaultInstance()
if SPTAuth.supportsApplicationAuthentication() {
self.open(url: auth!.spotifyAppAuthenticationURL())
} else {
self.authViewController = self.getAuthViewController(withURL: SPTAuth.defaultInstance().spotifyWebAuthenticationURL())
self.definesPresentationContext = true
self.present(self.authViewController!, animated: true, completion: { _ in })
}
}
func open(url: URL) {
if #available(iOS 10, *) {
UIApplication.shared.open(url, options: [:],
completionHandler: {
(success) in
print("Open \(url): \(success)")
})
} else {
let success = UIApplication.shared.openURL(url)
print("Open \(url): \(success)")
}
}
func renewTokenAndShowPlayer() {
self.statusLabel.text = "Refreshing token..."
SPTAuth.defaultInstance().renewSession(SPTAuth.defaultInstance().session) { error, session in
SPTAuth.defaultInstance().session = session
if error != nil {
self.statusLabel.text = "Refreshing token failed."
print("*** Error renewing session: \(error)")
return
}
self.showPlayer()
}
}
func webViewControllerDidFinish(_ controller: WebViewController) {
// User tapped the close button. Treat as auth error
}
}
webController :
import UIKit
import WebKit
#objc protocol WebViewControllerDelegate {
func webViewControllerDidFinish(_ controller: WebViewController)
/*! #abstract Invoked when the initial URL load is complete.
#param success YES if loading completed successfully, NO if loading failed.
#discussion This method is invoked when SFSafariViewController completes the loading of the URL that you pass
to its initializer. It is not invoked for any subsequent page loads in the same SFSafariViewController instance.
*/
#objc optional func webViewController(_ controller: WebViewController, didCompleteInitialLoad didLoadSuccessfully: Bool)
}
class WebViewController: UIViewController, UIWebViewDelegate {
var loadComplete: Bool = false
var initialURL: URL!
var webView: UIWebView!
var delegate: WebViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
print(initialURL)
let initialRequest = URLRequest(url: self.initialURL)
self.webView = UIWebView(frame: self.view.bounds)
self.webView.delegate = self
self.webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.view.addSubview(self.webView)
self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.done))
self.webView.loadRequest(initialRequest)
}
func done() {
self.delegate?.webViewControllerDidFinish(self)
self.presentingViewController?.dismiss(animated: true, completion: { _ in })
}
func webViewDidFinishLoad(_ webView: UIWebView) {
if !self.loadComplete {
delegate?.webViewController?(self, didCompleteInitialLoad: true)
self.loadComplete = true
}
}
func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
if !self.loadComplete {
delegate?.webViewController?(self, didCompleteInitialLoad: true)
self.loadComplete = true
}
}
init(url URL: URL) {
super.init(nibName: nil, bundle: nil)
self.initialURL = URL as URL!
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}

Resources