Building Firebase Log in in Xcode - swift

I am doing a Log in from Firebase in XCocde and I can't get any further cause of a problem. How can I Fix the guard problem? cause he will alway show me a expert pattern
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func Button(_ sender: UIButton) {
// get the default auth UI objekt
}
let authUI = FUIAuth.defaultAuthUI()
let guard authUi != nil else {
// log the error
return
}
}
I need to fix the guard authUi !=nil else {
return}

What is the problem? you have to clearly state the issue, so I will assume you are looking for a print value of the error
let authUI = FUIAuth.defaultAuthUI()
let guard authUi != nil else {
print("error: \(String(describing: authUI?.localizedDescription))")
return
}

Related

FirebaseUI not showing any input fields or buttons

I want to implement FirebaseUIin my project, but the login page is not showing any input fields or buttons:
Code for showing FUIAuth:
#IBAction func logInButtonTapped(_ sender: Any) {
let authUI = FUIAuth.defaultAuthUI()
guard authUI != nil else {
//Log error
return
}
authUI?.delegate = self
authUI?.providers = [FUIEmailAuth]()
let authViewController = authUI!.authViewController()
present(authViewController, animated: true, completion: nil)
}
}
extension LogInViewController: FUIAuthDelegate {
func authUI(_ authUI: FUIAuth, didSignInWith authDataResult: AuthDataResult?, error: Error?) {
if error != nil {
return
}
performSegue(withIdentifier: "ToHomeVCSegue", sender: self)
}
}
I have tried lots of different options in the podfile:
pod 'Firebase/Core'
pod 'Firebase/Auth'
pod 'Firebase/Database'
pod 'FirebaseUI'
pod 'FirebaseUI/Email'
I just ran into this same issue and it seems that all of the examples out there are missing some aspect of the steps required to make the providers appear. The first answer was correct but didnt give examples. In the code below I am just suing email and Google auth. This code is embedded in a login button pressed event.
let authUI = FUIAuth.defaultAuthUI()
guard authUI != nil else {
print("authUI error")
return
}
authUI?.delegate = self
let providers: [FUIAuthProvider] = [
FUIEmailAuth(),
FUIGoogleAuth()
]
authUI?.providers = providers
let authViewController = authUI!.authViewController()
present(authViewController, animated: true)
Hopefully it's not too late. But the problem looks to be with this line of code here
authUI?.providers = [FUIEmailAuth]()
The '.providers' property requires an array of type FUIAuthProviders.
Your code is basically trying to pass an array of type FUIEmailAuth, which the '.providers' property doesn't understand.
Here's an example of initializing an array of type FUIAuthProviders
let authProviders: [FUIAuthProviders] = []

Attempt to present <a> on <a> while a presentation is in progress

