Skip to content

Instantly share code, notes, and snippets.

@cjazz
Created November 23, 2016 17:42
Show Gist options
  • Save cjazz/5275790c270aa8c47c041c232fe7bc99 to your computer and use it in GitHub Desktop.
Save cjazz/5275790c270aa8c47c041c232fe7bc99 to your computer and use it in GitHub Desktop.
LoginFireBaseVC - Implements Logging auth for Firebase : Facebook/Twitter & set Email/PW. Also, captures email address & profile images
//
// LoginVC.m
//
// Created by Adam Chin on 7/14/16.
//
// This implementation is an example of Login Methods to Firebase
// Google's MBaaS. It includes login auths to Facebook and Twitter
// as well as Email Logging.
//
// Client Requirements:
// * Loging / Auth via Facebook, Twitter & Email
// * Storing Users Email for future contact
// * Capturing Images from Facebook / Twitter for optionally setting
// the users profile image consistently or making a new one (outside of the scope of this file)
// Practical use & suggestions:
// 1) If you're not an iOS developer find one to explain
// 2) It is required to set up a Firebase account, and set up your project accordingly
// either manually or with CocoaPods
// 3) In the Firebase console, set up FaceBook, Twitter, and Email auth
// 4) Design a Login screen with appropriate UI IBOutlets
//
// If you would like to see this example working in an app, contact me
// and if I have available time I will help you.
// Note: This isn't 100% prod ready as a few spots need further error handling and clean up.
#import "LoginVC.h"
#import "MBProgressHUD.h"
#import "UIViewController+Alerts.h"
#import <FBSDKCoreKit/FBSDKCoreKit.h>
#import <FBSDKLoginKit/FBSDKLoginKit.h>
#import "IonIcons.h"
@import FirebaseAuth;
@import TwitterKit;
#import "MBProgressHUD.h"
#import "TwitterAPIBundle.h"
#define USERPW_AUTHENTICATION_TYPE @"Username-Password-Authentication"
#define HTTP_RESPONSE_ISSUE 202
#define TWITTER_PROFILE_URL @"https://api.twitter.com/1.1/account/verify_credentials.json"
@interface LoginVC () <UITextFieldDelegate>
@property (weak, nonatomic) IBOutlet UIButton *signInButton;
@property (weak, nonatomic) IBOutlet UIButton *cancelButton;
@property(weak, nonatomic) IBOutlet UITextField *emailField;
@property(weak, nonatomic) IBOutlet UITextField *passwordField;
@property (nonatomic, weak) IBOutlet UIButton *facebookButton;
@property (nonatomic, weak) IBOutlet UIButton *twitterButton;
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *ActivityIndicator;
@property (strong, nonatomic) NSString *twitterEmail;
@property (nonatomic, weak) NSString *connectionType;
@end
@implementation LoginVC
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self.view endEditing:YES];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.ActivityIndicator.hidesWhenStopped = YES;
[self.emailField.layer addSublayer:[GlobalUI bottomBorderFor:self.emailField]];
[self.passwordField.layer addSublayer:[GlobalUI bottomBorderFor:self.passwordField]];
}
- (IBAction)cancel:(id)sender
{
[self dismissViewControllerAnimated:YES completion:nil];
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.emailField.delegate = self;
self.passwordField.delegate = self;
self.signInButton.layer.cornerRadius = 5;
self.signInButton.clipsToBounds = YES;
self.cancelButton.layer.cornerRadius = 5;
self.cancelButton.clipsToBounds = YES;
self.facebookButton.layer.cornerRadius = 5;
self.facebookButton.clipsToBounds = YES;
self.twitterButton.layer.cornerRadius = 5;
self.twitterButton.clipsToBounds = YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if (textField == self.emailField)
{
[textField resignFirstResponder];
[self.passwordField becomeFirstResponder];
} else if (textField == self.passwordField) {
[self didTapEmailLogin:self];
}
return YES;
}
- (IBAction)socialLogin:(id)sender {
[self.ActivityIndicator startAnimating];
if (sender == self.facebookButton)
{
if ([FBSDKAccessToken currentAccessToken]) // check for fb token
{
[self.ActivityIndicator stopAnimating];
UIAlertController *alert = [UIAlertController
alertControllerWithTitle:@"Facebook Login"
message:@"Already Logged in, no need to login again.."
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"Ok"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *action) {
}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
}
else
{
FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
[login logInWithReadPermissions:@[@"public_profile", @"email"]
fromViewController:self
handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
NSLog(@"Facebook Response Data: %@",result);
if (error) {
[self.ActivityIndicator stopAnimating];
UIAlertController *alert = [UIAlertController
alertControllerWithTitle:@"Facebook"
message:@"Could not login to Facebook at this time, try again later.."
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"Ok"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *action) {
}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
} else {
[self.ActivityIndicator stopAnimating];
#ifdef DEBUG
NSLog(@"----------------------------------------------->");
NSLog(@" FBSDKLoginManager: Login success");
NSLog(@" Result: %@",result);
NSLog(@"----------------------------------------------->");
#endif
if ([FBSDKAccessToken currentAccessToken]) // on
{
// get facebook profile image with currentAccessToken.userID:
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"https://graph.facebook.com/%@/picture?type=normal",
[FBSDKAccessToken currentAccessToken].userID]];
NSData *data = [NSData dataWithContentsOfURL:url];
if (data)
{
NSString *fileName = @"faceBookProfile.jpg";
NSFileManager *fm = [NSFileManager new];
NSError *err = nil;
NSURL *docsURL = [fm URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:&err];
NSURL *jsonFolder = [docsURL URLByAppendingPathComponent:@"SocialProfileImages"];
if ([fm createDirectoryAtURL:jsonFolder
withIntermediateDirectories:YES
attributes:nil
error:&err])
{
NSURL *fileURL = [jsonFolder URLByAppendingPathComponent:fileName];
if ([data writeToURL:fileURL options:NSDataWritingAtomic error:&err])
{
#ifdef DEBUG
NSLog(@"----------------------------------------------->");
NSLog(@" Saved Facebook Profile Pic");
NSLog(@"----------------------------------------------->");
#endif
}
else
{
NSLog(@"file not saved :%@ error: %@",fileName, err);
}
}
}
FIRAuthCredential *credential = [FIRFacebookAuthProvider
credentialWithAccessToken:[FBSDKAccessToken currentAccessToken].tokenString];
[[FIRAuth auth] signInWithCredential:credential
completion:^(FIRUser *user, NSError *error) {
if (error) {
NSLog(@"Error logging into Firebase: %@", error);
} else
{
#ifdef DEBUG
NSLog(@"----------------------------------------------->");
NSLog(@" FIRAuth Facebook SignInWithCredential: Login success");
NSLog(@" Result: %@",user);
NSLog(@"----------------------------------------------->");
#endif
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.mode = MBProgressHUDModeCustomView;
UIImage *image = [[UIImage imageNamed:@"Checkmark"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
hud.customView = [[UIImageView alloc] initWithImage:image];
hud.square = YES;
hud.label.text = NSLocalizedString(@"Success!", @"HUD done title");
[hud hideAnimated:YES afterDelay:2.f];
[self performSelector:@selector(dismissView) withObject:self afterDelay:2.0];
}
}];
}
}
}];
}
}
else if (sender == self.twitterButton)
{
self.connectionType = @"twitter";
[self twitterStartLoginFlow];
[self.ActivityIndicator stopAnimating];
}
}
// MARK: twitter login methods
-(void)twitterStartLoginFlow
{
TWTRLogInButton* logInButton = [TWTRLogInButton buttonWithLogInCompletion:^(TWTRSession* session, NSError* error) {
}];
logInButton.loginMethods = TWTRLoginMethodWebBased;
[[Twitter sharedInstance] logInWithMethods:TWTRLoginMethodWebBased completion:^(TWTRSession *session, NSError *error) {
if (session) {
TWTRAPIClient *client = [TWTRAPIClient clientWithCurrentUser];
NSURLRequest *request = [client URLRequestWithMethod:@"GET"
URL:TWITTER_PROFILE_URL
parameters:@{@"include_email": @"true", @"skip_status": @"true"}
error:nil];
[client sendTwitterRequest:request completion:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
if ((long)[httpResponse statusCode] > HTTP_RESPONSE_ISSUE)
{
UIAlertController *alert = [UIAlertController
alertControllerWithTitle:@"Twitter Login"
message:@"There's an issue with the Twitter service.."
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"Ok"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *action) {
}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
return;
}
NSDictionary *responseData = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
if (responseData) {
self.twitterEmail = [responseData valueForKey:@"email"];
if (self.twitterEmail.length) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self twitterSignInToFirebaseAndLogEmail:session];
[self getTwitterProfileImage:session];
});
[self.ActivityIndicator stopAnimating];
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.mode = MBProgressHUDModeCustomView;
UIImage *image = [[UIImage imageNamed:@"Checkmark"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
hud.customView = [[UIImageView alloc] initWithImage:image];
hud.square = YES;
hud.label.text = NSLocalizedString(@"Success!", @"HUD done title");
[hud hideAnimated:YES afterDelay:2.f];
[self performSelector:@selector(dismissView) withObject:self afterDelay:2.f];
}
}
}];
} else [self.ActivityIndicator stopAnimating];
}];
}
-(void)twitterSignInToFirebaseAndLogEmail:(TWTRSession*)session
{
if (session)
{
__weak NSString *weakself = self.twitterEmail;
FIRAuthCredential *credential = [FIRTwitterAuthProvider credentialWithToken:session.authToken
secret:session.authTokenSecret];
[[FIRAuth auth] signInWithCredential:credential
completion:^(FIRUser *user, NSError *error) {
if (error) {
// NSLog(@"Error logging into Twitter: %@", error);
}
else
{
[[FIRAuth auth].currentUser updateEmail:weakself
completion:^(NSError * _Nullable error) {
if (error) {
}
else{
#ifdef DEBUG
NSLog(@"----------------------------------------------->");
NSLog(@" FIRAuth Twitter Added email to Firebase profile:");
NSLog(@" Result: %@",user);
NSLog(@"----------------------------------------------->");
#endif
}
}];
}
}];
} else [self.ActivityIndicator stopAnimating];
}
-(void)getTwitterProfileImage:(TWTRSession*)session
{
if (session) {
TWTRAPIClient *client = [TWTRAPIClient clientWithCurrentUser];
NSString *userID = [Twitter sharedInstance].sessionStore.session.userID;
[client loadUserWithID:userID completion:^(TWTRUser * _Nullable user, NSError * _Nullable error) {
if (user.profileImageLargeURL.length)
{
NSString *stringURL = user.profileImageLargeURL;
NSURL *url = [NSURL URLWithString:stringURL];
NSData *urlData = [NSData dataWithContentsOfURL:url];
if (urlData)
{
NSString *fileName = @"twitterProfile.jpg";
NSFileManager *fm = [NSFileManager new];
NSError *err = nil;
NSURL *docsURL = [fm URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:&err];
NSURL *jsonFolder = [docsURL URLByAppendingPathComponent:@"SocialProfileImages"];
if ([fm createDirectoryAtURL:jsonFolder
withIntermediateDirectories:YES
attributes:nil
error:&err])
{
NSURL *fileURL = [jsonFolder URLByAppendingPathComponent:fileName];
if ([urlData writeToURL:fileURL options:NSDataWritingAtomic error:&err])
{
#ifdef DEBUG
NSLog(@"----------------------------------------------->");
NSLog(@" Saved Twitter Profile Image:");
NSLog(@"----------------------------------------------->");
#endif
}
else
{
NSLog(@"file not saved :%@ error: %@",fileName, err);
}
}
}
}
}];
} else [self.ActivityIndicator stopAnimating];
}
// MARK: email login methods
- (IBAction)didTapEmailLogin:(id)sender {
[self.ActivityIndicator startAnimating];
NSString *email = self.emailField.text;
NSString *password = self.passwordField.text;
[[FIRAuth auth] signInWithEmail:email
password:password
completion:^(FIRUser * _Nullable user, NSError * _Nullable error) {
if (error) {
[self.ActivityIndicator stopAnimating];
}
else {
#ifdef DEBUG
NSLog(@"----------------------------------------------->");
NSLog(@" FIRAuth Sign in with Email");
NSLog(@" Success with user: %@",user);
NSLog(@"----------------------------------------------->");
#endif
[self.ActivityIndicator stopAnimating];
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.mode = MBProgressHUDModeCustomView;
UIImage *image = [[UIImage imageNamed:@"Checkmark"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
hud.customView = [[UIImageView alloc] initWithImage:image];
hud.square = YES;
hud.label.text = NSLocalizedString(@"Success!", @"HUD done title");
[hud hideAnimated:YES afterDelay:2.f];
[self performSelector:@selector(dismissView) withObject:self afterDelay:2.f];
}
}];
}
- (IBAction)didRequestPasswordReset:(id)sender {
[self showTextInputPromptWithMessage:@"Enter Email for password reset:"
completionBlock:^(BOOL userPressedOK, NSString *_Nullable userInput) {
if (!userPressedOK || !userInput.length) {
return;
}
[self showSpinner:^{
[[FIRAuth auth]
sendPasswordResetWithEmail:userInput
completion:^(NSError *_Nullable error) {
// [START_EXCLUDE]
[self hideSpinner:^{
if (error) {
[self
showMessagePrompt:error
.localizedDescription];
return;
}
[self showMessagePrompt:@"Sent"];
}];
}];
}];
}];
}
-(void)dismissView
{
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment