diff options
author | Xiangtian Dai <xiangtian@google.com> | 2017-08-01 11:15:35 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-08-01 11:15:35 -0700 |
commit | 18fef1fea0c2c1e95b6b0d9b154810d93d247df1 (patch) | |
tree | b4e76944bb67a76a4202a89383b6ec4295b0deb9 /AuthSamples | |
parent | 91fee9d66dabc6d7db34df1a47fc22a50b45ffb2 (diff) |
Enables auth sample app to use multiple Firebase Apps. (#162)
Diffstat (limited to 'AuthSamples')
-rw-r--r-- | AuthSamples/Sample/AppManager.h | 80 | ||||
-rw-r--r-- | AuthSamples/Sample/AppManager.m | 135 | ||||
-rw-r--r-- | AuthSamples/Sample/GoogleAuthProvider.m | 3 | ||||
-rw-r--r-- | AuthSamples/Sample/MainViewController.m | 165 | ||||
-rw-r--r-- | AuthSamples/Sample/SettingsViewController.m | 122 | ||||
-rw-r--r-- | AuthSamples/Samples.xcodeproj/project.pbxproj | 6 |
6 files changed, 384 insertions, 127 deletions
diff --git a/AuthSamples/Sample/AppManager.h b/AuthSamples/Sample/AppManager.h new file mode 100644 index 0000000..e8e53a7 --- /dev/null +++ b/AuthSamples/Sample/AppManager.h @@ -0,0 +1,80 @@ +/* + * Copyright 2017 Google + * + * 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 <Foundation/Foundation.h> + +@class FIRApp; +@class FIRAuth; +@class FIROptions; +@class FIRPhoneAuthProvider; + +NS_ASSUME_NONNULL_BEGIN + +/** @class AppManager + @brief A manager of global FIRApp instances. + */ +@interface AppManager : NSObject + +/** @property count + @brief The total count of apps under management, including the default app. + */ +@property(nonatomic, assign, readonly) int count; + +/** @property active + @brief The index of the currently active app, 0 being the default app. + */ +@property(nonatomic, assign) int active; + +/** @fn appAtIndex: + @brief Retrieves the app at the given index. + @param index The index of the app to be retrieved, 0 being the default app. + @return The app at the given index. + */ +- (nullable FIRApp *)appAtIndex:(int)index; + +/** @fn recreateAppAtIndex:withOptions:completion: + @brief Deletes the app at the given index, and optionally creates it again with given options. + @param index The index of the app to be recreated, 0 being the default app. + @param options Optionally, the new options with which app should be created. + @param completion The block to call when completes. + */ +- (void)recreateAppAtIndex:(int)index + withOptions:(nullable FIROptions *)options + completion:(void (^)())completion; + +/** @fn sharedInstance + @brief Gets a shared instance of the class. + */ ++ (instancetype)sharedInstance; + +/** @fn app + @brief A shortcut to get the currently active app. + */ ++ (FIRApp *)app; + +/** @fn auth + @brief A shortcut to get the auth instance for the currently active app. + */ ++ (FIRAuth *)auth; + +/** @fn phoneAuthProvider + @brief A shortcut to get the phone auth provider for the currently active app. + */ ++ (FIRPhoneAuthProvider *)phoneAuthProvider; + +@end + +NS_ASSUME_NONNULL_END diff --git a/AuthSamples/Sample/AppManager.m b/AuthSamples/Sample/AppManager.m new file mode 100644 index 0000000..116fcf7 --- /dev/null +++ b/AuthSamples/Sample/AppManager.m @@ -0,0 +1,135 @@ +/* + * Copyright 2017 Google + * + * 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 "AppManager.h" + +#import "FirebaseAuth.h" +#import "FirebaseCore.h" +#import "FIRPhoneAuthProvider.h" + +NS_ASSUME_NONNULL_BEGIN + +// Declares a private method of FIRInstanceID to work around a bug. +@interface FIRInstanceID : NSObject ++ (void)notifyTokenRefresh; +@end + +@implementation AppManager { + /** @var _createdAppNames + @brief The set of names of live (created but not deleted) app, to avoid iCore warnings. + */ + NSMutableSet<NSString *> *_liveAppNames; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _count = 2; + _liveAppNames = [[NSMutableSet<NSString *> alloc] initWithCapacity:_count - 1]; + } + return self; +} + +- (nullable FIRApp *)appAtIndex:(int)index { + if (index == 0) { + return [FIRApp defaultApp]; + } + NSString *name = [self appNameWithIndex:index]; + if ([_liveAppNames containsObject:name]) { + return [FIRApp appNamed:[self appNameWithIndex:index]]; + } + return nil; +} + +- (void)recreateAppAtIndex:(int)index + withOptions:(nullable FIROptions *)options + completion:(void (^)())completion { + [self deleteAppAtIndex:index completion:^() { + if (index == 0) { + [FIRInstanceID notifyTokenRefresh]; // b/28967043 + if (options) { + [FIRApp configureWithOptions:options]; + } + } else { + NSString *name = [self appNameWithIndex:index]; + if (options) { + [FIRApp configureWithName:name options:options]; + [_liveAppNames addObject:name]; + } else { + [_liveAppNames removeObject:name]; + } + } + completion(); + }]; +} + ++ (instancetype)sharedInstance { + static dispatch_once_t onceToken; + static AppManager *sharedInstance; + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] init]; + }); + return sharedInstance; +} + ++ (FIRApp *)app { + AppManager *manager = [self sharedInstance]; + return [manager appAtIndex:manager.active]; +} + ++ (FIRAuth *)auth { + return [FIRAuth authWithApp:[self app]]; +} + ++ (FIRPhoneAuthProvider *)phoneAuthProvider { + return [FIRPhoneAuthProvider providerWithAuth:[self auth]]; +} + +#pragma mark - Helpers + +/** @fn appNameWithIndex: + @brief Gets the app name for the given index. + @param index The index of the app managed by this instance. + @returns The app name for the FIRApp instance. + */ +- (NSString *)appNameWithIndex:(int)index { + return [NSString stringWithFormat:@"APP_%02d", index]; +} + +/** @fn deleteAppAtIndex:withOptions:completion: + @brief Deletes the app at the given index. + @param index The index of the app to be deleted, 0 being the default app. + @param completion The block to call when completes. + */ +- (void)deleteAppAtIndex:(int)index + completion:(void (^)())completion { + FIRApp *app = [self appAtIndex:index]; + if (app) { + [app deleteApp:^(BOOL success) { + if (success) { + completion(); + } else { + NSLog(@"Failed to delete app '%@'.", app.name); + } + }]; + } else { + completion(); + } +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/AuthSamples/Sample/GoogleAuthProvider.m b/AuthSamples/Sample/GoogleAuthProvider.m index 23285cc..e63ade0 100644 --- a/AuthSamples/Sample/GoogleAuthProvider.m +++ b/AuthSamples/Sample/GoogleAuthProvider.m @@ -18,6 +18,7 @@ #import <GoogleSignIn/GoogleSignIn.h> +#import "AppManager.h" #import "FIRApp.h" #import "FIROptions.h" #import "FIRGoogleAuthProvider.h" @@ -123,7 +124,7 @@ typedef void (^GoogleSignInCallback)(GIDGoogleUser *user, NSError *error); } - (NSString *)googleClientID { - return [FIRApp defaultApp].options.clientID; + return [AppManager app].options.clientID; } @end diff --git a/AuthSamples/Sample/MainViewController.m b/AuthSamples/Sample/MainViewController.m index 8ee1b39..ec97506 100644 --- a/AuthSamples/Sample/MainViewController.m +++ b/AuthSamples/Sample/MainViewController.m @@ -18,6 +18,7 @@ #import <objc/runtime.h> +#import "AppManager.h" #import "AuthCredentials.h" #import "FIRAdditionalUserInfo.h" #import "FirebaseCommunity/FIRApp.h" @@ -578,6 +579,10 @@ typedef void (^FIRTokenCallback)(NSString *_Nullable token, NSError *_Nullable e _userInMemoryInfoTableViewCell.userInfoProfileURLImageView.layer.cornerRadius = _userInMemoryInfoTableViewCell.userInfoProfileURLImageView.frame.size.width / 2.0f; _userInMemoryInfoTableViewCell.userInfoProfileURLImageView.layer.masksToBounds = YES; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; [self updateTable]; [self updateUserInfo]; } @@ -753,7 +758,7 @@ typedef void (^FIRTokenCallback)(NSString *_Nullable token, NSError *_Nullable e } - (IBAction)memoryPlus { - _userInMemory = [FIRAuth auth].currentUser; + _userInMemory = [AppManager auth].currentUser; [self updateUserInfo]; } @@ -806,9 +811,9 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { if (!userPressedOK || !newPassword.length) { return; } - [[FIRAuth auth] confirmPasswordResetWithCode:queryItems[@"oobCode"] - newPassword:newPassword - completion:^(NSError *_Nullable error) { + [[AppManager auth] confirmPasswordResetWithCode:queryItems[@"oobCode"] + newPassword:newPassword + completion:^(NSError *_Nullable error) { [self hideSpinner:^{ if (error) { [self logFailure:@"Password reset failed" error:error]; @@ -843,8 +848,8 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { [self logFailedTest:@"The test needs a valid credential to continue."]; return; } - [[FIRAuth auth] signInWithCredential:credential completion:^(FIRUser *_Nullable user, - NSError *_Nullable error) { + [[AppManager auth] signInWithCredential:credential completion:^(FIRUser *_Nullable user, + NSError *_Nullable error) { if (error) { [self logFailure:@"sign-in with provider failed" error:error]; [self logFailedTest:@"Sign-in should succeed"]; @@ -865,7 +870,7 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { message:kSafariGoogleSignOutMessagePrompt showCancelButton:NO completion:^(BOOL userPressedOK, NSString *_Nullable userInput) { - FIRAuth *auth = [FIRAuth auth]; + FIRAuth *auth = [AppManager auth]; if (!auth) { [self logFailedTest:@"Could not obtain auth object."]; return; @@ -906,7 +911,7 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { message:kSafariFacebookSignOutMessagePrompt showCancelButton:NO completion:^(BOOL userPressedOK, NSString *_Nullable userInput) { - FIRAuth *auth = [FIRAuth auth]; + FIRAuth *auth = [AppManager auth]; if (!auth) { [self logFailedTest:@"Could not obtain auth object."]; return; @@ -931,7 +936,7 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { */ - (void)automatedEmailSignUp { [self log:@"INITIATING AUTOMATED MANUAL TEST FOR FACEBOOK SIGN IN:"]; - FIRAuth *auth = [FIRAuth auth]; + FIRAuth *auth = [AppManager auth]; if (!auth) { [self logFailedTest:@"Could not obtain auth object."]; return; @@ -974,7 +979,7 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { */ - (void)automatedAnonymousSignIn { [self log:@"INITIATING AUTOMATED MANUAL TEST FOR ANONYMOUS SIGN IN:"]; - FIRAuth *auth = [FIRAuth auth]; + FIRAuth *auth = [AppManager auth]; if (!auth) { [self logFailedTest:@"Could not obtain auth object."]; return; @@ -999,7 +1004,7 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { @param callback The callback to be executed. */ - (void)signInAnonymouslyWithCallback:(nullable FIRAuthResultCallback)callback { - FIRAuth *auth = [FIRAuth auth]; + FIRAuth *auth = [AppManager auth]; if (!auth) { [self logFailedTest:@"Could not obtain auth object."]; return; @@ -1023,7 +1028,7 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { */ - (void)automatedAccountLinking { [self log:@"INITIATING AUTOMATED MANUAL TEST FOR ACCOUNT LINKING:"]; - FIRAuth *auth = [FIRAuth auth]; + FIRAuth *auth = [AppManager auth]; if (!auth) { [self logFailedTest:@"Could not obtain auth object."]; return; @@ -1098,7 +1103,7 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { [self log:@"There was an error retrieving the custom token."]; return; } - FIRAuth *auth = [FIRAuth auth]; + FIRAuth *auth = [AppManager auth]; [auth signInWithCustomToken:customToken completion:^(FIRUser *_Nullable user, NSError *_Nullable error) { if (error) { @@ -1158,8 +1163,8 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { [self log:@"There was an error retrieving the custom token."]; return; } - [[FIRAuth auth] signInWithCustomToken:customToken - completion:^(FIRUser *_Nullable user, NSError *_Nullable error) { + [[AppManager auth] signInWithCustomToken:customToken + completion:^(FIRUser *_Nullable user, NSError *_Nullable error) { if (error) { [self logFailure:@"sign-in with custom token failed" error:error]; [self logFailedTest:@"A fresh custom token should succeed in signing-in."]; @@ -1188,8 +1193,8 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { [self log:@"There was an error retrieving the custom token."]; return; } - [[FIRAuth auth] signInWithCustomToken:customToken - completion:^(FIRUser *_Nullable user, NSError *_Nullable error) { + [[AppManager auth] signInWithCustomToken:customToken + completion:^(FIRUser *_Nullable user, NSError *_Nullable error) { if (error) { [self logFailure:@"sign-in with custom token failed" error:error]; [self logFailedTest:@"A fresh custom token should succeed in signing-in."]; @@ -1211,7 +1216,7 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { @param completion The completion block to continue the automatic test flow. */ - (void)updateEmailPasswordWithCompletion:(void(^)(void))completion { - FIRAuth *auth = [FIRAuth auth]; + FIRAuth *auth = [AppManager auth]; [auth.currentUser updateEmail:kFakeEmail completion:^(NSError *_Nullable error) { if (error) { [self logFailure:@"update email failed" error:error]; @@ -1258,7 +1263,7 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { @param completion The completion block to continue the automatic test flow. */ - (void)updateDisplayNameAndPhotoURlWithCompletion:(void(^)(void))completion { - FIRAuth *auth = [FIRAuth auth]; + FIRAuth *auth = [AppManager auth]; FIRUserProfileChangeRequest *changeRequest = [auth.currentUser profileChangeRequest]; changeRequest.photoURL = [NSURL URLWithString:kFakeDisplayPhotoUrl]; [changeRequest commitChangesWithCompletion:^(NSError *_Nullable error) { @@ -1291,8 +1296,8 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { [self log:[NSString stringWithFormat:@"Auth State Did Change Listener #%lu was added.", (unsigned long)index]]; FIRAuthStateDidChangeListenerHandle handle = - [[FIRAuth auth] addAuthStateDidChangeListener:^(FIRAuth *_Nonnull auth, - FIRUser *_Nullable user) { + [[AppManager auth] addAuthStateDidChangeListener:^(FIRAuth *_Nonnull auth, + FIRUser *_Nullable user) { [weakSelf log:[NSString stringWithFormat: @"Auth State Did Change Listener #%lu was invoked on user '%@'.", (unsigned long)index, user.uid]]; @@ -1310,7 +1315,7 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { } NSUInteger index = _authStateDidChangeListeners.count - 1; FIRAuthStateDidChangeListenerHandle handle = _authStateDidChangeListeners.lastObject; - [[FIRAuth auth] removeAuthStateDidChangeListener:handle]; + [[AppManager auth] removeAuthStateDidChangeListener:handle]; [_authStateDidChangeListeners removeObject:handle]; NSString *logString = [NSString stringWithFormat:@"Auth State Did Change Listener #%lu was removed.", @@ -1327,8 +1332,8 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { [self log:[NSString stringWithFormat:@"ID Token Did Change Listener #%lu was added.", (unsigned long)index]]; FIRIDTokenDidChangeListenerHandle handle = - [[FIRAuth auth] addIDTokenDidChangeListener:^(FIRAuth *_Nonnull auth, - FIRUser *_Nullable user) { + [[AppManager auth] addIDTokenDidChangeListener:^(FIRAuth *_Nonnull auth, + FIRUser *_Nullable user) { [weakSelf log:[NSString stringWithFormat: @"ID Token Did Change Listener #%lu was invoked on user '%@'.", (unsigned long)index, user.uid]]; @@ -1346,7 +1351,7 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { } NSUInteger index = _IDTokenDidChangeListeners.count - 1; FIRIDTokenDidChangeListenerHandle handle = _IDTokenDidChangeListeners.lastObject; - [[FIRAuth auth] removeIDTokenDidChangeListener:handle]; + [[AppManager auth] removeIDTokenDidChangeListener:handle]; [_IDTokenDidChangeListeners removeObject:handle]; NSString *logString = [NSString stringWithFormat:@"ID Token Did Change Listener #%lu was removed.", @@ -1420,7 +1425,7 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { */ - (void)presentUserInfo { UserInfoViewController *userInfoViewController = - [[UserInfoViewController alloc] initWithUser:[FIRAuth auth].currentUser]; + [[UserInfoViewController alloc] initWithUser:[AppManager auth].currentUser]; [self presentViewController:userInfoViewController animated:YES completion:nil]; } @@ -1480,8 +1485,8 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { [FIREmailAuthProvider credentialWithEmail:email password:password]; [self showSpinner:^{ - [[FIRAuth auth] signInWithCredential:credential - completion:^(FIRUser *_Nullable user, NSError *_Nullable error) { + [[AppManager auth] signInWithCredential:credential + completion:^(FIRUser *_Nullable user, NSError *_Nullable error) { [self hideSpinner:^{ if (error) { [self logFailure:@"sign-in with Email/Password failed" error:error]; @@ -1504,9 +1509,9 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { - (void)signUpNewEmail:(NSString *)email password:(NSString *)password callback:(nullable FIRAuthResultCallback)callback { - [[FIRAuth auth] createUserWithEmail:email - password:password - completion:^(FIRUser *_Nullable user, NSError *_Nullable error) { + [[AppManager auth] createUserWithEmail:email + password:password + completion:^(FIRUser *_Nullable user, NSError *_Nullable error) { if (error) { [self logFailure:@"sign-up with Email/Password failed" error:error]; if (callback) { @@ -1546,7 +1551,7 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { - (void)signOut { [[AuthProviders google] signOut]; [[AuthProviders facebook] signOut]; - [[FIRAuth auth] signOut:NULL]; + [[AppManager auth] signOut:NULL]; } /** @fn deleteAccount @@ -1673,7 +1678,7 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { @param retrieveData Defines if additional provider data should be read. */ - (void)signinWithProvider:(id<AuthProvider>)authProvider retrieveData:(BOOL)retrieveData { - FIRAuth *auth = [FIRAuth auth]; + FIRAuth *auth = [AppManager auth]; if (!auth) { return; } @@ -1965,9 +1970,9 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { } [self showSpinner:^{ - [[FIRAuth auth] fetchProvidersForEmail:userInput - completion:^(NSArray<NSString *> *_Nullable providers, - NSError *_Nullable error) { + [[AppManager auth] fetchProvidersForEmail:userInput + completion:^(NSArray<NSString *> *_Nullable providers, + NSError *_Nullable error) { if (error) { [self logFailure:@"get providers for email failed" error:error]; } else { @@ -2015,7 +2020,7 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { return; } [self showSpinner:^{ - [[FIRAuth auth] sendPasswordResetWithEmail:userInput completion:^(NSError *_Nullable error) { + [[AppManager auth] sendPasswordResetWithEmail:userInput completion:^(NSError *_Nullable error) { [self hideSpinner:^{ if (error) { [self logFailure:@"request password reset failed" error:error]; @@ -2045,9 +2050,9 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { actionCodeSettings.URL = [NSURL URLWithString:KCONTINUE_URL]; actionCodeSettings.handleCodeInApp = YES; - [[FIRAuth auth] sendPasswordResetWithEmail:userInput - actionCodeSettings:actionCodeSettings - completion:^(NSError *_Nullable error) { + [[AppManager auth] sendPasswordResetWithEmail:userInput + actionCodeSettings:actionCodeSettings + completion:^(NSError *_Nullable error) { [self hideSpinner:^{ if (error) { [self logFailure:@"request password reset failed" error:error]; @@ -2080,9 +2085,9 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { } [self showSpinner:^{ - [[FIRAuth auth] confirmPasswordResetWithCode:code - newPassword:userInput - completion:^(NSError *_Nullable error) { + [[AppManager auth] confirmPasswordResetWithCode:code + newPassword:userInput + completion:^(NSError *_Nullable error) { [self hideSpinner:^{ if (error) { [self logFailure:@"Password reset failed" error:error]; @@ -2108,8 +2113,8 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { return; } [self showSpinner:^{ - [[FIRAuth auth] checkActionCode:userInput completion:^(FIRActionCodeInfo *_Nullable info, - NSError *_Nullable error) { + [[AppManager auth] checkActionCode:userInput completion:^(FIRActionCodeInfo *_Nullable info, + NSError *_Nullable error) { [self hideSpinner:^{ if (error) { [self logFailure:@"Check action code failed" error:error]; @@ -2139,7 +2144,7 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { } [self showSpinner:^{ - [[FIRAuth auth] applyActionCode:userInput completion:^(NSError *_Nullable error) { + [[AppManager auth] applyActionCode:userInput completion:^(NSError *_Nullable error) { [self hideSpinner:^{ if (error) { [self logFailure:@"Apply action code failed" error:error]; @@ -2164,8 +2169,8 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { return; } [self showSpinner:^{ - [[FIRAuth auth] verifyPasswordResetCode:userInput completion:^(NSString *_Nullable email, - NSError *_Nullable error) { + [[AppManager auth] verifyPasswordResetCode:userInput completion:^(NSString *_Nullable email, + NSError *_Nullable error) { [self hideSpinner:^{ if (error) { [self logFailure:@"Verify password reset code failed" error:error]; @@ -2267,9 +2272,9 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { } [self showSpinner:^{ - [[FIRAuth auth] createUserWithEmail:email - password:password - completion:^(FIRUser *_Nullable user, NSError *_Nullable error) { + [[AppManager auth] createUserWithEmail:email + password:password + completion:^(FIRUser *_Nullable user, NSError *_Nullable error) { if (error) { [self logFailure:@"create user failed" error:error]; } else { @@ -2295,9 +2300,9 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { return; } [self showSpinner:^{ - [[FIRPhoneAuthProvider provider] verifyPhoneNumber:phoneNumber - completion:^(NSString *_Nullable verificationID, - NSError *_Nullable error) { + [[AppManager phoneAuthProvider] verifyPhoneNumber:phoneNumber + completion:^(NSString *_Nullable verificationID, + NSError *_Nullable error) { [self hideSpinner:^{ if (error) { [self logFailure:@"failed to send verification code" error:error]; @@ -2315,11 +2320,11 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { } [self showSpinner:^{ FIRAuthCredential *credential = - [[FIRPhoneAuthProvider provider] credentialWithVerificationID:verificationID - verificationCode:verificationCode]; - [[FIRAuth auth] signInWithCredential:credential - completion:^(FIRUser *_Nullable user, - NSError *_Nullable error) { + [[AppManager phoneAuthProvider] credentialWithVerificationID:verificationID + verificationCode:verificationCode]; + [[AppManager auth] signInWithCredential:credential + completion:^(FIRUser *_Nullable user, + NSError *_Nullable error) { [self hideSpinner:^{ if (error) { [self logFailure:@"failed to verify phone number" error:error]; @@ -2347,9 +2352,9 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { return; } [self showSpinner:^{ - [[FIRPhoneAuthProvider provider] verifyPhoneNumber:phoneNumber - completion:^(NSString *_Nullable verificationID, - NSError *_Nullable error) { + [[AppManager phoneAuthProvider] verifyPhoneNumber:phoneNumber + completion:^(NSString *_Nullable verificationID, + NSError *_Nullable error) { if (error) { [self logFailure:@"failed to send verification code" error:error]; [self showMessagePrompt:error.localizedDescription]; @@ -2366,8 +2371,8 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { } [self showSpinner:^{ FIRPhoneAuthCredential *credential = - [[FIRPhoneAuthProvider provider] credentialWithVerificationID:verificationID - verificationCode:verificationCode]; + [[AppManager phoneAuthProvider] credentialWithVerificationID:verificationID + verificationCode:verificationCode]; [[self user] updatePhoneNumberCredential:credential completion:^(NSError *_Nullable error) { if (error) { @@ -2398,9 +2403,9 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { return; } [self showSpinner:^{ - [[FIRPhoneAuthProvider provider] verifyPhoneNumber:phoneNumber - completion:^(NSString *_Nullable verificationID, - NSError *_Nullable error) { + [[AppManager phoneAuthProvider] verifyPhoneNumber:phoneNumber + completion:^(NSString *_Nullable verificationID, + NSError *_Nullable error) { [self hideSpinner:^{ if (error) { [self logFailure:@"failed to send verification code" error:error]; @@ -2418,8 +2423,8 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { } [self showSpinner:^{ FIRPhoneAuthCredential *credential = - [[FIRPhoneAuthProvider provider] credentialWithVerificationID:verificationID - verificationCode:verificationCode]; + [[AppManager phoneAuthProvider] credentialWithVerificationID:verificationID + verificationCode:verificationCode]; [[self user] linkWithCredential:credential completion:^(FIRUser *_Nullable user, NSError *_Nullable error) { @@ -2438,9 +2443,9 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { [self showSpinner:^{ FIRPhoneAuthCredential *credential = error.userInfo[FIRAuthUpdatedCredentialKey]; - [[FIRAuth auth] signInWithCredential:credential - completion:^(FIRUser *_Nullable user, - NSError *_Nullable error) { + [[AppManager auth] signInWithCredential:credential + completion:^(FIRUser *_Nullable user, + NSError *_Nullable error) { [self hideSpinner:^{ if (error) { [self logFailure:@"failed to verify phone number" error:error]; @@ -2473,8 +2478,8 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { @brief Signs in as an anonymous user. */ - (void)signInAnonymously { - [[FIRAuth auth] signInAnonymouslyWithCompletion:^(FIRUser *_Nullable user, - NSError *_Nullable error) { + [[AppManager auth] signInAnonymouslyWithCompletion:^(FIRUser *_Nullable user, + NSError *_Nullable error) { if (error) { [self logFailure:@"sign-in anonymously failed" error:error]; } else { @@ -2497,8 +2502,8 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { FIRAuthCredential *credential = [FIROAuthProvider credentialWithProviderID:FIRGitHubAuthProviderID accessToken:accessToken]; if (credential) { - [[FIRAuth auth] signInWithCredential:credential completion:^(FIRUser *_Nullable user, - NSError *_Nullable error) { + [[AppManager auth] signInWithCredential:credential completion:^(FIRUser *_Nullable user, + NSError *_Nullable error) { if (error) { [self logFailure:@"sign-in with provider failed" error:error]; } else { @@ -2568,7 +2573,7 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { user in memory" setting. */ - (FIRUser *)user { - return _useUserInMemory ? _userInMemory : [FIRAuth auth].currentUser; + return _useUserInMemory ? _userInMemory : [AppManager auth].currentUser; } /** @fn showTypicalUIForUserUpdateResultsWithTitle:error: @@ -2623,8 +2628,8 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { } - (void)doSignInWithCustomToken:(NSString *_Nullable)userEnteredTokenText { - [[FIRAuth auth] signInWithCustomToken:userEnteredTokenText - completion:^(FIRUser *_Nullable user, NSError *_Nullable error) { + [[AppManager auth] signInWithCustomToken:userEnteredTokenText + completion:^(FIRUser *_Nullable user, NSError *_Nullable error) { if (error) { [self logFailure:@"sign-in with custom token failed" error:error]; [self showMessagePromptWithTitle:kSignInErrorAlertTitle @@ -2642,7 +2647,7 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) { } - (void)updateUserInfo { - [_userInfoTableViewCell updateContentsWithUser:[FIRAuth auth].currentUser]; + [_userInfoTableViewCell updateContentsWithUser:[AppManager auth].currentUser]; [_userInMemoryInfoTableViewCell updateContentsWithUser:_userInMemory]; } diff --git a/AuthSamples/Sample/SettingsViewController.m b/AuthSamples/Sample/SettingsViewController.m index f0458bb..df30899 100644 --- a/AuthSamples/Sample/SettingsViewController.m +++ b/AuthSamples/Sample/SettingsViewController.m @@ -18,22 +18,17 @@ #import <objc/runtime.h> -#import "FIRApp.h" +#import "AppManager.h" #import "FIRAuth_Internal.h" #import "FIRAuthAPNSToken.h" #import "FIRAuthAPNSTokenManager.h" #import "FIRAuthAppCredential.h" #import "FIRAuthAppCredentialManager.h" -#import "FIROptions.h" #import "FirebaseAuth.h" +#import "FirebaseCore.h" #import "StaticContentTableViewManager.h" #import "UIViewController+Alerts.h" -// Declares a private method of FIRInstanceID to work around a bug. -@interface FIRInstanceID : NSObject -+ (void)notifyTokenRefresh; -@end - /** @var kIdentityToolkitRequestClassName @brief The class name of Identity Toolkit requests. */ @@ -166,13 +161,6 @@ static NSString *truncatedString(NSString *string, NSUInteger length) { value:versionString( FirebaseAuthVersionString, FirebaseAuthVersionNumber)], ]], - [StaticContentTableViewSection sectionWithTitle:@"Client Identity" cells:@[ - [StaticContentTableViewCell cellWithTitle:@"Project" - value:[self currentProjectID] - action:^{ - [weakSelf toggleClientProject]; - }], - ]], [StaticContentTableViewSection sectionWithTitle:@"API Hosts" cells:@[ [StaticContentTableViewCell cellWithTitle:@"Identity Toolkit" value:APIHost(kIdentityToolkitRequestClassName) @@ -185,6 +173,23 @@ static NSString *truncatedString(NSString *string, NSUInteger length) { [weakSelf toggleAPIHostWithRequestClassName:kSecureTokenRequestClassName]; }], ]], + [StaticContentTableViewSection sectionWithTitle:@"Firebase Apps" cells:@[ + [StaticContentTableViewCell cellWithTitle:@"Active App" + value:[self activeAppDescription] + action:^{ + [weakSelf toggleActiveApp]; + }], + [StaticContentTableViewCell cellWithTitle:@"Default App" + value:[self projectIDForAppAtIndex:0] + action:^{ + [weakSelf toggleProjectForAppAtIndex:0]; + }], + [StaticContentTableViewCell cellWithTitle:@"Other App" + value:[self projectIDForAppAtIndex:1] + action:^{ + [weakSelf toggleProjectForAppAtIndex:1]; + }], + ]], [StaticContentTableViewSection sectionWithTitle:@"Phone Auth" cells:@[ [StaticContentTableViewCell cellWithTitle:@"APNs Token" value:[self APNSTokenString] @@ -196,13 +201,15 @@ static NSString *truncatedString(NSString *string, NSUInteger length) { action:^{ [weakSelf clearAppCredential]; }], + ]], + [StaticContentTableViewSection sectionWithTitle:@"Language" cells:@[ [StaticContentTableViewCell cellWithTitle:@"Auth Language" - value:[FIRAuth auth].languageCode ?: @"[none]" + value:[AppManager auth].languageCode ?: @"[none]" action:^{ [weakSelf showLanguageInput]; }], [StaticContentTableViewCell cellWithTitle:@"Use App language" action:^{ - [[FIRAuth auth] useAppLanguage]; + [[AppManager auth] useAppLanguage]; [weakSelf loadTableView]; }], ]], @@ -221,49 +228,72 @@ static NSString *truncatedString(NSString *string, NSUInteger length) { [self loadTableView]; } -/** @fn currentProjectID - @brief Returns the the current Firebase project ID. +/** @fn activeAppDescription + @brief Returns the description for the currently active Firebase app. + */ +- (NSString *)activeAppDescription { + return [AppManager sharedInstance].active == 0 ? @"[Default]" : @"[Other]"; +} + +/** @fn toggleActiveApp + @brief Toggles the active Firebase app for the rest of the application. */ -- (NSString *)currentProjectID { - NSString *APIKey = [FIRApp defaultApp].options.APIKey; +- (void)toggleActiveApp { + AppManager *apps = [AppManager sharedInstance]; + // This changes the FIRAuth instance returned from `[AppManager auth]` to be one that is + // associated with a different `FIRApp` instance. The sample app uses `[AppManager auth]` + // instead of `[FIRAuth auth]` almost everywhere. Thus, this statement switches between default + // and non-default `FIRApp` instances for the sample app to test against. + apps.active = (apps.active + 1) % apps.count; + [self loadTableView]; +} + +/** @fn projectIDForAppAtIndex: + @brief Returns the Firebase project ID for the Firebase app at the given index. + @param index The index for the app in the app manager. + @return The ID of the project. + */ +- (NSString *)projectIDForAppAtIndex:(int)index { + NSString *APIKey = [[AppManager sharedInstance] appAtIndex:index].options.APIKey; for (FIROptions *options in gFirebaseAppOptions) { if ([options.APIKey isEqualToString:APIKey]) { return options.projectID; } } - return nil; + return @"[none]"; } -/** @fn toggleClientProject - @brief Toggles the Firebase/Google project this client presents by recreating the default +/** @fn toggleProjectForAppAtIndex: + @brief Toggles the Firebase project for the Firebase app at the given index by recreating the FIRApp instance with different options. + @param index The index for the app to be recreated in the app manager. */ -- (void)toggleClientProject { - NSString *APIKey = [FIRApp defaultApp].options.APIKey; - for (NSUInteger i = 0 ; i < gFirebaseAppOptions.count; i++) { - FIROptions *options = gFirebaseAppOptions[i]; +- (void)toggleProjectForAppAtIndex:(int)index { + NSString *APIKey = [[AppManager sharedInstance] appAtIndex:index].options.APIKey; + int optionIndex; + for (optionIndex = 0; optionIndex < gFirebaseAppOptions.count; optionIndex++) { + FIROptions *options = gFirebaseAppOptions[optionIndex]; if ([options.APIKey isEqualToString:APIKey]) { - __weak typeof(self) weakSelf = self; - [[FIRApp defaultApp] deleteApp:^(BOOL success) { - if (success) { - [FIRInstanceID notifyTokenRefresh]; // b/28967043 - dispatch_async(dispatch_get_main_queue(), ^() { - FIROptions *options = gFirebaseAppOptions[(i + 1) % gFirebaseAppOptions.count]; - [FIRApp configureWithOptions:options]; - [weakSelf loadTableView]; - }); - } - }]; - return; + break; } } + // For non-default apps, `nil` is considered the next option after the last options in the array. + int useNil = index > 0; + optionIndex = (optionIndex + 1 + useNil) % (gFirebaseAppOptions.count + useNil) - useNil; + FIROptions *options = optionIndex >= 0 ? gFirebaseAppOptions[optionIndex] : nil; + __weak typeof(self) weakSelf = self; + [[AppManager sharedInstance] recreateAppAtIndex:index withOptions:options completion:^() { + dispatch_async(dispatch_get_main_queue(), ^() { + [weakSelf loadTableView]; + }); + }]; } /** @fn APNSTokenString @brief Returns a string representing APNS token. */ - (NSString *)APNSTokenString { - FIRAuthAPNSToken *token = [FIRAuth auth].tokenManager.token; + FIRAuthAPNSToken *token = [AppManager auth].tokenManager.token; if (!token) { return @""; } @@ -276,7 +306,7 @@ static NSString *truncatedString(NSString *string, NSUInteger length) { @brief Clears the saved app credential. */ - (void)clearAPNSToken { - FIRAuthAPNSToken *token = [FIRAuth auth].tokenManager.token; + FIRAuthAPNSToken *token = [AppManager auth].tokenManager.token; if (!token) { return; } @@ -288,7 +318,7 @@ static NSString *truncatedString(NSString *string, NSUInteger length) { showCancelButton:YES completion:^(BOOL userPressedOK, NSString *_Nullable userInput) { if (userPressedOK) { - [FIRAuth auth].tokenManager.token = nil; + [AppManager auth].tokenManager.token = nil; [self loadTableView]; } }]; @@ -298,7 +328,7 @@ static NSString *truncatedString(NSString *string, NSUInteger length) { @brief Returns a string representing app credential. */ - (NSString *)appCredentialString { - FIRAuthAppCredential *credential = [FIRAuth auth].appCredentialManager.credential; + FIRAuthAppCredential *credential = [AppManager auth].appCredentialManager.credential; if (!credential) { return @""; } @@ -311,7 +341,7 @@ static NSString *truncatedString(NSString *string, NSUInteger length) { @brief Clears the saved app credential. */ - (void)clearAppCredential { - FIRAuthAppCredential *credential = [FIRAuth auth].appCredentialManager.credential; + FIRAuthAppCredential *credential = [AppManager auth].appCredentialManager.credential; if (!credential) { return; } @@ -322,7 +352,7 @@ static NSString *truncatedString(NSString *string, NSUInteger length) { showCancelButton:YES completion:^(BOOL userPressedOK, NSString *_Nullable userInput) { if (userPressedOK) { - [[FIRAuth auth].appCredentialManager clearCredential]; + [[AppManager auth].appCredentialManager clearCredential]; [self loadTableView]; } }]; @@ -337,7 +367,7 @@ static NSString *truncatedString(NSString *string, NSUInteger length) { if (!userPressedOK) { return; } - [FIRAuth auth].languageCode = languageCode.length ? languageCode : nil; + [AppManager auth].languageCode = languageCode.length ? languageCode : nil; [self loadTableView]; }]; } diff --git a/AuthSamples/Samples.xcodeproj/project.pbxproj b/AuthSamples/Samples.xcodeproj/project.pbxproj index 3b1c2d8..30738ca 100644 --- a/AuthSamples/Samples.xcodeproj/project.pbxproj +++ b/AuthSamples/Samples.xcodeproj/project.pbxproj @@ -32,6 +32,7 @@ BD555A1DCF4E889DC3338248 /* Pods_FirebaseAuthUnitTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4FFAD3F37BC4D7CEF0CAD579 /* Pods_FirebaseAuthUnitTests.framework */; }; BE7B447C1EC2508300FA4C1B /* AuthCredentials.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE7B447A1EC2507800FA4C1B /* AuthCredentials.swift */; }; D99C31A11ED7A0ED00607534 /* GoogleService-Info_multi.plist in Resources */ = {isa = PBXBuildFile; fileRef = D99C31A01ED7A0ED00607534 /* GoogleService-Info_multi.plist */; }; + D9AC266E1F2ABBC5002B789B /* AppManager.m in Sources */ = {isa = PBXBuildFile; fileRef = D9AC266C1F2ABBC5002B789B /* AppManager.m */; }; D9AE2A641ED751C900DDAD18 /* FirebaseAuthApiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D9AE2A631ED751C900DDAD18 /* FirebaseAuthApiTests.m */; }; D9AE2A661ED757C400DDAD18 /* FirebaseAuthEarlGreyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D9AE2A651ED757C400DDAD18 /* FirebaseAuthEarlGreyTests.m */; }; DE5371B31EA7E89D000DA57F /* FIRAdditionalUserInfoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE5371831EA7E89D000DA57F /* FIRAdditionalUserInfoTests.m */; }; @@ -199,6 +200,8 @@ D90D8C411ED3B72B00C6BE87 /* AuthCredentials.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AuthCredentials.h; sourceTree = "<group>"; }; D930B7611EDF9AAD001265FD /* Sample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Sample.entitlements; sourceTree = "<group>"; }; D99C31A01ED7A0ED00607534 /* GoogleService-Info_multi.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info_multi.plist"; sourceTree = "<group>"; }; + D9AC266C1F2ABBC5002B789B /* AppManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppManager.m; sourceTree = "<group>"; }; + D9AC266D1F2ABBC5002B789B /* AppManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppManager.h; sourceTree = "<group>"; }; D9AE2A631ED751C900DDAD18 /* FirebaseAuthApiTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirebaseAuthApiTests.m; sourceTree = "<group>"; }; D9AE2A651ED757C400DDAD18 /* FirebaseAuthEarlGreyTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirebaseAuthEarlGreyTests.m; sourceTree = "<group>"; }; D9D6F0DE0BB3F49EF1B7CBB3 /* Pods-SwiftSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftSample.release.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftSample/Pods-SwiftSample.release.xcconfig"; sourceTree = "<group>"; }; @@ -418,6 +421,8 @@ children = ( 7EDFD35D1F0EA29200B29DC5 /* Localizable.strings */, D930B7611EDF9AAD001265FD /* Sample.entitlements */, + D9AC266D1F2ABBC5002B789B /* AppManager.h */, + D9AC266C1F2ABBC5002B789B /* AppManager.m */, DECEA5661EBBDFB400273585 /* AuthCredentials.h */, DECE049B1E9FEAE600164CA4 /* Application.plist */, DECE049C1E9FEAE600164CA4 /* ApplicationDelegate.h */, @@ -1191,6 +1196,7 @@ DECE04E51E9FEAE600164CA4 /* CustomTokenDataEntryViewController.m in Sources */, DECE04E41E9FEAE600164CA4 /* AuthProviders.m in Sources */, DECE04EF1E9FEAE600164CA4 /* SettingsViewController.m in Sources */, + D9AC266E1F2ABBC5002B789B /* AppManager.m in Sources */, DECE04E71E9FEAE600164CA4 /* GoogleAuthProvider.m in Sources */, DECE04F51E9FEAE600164CA4 /* UserInfoViewController.m in Sources */, DECE04EC1E9FEAE600164CA4 /* MainViewController.m in Sources */, |