i know this has been asked before but i'm trying to figure out the issue with my project, as the title states (a) is trying to present on (a) i have checked all segue triggers to see if i accidentally set a segue to go to the same view controller that it is already on but this is not the case.
view controller 1 code
import UIKit
import UserNotifications
class NotificationViewController: UIViewController {
let isRegisteredForRemoteNotifications = UIApplication.shared.isRegisteredForRemoteNotifications
let current = UNUserNotificationCenter.current()
#IBAction func Notification(_ sender: Any) {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge], completionHandler: {didAllow, error in})
var i = 0
while i < 1{
current.getNotificationSettings(completionHandler: { (settings) in
if settings.authorizationStatus == .notDetermined {
// Notification permission has not been asked yet, go for it!
}
if settings.authorizationStatus == .denied {
i = i + 1
DispatchQueue.main.async {
self.performSegue(withIdentifier: "ToLocation", sender: self)
// Notification permission was previously denied, go to settings & privacy to re-enable
}
}
if settings.authorizationStatus == .authorized {
i = i + 1
DispatchQueue.main.async {
self.performSegue(withIdentifier: "ToLocation", sender: self)
// Notification permission was already granted
}
}
})
}
}
override func viewDidLoad() {
current.getNotificationSettings(completionHandler: { (settings) in
if settings.authorizationStatus == .notDetermined {
// Notification permission has not been asked yet, go for it!
}
if settings.authorizationStatus == .denied {
DispatchQueue.main.async {
self.performSegue(withIdentifier: "ToLocation", sender: self)
// Notification permission was previously denied, go to settings & privacy to re-enable
}
}
if settings.authorizationStatus == .authorized {
DispatchQueue.main.async {
self.performSegue(withIdentifier: "ToLocation", sender: self)
// Notification permission was already granted
}
}
})
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
view controller 2 code
import UIKit
import CoreLocation
class LocationViewController: UIViewController {
#IBOutlet weak var textview: UITextView!
let locationManager = CLLocationManager()
#IBAction func OnLocation(_ sender: Any) {
locationManager.delegate = self as? CLLocationManagerDelegate
var i = 0
while i < 1{
switch CLLocationManager.authorizationStatus() {
case .notDetermined:
// Request when-in-use authorization initially
locationManager.requestWhenInUseAuthorization()
break
case .restricted, .denied:
i = i + 1
DispatchQueue.main.async {
self.performSegue(withIdentifier: "ToLogin", sender: self)
}
// Disable location features
//disableMyLocationBasedFeatures()
break
case .authorizedWhenInUse:
i = i + 1
DispatchQueue.main.async {
self.performSegue(withIdentifier: "ToLogin", sender: self)
}
// Enable basic location features
//enableMyWhenInUseFeatures()
break
case .authorizedAlways:
// Enable any of your app's location features
// enableMyAlwaysFeatures()
break
}
}
}
override func viewDidLoad() {
func locationManager(_ manager: CLLocationManager,
didChangeAuthorization status: CLAuthorizationStatus) { switch status {
case .restricted, .denied:
self.performSegue(withIdentifier: "ToLogin", sender: self)
break
case .authorizedWhenInUse:
self.performSegue(withIdentifier: "ToLogin", sender: self)
break
case .authorizedAlways:
self.performSegue(withIdentifier: "ToLogin", sender: self)
break
case .notDetermined:
break
}
}
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
error message
018-02-27 23:06:41.534749+1030 Request[27358:1351259] Warning: Attempt
to present on
while a presentation
is in progress!
No no no no no. This is not the way. sorry about this plenty of no´s but completionHandler result parameter of the requestAuthorization method from UNUserNotification may be executed on a background thread.
tips for this function
#IBAction func Notification(_ sender: Any)
*should start with lowercase
*provide a name that the action it accomplish can be inferred by that name
*change the type of the sender (if you know it), that way you can explicitly call properties or methods on that object without cast.
continuing with the rest of the code inside the scope of the function. requestAuthorization have the only responsibility of that - ask for a permission - and the response is didAllow or error. You never check this and continue launching another block that response is also another thread
bottom line: your calling requestAuthorization and then getNotificationSettings inside a loop (why?), you have a lot of luck if this code execute 30% of the time.
So you should separate some of the code involving permissions, read some lines about GRASP principle, also read every chapter here
Your error message is pretty clear while a presentation is in progress. That mean that you try to present LocationViewController from another LocationViewController, but it still not presented yet.
Move your presentation logic to viewWillAppear method. It will help
UPDATE
1) remove your existing segue from Notification button to LocationViewController in storyboard
2) Add segue from NotificationViewController to LocationViewController like it shown on picture
3) Set name for this segue
Now try to run your project

Swift: How to check if user's phone number is already in Firebase database before creating a new user

I just started working with Swift a few months ago and to help me learn the language better, I am creating a chat application. For the sign-in method, I am using the phone number method. I have the onboarding process already created but I want to implement something that lets me check if the user has already created an account with that phone number. If they have, I want to segue them to the main view controller, skipping the onboarding view controller.
Here is my code for the phone verification view controllers (One is for inputting a phone number and the other is for inputting the code sent to the user's phone):
import UIKit
import Firebase
import FirebaseAuth
import FirebaseDatabase
class PhoneVerification: UIViewController {
//MARK: Properties
#IBOutlet weak var phoneNumber: UITextField!
#IBOutlet weak var code: UITextField!
#IBOutlet weak var verifyCodeImage: UIButton!
#IBOutlet weak var sendCodeImage: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//MARK: Format phone text field
var phoneFormatter = PhoneNumberFormatter()
#IBAction func formatPhoneNumber(_ sender: UITextField) {
sender.text = phoneFormatter.format(sender.text!, hash: sender.hash)
}
//MARK: When send secret code button is pressed
#IBAction func sendCode(_ sender: Any) {
let submitPhoneNumber = "+1" + phoneNumber.text!
if submitPhoneNumber.count > 9{
PhoneAuthProvider.provider().verifyPhoneNumber(submitPhoneNumber, uiDelegate: nil) {(verificationID, error) in
if error != nil {
print(error!)
}else{
UserDefaults.standard.set(verificationID, forKey: "authVerificationID")
self.performSegue(withIdentifier: "phoneCode", sender: self)
}
}
}else{
let phoneNumAlert = UIAlertController(title: "Please enter your phone number", message: "You must enter your phone number to continue.", preferredStyle: .alert)
phoneNumAlert.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: nil))
self.present(phoneNumAlert, animated: true)
}
}
let verificationID = UserDefaults.standard.string(forKey: "authVerificationID")
//MARK: When verify code button is pressed
#IBAction func verifyCode(_ sender: Any) {
let credential = PhoneAuthProvider.provider().credential(
withVerificationID: verificationID!,
verificationCode: code.text!)
//This is where the user is signed in if the verification code is correct
Auth.auth().signIn(with: credential) { (user, error) in
if let error = error {
let invalidCodeAlert = UIAlertController(title: "That code is incorrect", message: "Please input the correct code", preferredStyle: .alert)
invalidCodeAlert.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: nil))
self.present(invalidCodeAlert, animated: true)
print(error)
return
}
//MARK: User is signed in
print("Phone number: \(String(describing: user?.phoneNumber))")
self.performSegue(withIdentifier: "accountCreated", sender: self)
}
}
}
All help is very much appreciated! Thanks!
Let's say you hold user data at the users ref. When the user signs in check to see if they have any data there, if they do then they are an existing user, if they don't then it is a new account:
Auth.auth().signIn(with: credential, completion: { [weak self](authDataResult, error) in
if let error = error { return }
guard let safeAuthDataResult = authDataResult else { return }
// 1. get the signed in user's userId
let userId = safeAuthDataResult.user.uid
// 2. check to see if their userId exists at the user's path
let usersRef = Database.database().reference().child("users").child(userId)
usersPublicDataRef.observeSingleEvent(of: .value, with: { (snapshot) in
// 3. this is a new user
if !snapshot.exists() {
// *** what you should do here is update the user's ref with some sort of data
} else {
// 4. this is an existing user
}
})
})
You can use FirebaseAuthUI and FirebasePhoneAuthUI to registered your mobile number into firebase. It's default method and UI which is provided by Firebase itself. So you don't have to worry about rest of things.
You just have to installed PhoneAuthUI using pod and write down below code to registered mobile number:
FUIAuth.defaultAuthUI()?.delegate = self
let phoneProvider = FUIPhoneAuth.init(authUI: FUIAuth.defaultAuthUI()!)
FUIAuth.defaultAuthUI()?.providers = [phoneProvider]
let currentlyVisibleController = self.navigationController?.visibleViewController
phoneProvider.signIn(withPresenting: currentlyVisibleController!, phoneNumber: nil)
Once your mobile number is registered then you will get a callback on this method:
func authUI(_ authUI: FUIAuth, didSignInWith user: User?, error: Error?) {
if user != nil{
// here we need to check if current user is registered or not.
var ref: DatabaseReference!
ref = Database.database().reference()
let userID = Auth.auth().currentUser?.uid
}) { (error) in
print(error.localizedDescription)
}
}else if error != nil{
print(error?.localizedDescription)
}
}
For more information, you can see this tutorial.

macOS - AVCaptureSession.stopRunning() crash

