Swift 4: Azure DB with Facebook Authentication Callback method - facebook

app in swift4+xcode9 we are connection with DataBase in Azure with authentication through facebook.
in the App when launch the viewController, the login window of facebook appears.
I enter the user and the password but when the control will be return to the app will appears this window and stay there (nor return to the app control:
window callback
this is the code of viewDidAppear:
override func viewDidAppear(_ animated: Bool) {
let delegate = UIApplication.shared.delegate as! AppDelegate
let cliente = delegate.cliente
cliente?.login(withProvider: "facebook", urlScheme: "portfoliodispositivos", controller: self, animated: true) {
(usuario, error) -> Void in
if (error != nil) {
let alerta = UIAlertController(title: "Error", message: "OcurriĆ³ un error al iniciar sesiĆ³n en Facebook Error: \(String(describing: error?.localizedDescription))", preferredStyle: .alert)
alerta.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil))
self.present(alerta, animated: true, completion: nil)
} else {
print("sin error en login")
let tablaUbicaciones = cliente?.table(withName: "Ubicaciones")
tablaUbicaciones?.read(){
(resultado, error) in
if error != nil {
print("Error: \(error.debugDescription)")
} else {
self.ubicaciones.removeAll()
for item in (resultado?.items)! {
let ubicacion = item as NSDictionary
self.ubicaciones.append(ubicacion)
}
}
}
}
}
self.tableView.reloadData()
}
In previous versions of swift the login not included urlScheme and I do not understand what scheme it refers to.
If push 'Done' in the window the control return with error. I d not understand if the message is 'You have successfully signed in' why does not it come back without error automatically?

Related

How do I close a view after firebase google sign in

I have the code working for a swift 4 firebase google log in. The problem is after sign in, it just drops me back onto the view that was used for the sign in. Where do I execute the code to automatically close the view after the sign in?
I am assuming that your code looks something like this.
FIRAuth.auth()?.signIn(withEmail: self.emailTextField.text!, password: self.passwordTextField.text!) { (user, error) in
if error == nil {
//Print into the console if successfully logged in
print("You have successfully logged in")
//Go to the HomeViewController if the login is sucessful
let vc = self.storyboard?.instantiateViewController(withIdentifier: "Home")
self.present(vc!, animated: true, completion: nil)
//If you want to go back to the previous view then call
//For view embedded in navigation controller use,
self.navigationController?.popViewController(animated: true)
//For view that was presented use,
self.dismiss(animated: true, completion: nil)
} else {
//Tells the user that there is an error and then gets firebase to tell them the error
let alertController = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
}
}

How to rectify error when the app is uninstalled and then reinstalled and goes to the home page

