Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 43 additions & 27 deletions FirebaseAuthUI/FUIAuth.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#import "FUIAuthStrings.h"
#import "FUIGoogleAuth.h"
#import "FUIEmailEntryViewController.h"
#import "FUIPasswordSignInViewController_Internal.h"
#import "FUIPasswordVerificationViewController.h"

/** @var kAppNameCodingKey
Expand Down Expand Up @@ -154,7 +155,7 @@ - (BOOL)signOutWithError:(NSError *_Nullable *_Nullable)error {
}

- (void)signInWithProviderUI:(id<FUIAuthProvider>)providerUI
presentingViewController:(UIViewController *)presentingViewController
presentingViewController:(FUIAuthBaseViewController *)presentingViewController
defaultValue:(nullable NSString *)defaultValue {

// Sign out first to make sure sign in starts with a clean state.
Expand Down Expand Up @@ -280,7 +281,7 @@ - (void)signInWithProviderUI:(id<FUIAuthProvider>)providerUI
}

- (void)signInWithEmailHint:(NSString *)emailHint
presentingViewController:(UIViewController *)presentingViewController
presentingViewController:(FUIAuthBaseViewController *)presentingViewController
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like the only method being used on these controllers is pushViewController:, in which case UIViewController should be ok. If this is public API, we want to provide the highest-level types possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

signInWithEmailHint:presentingViewController:completion: isn't a public API, it's only used for a special case of automatic upgrade behind the scenes. The pushViewController: method being used here is a custom method which modifies the way the navigation bar is presented when the view controller is pushed.

completion:(FIRAuthDataResultCallback)completion {
NSString *kTempApp = @"tempApp";
FIROptions *options = [FIROptions defaultOptions];
Expand All @@ -291,47 +292,62 @@ - (void)signInWithEmailHint:(NSString *)emailHint
FIRApp *tempApp = [FIRApp appNamed:kTempApp];
// Create a new auth instance in order to perform a successful sign-in without losing the
// currently signed in user on the default auth instance.
FIRAuth *auth = [FIRAuth authWithApp:tempApp];
FIRAuth *tempAuth = [FIRAuth authWithApp:tempApp];

[self.auth fetchProvidersForEmail:emailHint completion:^(NSArray<NSString *> *_Nullable providers,
NSError *_Nullable error) {
if (error) {
completion(nil, error);
return;
}
NSString *existingFederatedProviderID = [self federatedAuthProviderFromProviders:providers];
// Set of providers which can be auto-linked
NSString *existingFederatedProviderID = [self authProviderFromProviders:providers];
// Set of providers which can be auto-linked.
NSSet *supportedProviders =
[NSSet setWithObjects:FIRGoogleAuthProviderID, FIRFacebookAuthProviderID, nil];
[NSSet setWithObjects:FIRGoogleAuthProviderID,
FIRFacebookAuthProviderID,
FIREmailAuthProviderID,
nil];
if ([supportedProviders containsObject:existingFederatedProviderID]) {
id<FUIAuthProvider> authProviderUI;
// Retrieve the FUIAuthProvider instance from FUIAuth for the existing provider ID.
for (id<FUIAuthProvider> provider in self.providers) {
if ([provider.providerID isEqualToString:existingFederatedProviderID]) {
authProviderUI = provider;
break;
if ([existingFederatedProviderID isEqualToString:FIREmailAuthProviderID]) {
FUIAuth *authUI = [[FUIAuth alloc]initWithAuth:tempAuth];
// Email password sign-in
FUIPasswordSignInViewController *controller =
[[FUIPasswordSignInViewController alloc] initWithAuthUI:authUI email:emailHint];
controller.onDismissCallback = completion;
[presentingViewController pushViewController:controller];
} else {
id<FUIAuthProvider> authProviderUI;
// Retrieve the FUIAuthProvider instance from FUIAuth for the existing provider ID.
for (id<FUIAuthProvider> provider in self.providers) {
if ([provider.providerID isEqualToString:existingFederatedProviderID]) {
authProviderUI = provider;
break;
}
}
[authProviderUI signOut];
[authProviderUI signInWithDefaultValue:emailHint
presentingViewController:presentingViewController
completion:^(FIRAuthCredential *_Nullable credential,
NSError *_Nullable error,
FIRAuthResultCallback _Nullable result) {
if (error) {
if (completion) {
completion(nil, error);
}
return;
}
[tempAuth signInAndRetrieveDataWithCredential:credential completion:completion];
}];
}
[authProviderUI signOut];
[authProviderUI signInWithDefaultValue:emailHint
presentingViewController:presentingViewController
completion:^(FIRAuthCredential *_Nullable credential,
NSError *_Nullable error,
FIRAuthResultCallback _Nullable result) {
if (error) {
completion(nil, error);
return;
}

[auth signInAndRetrieveDataWithCredential:credential completion:completion];
}];
}
}];
}

- (nullable NSString *)federatedAuthProviderFromProviders:(NSArray <NSString *> *) providers {
- (nullable NSString *)authProviderFromProviders:(NSArray <NSString *> *) providers {
NSSet *providerSet =
[NSSet setWithArray:@[ FIRFacebookAuthProviderID, FIRGoogleAuthProviderID ]];
[NSSet setWithArray:@[ FIRFacebookAuthProviderID,
FIRGoogleAuthProviderID,
FIREmailAuthProviderID ]];
for (NSString *provider in providers) {
if ( [providerSet containsObject:provider]) {
return provider;
Expand Down
10 changes: 8 additions & 2 deletions FirebaseAuthUI/FUIPasswordSignInViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// limitations under the License.
//

#import "FUIPasswordSignInViewController.h"
#import "FUIPasswordSignInViewController_Internal.h"

#import <FirebaseAuth/FirebaseAuth.h>
#import "FUIAuthBaseViewController_Internal.h"
Expand Down Expand Up @@ -80,6 +80,10 @@ - (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil
_email = [email copy];

self.title = FUILocalizedString(kStr_SignInTitle);
__weak FUIPasswordSignInViewController *weakself = self;
_onDismissCallback = ^(FIRAuthDataResult *authResult, NSError *error){
[weakself.authUI invokeResultCallbackWithAuthDataResult:authResult error:error];
};
}
return self;
}
Expand Down Expand Up @@ -134,7 +138,9 @@ - (void)signInWithDefaultValue:(NSString *)email andPassword:(NSString *)passwor
}
}
[self.navigationController dismissViewControllerAnimated:YES completion:^{
[self.authUI invokeResultCallbackWithAuthDataResult:authResult error:error];
if (self->_onDismissCallback) {
self->_onDismissCallback(authResult, error);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is usually a good idea to nil-out callback blocks after use to avoid circular references.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went with the property approach outlined in you other comment. Since the block will be reused I leave it up to the developer using a custom block to decide whether or not it should be set to nil.

}
}];
};

Expand Down
35 changes: 35 additions & 0 deletions FirebaseAuthUI/FUIPasswordSignInViewController_Internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// Copyright (c) 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#import "FUIPasswordSignInViewController.h"
#import <FirebaseAuth/FirebaseAuth.h>

NS_ASSUME_NONNULL_BEGIN

@interface FUIPasswordSignInViewController ()

/** @property onDismissCallback:
@brief Sets an optional custom callback for FUIPasswordSigInViewController during dismissal. If
this property is set the default dismissal routine is not triggered and should be included
in this block if necessary. This block is NOT set to nil after use, set to nil after using
if you wish to avoid circular references.
*/
@property(nonatomic, strong, nullable) FIRAuthDataResultCallback onDismissCallback;

NS_ASSUME_NONNULL_END


@end