I have the following code (I copied whole class because I don't really get what the problem is; the function with the problem is displayImage - last 4 lines of code or so):
class ViewController: NSViewController {
#IBOutlet var previewBox: NSView!
#IBOutlet var captureBox: NSImageView!
let cameraSession = AVCaptureSession()
let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) as AVCaptureDevice
var deviceInput: AVCaptureDeviceInput?
var dataOutput: AVCaptureStillImageOutput?
override func viewDidLoad() {
super.viewDidLoad()
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
#IBAction func scan(_ sender: NSButton) {
do {
deviceInput = try AVCaptureDeviceInput(device: device)
cameraSession.beginConfiguration()
if (cameraSession.canAddInput(deviceInput) == true) {
cameraSession.addInput(deviceInput)
}
dataOutput = AVCaptureStillImageOutput()
if (cameraSession.canAddOutput(dataOutput) == true) {
cameraSession.addOutput(dataOutput)
}
cameraSession.commitConfiguration()
let previewLayer = AVCaptureVideoPreviewLayer(session: cameraSession)
previewBox.layer?.addSublayer(previewLayer!)
previewLayer?.frame = (previewBox.layer?.frame)!
previewLayer?.connection.automaticallyAdjustsVideoMirroring = false
previewLayer?.connection.isVideoMirrored = true
cameraSession.startRunning()
}
catch let error as NSError {
NSLog("\(error), \(error.localizedDescription)")
}
}
#IBAction func capture(_ sender: NSButton) {
if let videoConnection = dataOutput?.connection(withMediaType: AVMediaTypeVideo) {
dataOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: self.displayImage)
}
}
func displayImage(buffer: CMSampleBuffer?, err: Error?) {
let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer)
cameraSession.stopRunning()
captureBox.image = NSImage(data: imageData!)
}
}
Now... everything looks ok the preview is working, the buffer seems to have something in it - although that may be corrupted also since I can't display the image even if I comment the line with the crash (the main problem I'm asking about now). But... when it get's to the stopRunning() function the app crashes (print below). Any idea what I'm doing wrong here? If I comment the stop running part the app doesn't crash but the image is not set (that's why I pasted all... I'm expecting the problem to be somewhere else in code).
IMPORTANT: This is cocoa app, not iOS (and apparently there are 999999 code examples for iOS and 0 for macOS).

SWIFT: Passing Data from one class to another

So I have been using prepareForSegue to pass data from one variable to another class. It all works fine when the variable I am passing data to is with the destinationViewController. But what happens when it's not?
Example: I am taking moving from ViewController1 to ViewController2 but I want the data from ViewController1 to go to a "non ViewController" class even though I still want the segue to VC2 to happen.
Any ideas? Thank you!
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "stopRecording") {
//let playSoundsVC:PlaySoundsViewController = segue.destinationViewController as! PlaySoundsViewController
let audioEffectsClass = AudioEffect()
let data = sender as! RecordedAudio
audioEffectsClass.receivedAudio = data
}
}
import Foundation
import AVFoundation
class AudioEffect {
let session = AVAudioSession.sharedInstance()
var audioEngine: AVAudioEngine!
var audioPlayerNode: AVAudioPlayerNode!
var audioFile: AVAudioFile!
var receivedAudio: RecordedAudio!
var changeEffect = AVAudioUnitTimePitch()
func create(){
//output is through speakers
do{
try session.overrideOutputAudioPort(AVAudioSessionPortOverride.Speaker)
} catch {print("Failed output audio through speakers.")}
audioEngine = AVAudioEngine()
audioPlayerNode = AVAudioPlayerNode()
audioEngine.attachNode(audioPlayerNode)
}
func playAudio(){
audioEngine.stop()
audioEngine.reset()
do {
audioFile = try AVAudioFile(forReading: receivedAudio.filePathUrl)
} catch {print("Failed to create file.")}
audioPlayerNode.scheduleFile(audioFile, atTime: nil, completionHandler: nil)
do {
try audioEngine.start()
} catch {}
audioPlayerNode.play()
audioEngine.attachNode(changeEffect)
audioEngine.connect(audioPlayerNode, to: changeEffect, format: nil)
audioEngine.connect(changeEffect, to: audioEngine.outputNode, format: nil)
}
func playAudioWithVariablePitch(pitch:Float) {
changeEffect.pitch = pitch
create()
playAudio()
}
func playAudioWithVariableRate(rate: Float){
changeEffect.rate = rate
create()
playAudio()
}
func stopAudio(){
audioEngine.stop()
}
}
If you have a variable referencing the class, make a method to receive the data in that class and call the method and pass the data in prepareForSegue.
Well I hope I understand you right... But if I understand you right I don´t know what should be the problem?!? If you pass data to a subclassed UIViewcontroller class, or to any other class, its just the same?!? :-)
What error do you get? Or what happens if you run your code posted?
Maybe this helps you?
class VCOne: UIViewController {
lazy var audioEffect: AudioEffect = AudioEffect()
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "stopRecording") {
if let recordedAudio: RecordedAudio = sender as? RecordedAudio {
audioEffect.receivedAudio = recordedAudio
}
}
}
}
class AudioEffect {
var receivedAudio: RecordedAudio?
}