If I uninstalls the app and then reinstall my app then it directly goes to the home page of the app. It doesn't ask the user to login.
I wrote the authStateListener for the current user to monitor when the app is removed in the background and then reinstalled, the app will show the login page instead of the Home page. When the user logs out then the app shows the login page otherwise the app goes to the home page. So when the user is logged out from the app and then uninstalls and reinstalls the app, it works correctly.
But my problem is if user isn't logged out, and uninstalls and reinstalls the app then it shows the home page of the app instead of the log in page. How do I solve this?
The code is :
class ViewController: UIViewController {
var db : Firestore!
var handle:AuthStateDidChangeListenerHandle?
#IBOutlet weak var email: UITextField!
#IBOutlet weak var pswd: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
db=Firestore.firestore()
print(currentReachabilityStatus != .notReachable)
let token = Messaging.messaging().fcmToken
let authid = Auth.auth().currentUser?.uid
print("token\(String(describing: token))")
let docRef = self.db.collection("deyaPayUsers").document(authid!)
docRef.setData(["FCMToken":token as Any],options:SetOptions.merge())
self.handle = Auth.auth().addStateDidChangeListener { auth, user in
if user != nil {
if (user?.isEmailVerified)!{
let myVC = self.storyboard?.instantiateViewController(withIdentifier: "deyaPay") as!deyaPay
self.navigationController?.pushViewController(myVC, animated:true)
}
else{
let alertVC = UIAlertController(title: "Error", message: "Sorry. Your email address has not yet been verified. Do you want us to send another verification email to \(String(describing: self.email.text!)).", preferredStyle: .alert)
let alertActionCancel = UIAlertAction(title: "Cancel", style: .default, handler: nil)
//alertVC.addAction(alertActionOkay)
alertVC.addAction(alertActionCancel)
self.present(alertVC, animated: true, completion: nil)
}
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(_ animated: Bool) {
if currentReachabilityStatus != .notReachable
{
print("Connected")
}
else
{
let controller = UIAlertController(title: "No Internet Detected", message: "This app requires an Internet connection", preferredStyle: .alert)
let ok = UIAlertAction(title: "OK", style: .default, handler: nil)
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
controller.addAction(ok)
controller.addAction(cancel)
present(controller, animated: true, completion: nil)
}
Auth.auth().addStateDidChangeListener{ auth, user in
if Auth.auth().currentUser != nil {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "deyaPay")as!deyaPay
//self.present(vc, animated: true, completion: nil)
let navigationController = UINavigationController(rootViewController: vc)
self.present(navigationController, animated: true, completion: nil)
} else {
print("signout")
}
}
}
}

Does replaykit allow to record the screen and then broadcast the screen?

Im having a problem where after I broadcast my screen live, I then try to record the screen but it doesn't work. Same thing happens when I record my screen and then I try to broadcast the screen live. Im not trying to do them together btw. This is after one is done and I try to use the other one. Let me know if you need to see code or more info. Im in Swift 3 and using the new replay kit framework. Thanks!
EDIT: THIS IS THE CODE IM USING
//LIVE STREAM REPLAYKIT=====================================================================
func broadcastActivityViewController(_ broadcastAVC: RPBroadcastActivityViewController, didFinishWith broadcastController: RPBroadcastController?, error: Error?) {
print("=====hello delegate \(broadcastController?.broadcastURL) (error)")
self.broadcastController = broadcastController
self.broadcastController?.delegate = self
broadcastAVC.dismiss(animated: true) {
self.broadcastController?.startBroadcast(handler: { error in
print("start broadcast \(error)")
print("\(broadcastController?.broadcastExtensionBundleID)")
print("==url=\(broadcastController?.broadcastURL)")
print("==serviceInfo=\(broadcastController?.serviceInfo)")
//This is called when the broadcast is live
})
}
}
func broadcastController(_ broadcastController: RPBroadcastController, didFinishWithError error: Error?) {
print("broadcastController====delegate")
let alert = UIAlertController(title: "Alert", message: "There was an error broadcasting your screen. Please try again", preferredStyle: UIAlertControllerStyle.alert)
// show the alert
self.view!.window?.rootViewController!.present(alert, animated: true, completion: nil)
alert.addAction(UIAlertAction(title: "Okay", style: UIAlertActionStyle.destructive, handler: { action in
// add action
}))
}
func broadcastController(_ broadcastController: RPBroadcastController, didUpdateServiceInfo serviceInfo: [String : NSCoding & NSObjectProtocol]) {
print("broadcastController====didUpdateServiceInfo")
}
//LIVE STREAM REPLAYKIT=========================================================
//RECORD SCREEN REPLAYKIT-------------------------------------------------------------------
func startRecoding() {
let recorder = RPScreenRecorder.shared()
if recorder.isAvailable {
recorder.startRecording(handler: { (error) in
if error == nil { // Recording has started
} else {
// Handle error
print("Dont Allow Recording")
}
})
} else {
print("Did not record screen")
//if iphone or ipad doesnt support replaykit
// create the alert
let alert = UIAlertController(title: "Alert", message: "Please make sure your device supports ReplayKit!", preferredStyle: UIAlertControllerStyle.alert)
// show the alert
self.view!.window?.rootViewController!.present(alert, animated: true, completion: nil)
alert.addAction(UIAlertAction(title: "Try Again!", style: UIAlertActionStyle.destructive, handler: { action in
// add action
}))
}
}
func stopRecording() {
let sharedRecorder = RPScreenRecorder.shared()
sharedRecorder.stopRecording(handler: { (previewViewController: RPPreviewViewController?, error) in
if previewViewController != nil {
print("stopped recording")
previewViewController!.previewControllerDelegate = self
let alertController = UIAlertController(title: "Recording", message: "Tap view to watch, edit, share, or save your screen recording!", preferredStyle: .alert)
let viewAction = UIAlertAction(title: "View", style: .default, handler: { (action: UIAlertAction) -> Void in
self.view?.window?.rootViewController?.present(previewViewController!, animated: true, completion: nil)
})
alertController.addAction(viewAction)
self.previewViewController = previewViewController!
self.previewViewController.modalPresentationStyle = UIModalPresentationStyle.fullScreen
self.view?.window?.rootViewController!.present(alertController, animated: true, completion: nil)
}
else {
print("recording stopped working")
//create the alert================================
let alert = UIAlertController(title: "Alert", message: "Sorry, there was an error recording your screen. Please Try Again!", preferredStyle: UIAlertControllerStyle.alert)
// show the alert
self.view!.window?.rootViewController!.present(alert, animated: true, completion: nil)
alert.addAction(UIAlertAction(title: "Try Again!", style: UIAlertActionStyle.destructive, handler: { action in
// add action
}))
}
})
}
func previewControllerDidFinish(_ previewViewController: RPPreviewViewController) {
print("cancel and save button pressed")
previewViewController.dismiss(animated: true, completion: nil)
//dismiss preview view controller when save or cancel button pressed
}
I believe that this is a bug in ReplayKit, I'm not sure if it has been resolved as of 10.1 or not, but it is worth trying the 10.1 beta to see if it solves your issue.

Delete Parse PFUser Account

I have an app(written in Swift) that uses Parse and allows a User to create an account. I want the user to have the option to delete their account but can't seem to figure it out and not sure what I'm doing wrong. I want the user to have to verify their email and password for this to occur. Once they've deleted their account, an alert pops up and then once the user dismisses the alert it takes them back to the log in screen and out of the app.
This is what I've tried:
#IBAction func deleteAccount(sender: AnyObject) {
if PFUser.currentUser()?.username == emailAddressTextField.text && PFUser.currentUser()?.password == passwordTextFieldOne.text && PFUser.currentUser()?.password == passwordTextFieldTwo.text {
PFUser.currentUser()?.deleteInBackgroundWithBlock({ (success: Bool, error: NSError?) -> Void in
if success {
let alertController = UIAlertController(title: "Success!", message: "Now Please Login", preferredStyle: .Alert)
let enterAppAction = UIAlertAction(title: "OK", style: .Default, handler: { (UIAlertAction) -> Void in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
let viewController:UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("Login")
self.presentViewController(viewController, animated: true, completion: nil)
})
})
alertController.addAction(enterAppAction)
self.presentViewController(alertController, animated: true, completion: nil)
} else {
print(error)
self.displayAlert("Account deletion failed", message: "Please try again", actionTitle: "OK")
}
})
}
}
You can make a cloud function to verify that the user correctly entered their current password and have it return success/error to iOS, at which point you can delete the account (provided the successful completion of the password check). Here's a relevant Parse forum post.
From the referenced post:
Parse.Cloud.define(FUNCTION_PASSWORD_CHECK, function(request, response)
{
var password = request.params.password;
Parse.User.logIn(request.user.getUsername(), password, {
success: function(results)
{
response.success(true);
},
error: function() {
response.success(false);
}
});
});
Note: you can do a similar login function on iOS, but that may mess with the PFUser.currentUser() if the user incorrectly enters their password (I'm not sure on that). Also, the referenced function uses the request.user, which is advised (i.e., not passing the user as a param as well), so that it only works for users with sessions.
Your initial if-statement:
if PFUser.currentUser()?.username == emailAddressTextField.text && PFUser.currentUser()?.password == passwordTextFieldOne.text && PFUser.currentUser()?.password == passwordTextFieldTwo.text
The statement PFUser.currentUser()?.password will return nil as parse does not make a users password accessible to you. Therefore, you won't be able to compare the user's password with the text entered into the textfield.
To check if the user has in fact entered a password that matches an existing password:
PFUser.logInWithUsernameInBackground(PFUser.currentUser(), password:passwordTextFieldOne.text!) {
(user: PFUser?, error: NSError?) -> Void in
if user != nil {
//continue with delete function
} else {
//Display error
}
}

Invalid Session Token (Code: 209 Version: 1.7.4)

Every time I go to run my app the app runs fine but the console prints an error. The error is "Invalid Session Token (Code: 209 Version: 1.7.4)"
I checked Parse.com and they told me to handle this error, writing a global utility function that is called by all of my parse request error callbacks. They said i can handle the "invalid session token" error in this global function and I should prompt the user to login again so that they can obtain a new session token. However when I try to input the code in my app I get the error that I am using unresolved identifiers.
Does anyone know how to fix an Invalid Session Token error. Or how I can use the code "kPFErrorInvalidSessionToken" in my app. Any help would be greatly appreciated. (the language I am writing in is swift)
I have tried to call ParseErrorHandler.handleParseError(err) not just only from AppDelegate, but also from other view controllers and it was not worked properly. Here is solution which works from every VC:
class ParseErrorHandler {
class func handleParseError(error: NSError) {
if error.domain != PFParseErrorDomain {
return
}
switch (error.code) {
// error code 209 handling
case PFErrorCode.ErrorInvalidSessionToken.rawValue:
invalidSessionTokenHandler()
default:
break
}
}
// NOTE: User has no other option but to log out in this implementation
private class func invalidSessionTokenHandler() {
let message: String = "Session is no longer valid! Please login again!"
let alert = UIAlertController(title: nil, message: message, preferredStyle: .Alert)
var vc = UIApplication.sharedApplication().keyWindow?.rootViewController
while (vc!.presentedViewController != nil)
{
vc = vc!.presentedViewController
}
vc?.presentViewController(alert, animated: true, completion: nil)
let logoutAction = UIAlertAction(title: "OK", style: .Default, handler: {
(UIAlertAction) -> Void in
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let exampleViewController: SignUpViewController = mainStoryboard.instantiateViewControllerWithIdentifier("SignUpViewController") as! SignUpViewController
vc?.presentViewController(exampleViewController, animated: true, completion: nil)
PFUser.logOut()
})
alert.addAction(logoutAction)
}
}
Hopefully I will save somebody's time!
If by saying "unresolved identifiers" you mean to "kPFErrorInvalidSessionToken" then you should use PFErrorCode.ErrorInvalidSessionToken.rawValue instead.
please tell me if you succeded in catching the error because all i get back is a nil NSErrorPointer.
Here is my solution, largely based on code in the Parse.com iOS developers guide.
class ParseErrorHandler {
class func handleParseError(error: NSError) {
if error.domain != PFParseErrorDomain {
return
}
switch (error.code) {
// error code 209 handling
case PFErrorCode.ErrorInvalidSessionToken.rawValue:
invalidSessionTokenHandler()
default:
break
}
}
// NOTE: User has no other option but to log out in this implementation
private class func invalidSessionTokenHandler() {
let message: String = "Session is no longer valid, you are no longer logged in"
let alert = UIAlertController(title: nil, message: message, preferredStyle: .Alert)
let presentingViewController = UIApplication.sharedApplication().keyWindow?.rootViewController
presentingViewController?.presentViewController(alert, animated: true, completion: nil)
let logoutAction = UIAlertAction(title: "OK", style: .Default, handler: {
(UIAlertAction) -> Void in
let loginViewController:UIViewController = UIStoryboard(name: "Main", bundle:
nil).instantiateViewControllerWithIdentifier("Login_2.0")
presentingViewController?.presentViewController(loginViewController, animated: true, completion: nil)
PFUser.logOut()
})
alert.addAction(logoutAction)
}
}
Above is the errorHandler class that should be used to catch all errors according to the Parse documentation (in this case I'm only showing error 209)
Here is how I catch this error in AppDelegate.swift within application function:
PFAnalytics.trackAppOpenedWithLaunchOptionsInBackground(launchOptions, block: {
(suceeded: Bool?, error: NSError?) -> Void in
if let err = error {
ParseErrorHandler.handleParseError(err)
}
})
Note that the user is technically still logged in hence why logout is called