@@ -72,12 +72,9 @@ - (instancetype)init;
7272@implementation FLTGoogleSignInPlugin
7373
7474+ (void )registerWithRegistrar : (NSObject <FlutterPluginRegistrar> *)registrar {
75- FlutterMethodChannel *channel =
76- [FlutterMethodChannel methodChannelWithName: @" plugins.flutter.io/google_sign_in_ios"
77- binaryMessenger: [registrar messenger ]];
7875 FLTGoogleSignInPlugin *instance = [[FLTGoogleSignInPlugin alloc ] init ];
7976 [registrar addApplicationDelegate: instance];
80- [ registrar addMethodCallDelegate: instance channel: channel] ;
77+ FSIGoogleSignInApiSetup ( registrar. messenger , instance) ;
8178}
8279
8380- (instancetype )init {
@@ -105,104 +102,122 @@ - (instancetype)initWithSignIn:(GIDSignIn *)signIn
105102
106103#pragma mark - <FlutterPlugin> protocol
107104
108- - (void )handleMethodCall : (FlutterMethodCall *)call result : (FlutterResult)result {
109- if ([call.method isEqualToString: @" init" ]) {
110- GIDConfiguration *configuration =
111- [self configurationWithClientIdArgument: call.arguments[@" clientId" ]
112- serverClientIdArgument: call.arguments[@" serverClientId" ]
113- hostedDomainArgument: call.arguments[@" hostedDomain" ]];
114- if (configuration != nil ) {
115- if ([call.arguments[@" scopes" ] isKindOfClass: [NSArray class ]]) {
116- self.requestedScopes = [NSSet setWithArray: call.arguments[@" scopes" ]];
117- }
118- self.configuration = configuration;
119- result (nil );
120- } else {
121- result ([FlutterError errorWithCode: @" missing-config"
105+ - (BOOL )application : (UIApplication *)app openURL : (NSURL *)url options : (NSDictionary *)options {
106+ return [self .signIn handleURL: url];
107+ }
108+
109+ #pragma mark - FSIGoogleSignInApi
110+
111+ - (void )initializeSignInWithParameters : (nonnull FSIInitParams *)params
112+ error : (FlutterError *_Nullable __autoreleasing *_Nonnull)error {
113+ GIDConfiguration *configuration = [self configurationWithClientIdArgument: params.clientId
114+ serverClientIdArgument: params.serverClientId
115+ hostedDomainArgument: params.hostedDomain];
116+ if (configuration != nil ) {
117+ self.requestedScopes = [NSSet setWithArray: params.scopes];
118+ self.configuration = configuration;
119+ } else {
120+ *error = [FlutterError errorWithCode: @" missing-config"
122121 message: @" GoogleService-Info.plist file not found and clientId "
123122 @" was not provided programmatically."
124- details: nil ]);
125- }
126- } else if ([call.method isEqualToString: @" signInSilently" ]) {
127- [self .signIn restorePreviousSignInWithCallback: ^(GIDGoogleUser *user, NSError *error) {
128- [self didSignInForUser: user result: result withError: error];
129- }];
130- } else if ([call.method isEqualToString: @" isSignedIn" ]) {
131- result (@([self .signIn hasPreviousSignIn ]));
132- } else if ([call.method isEqualToString: @" signIn" ]) {
133- @try {
134- GIDConfiguration *configuration = self.configuration
135- ?: [self configurationWithClientIdArgument: nil
136- serverClientIdArgument: nil
137- hostedDomainArgument: nil ];
138- [self .signIn signInWithConfiguration: configuration
139- presentingViewController: [self topViewController ]
140- hint: nil
141- additionalScopes: self .requestedScopes.allObjects
142- callback: ^(GIDGoogleUser *user, NSError *error) {
143- [self didSignInForUser: user result: result withError: error];
144- }];
145- } @catch (NSException *e) {
146- result ([FlutterError errorWithCode: @" google_sign_in" message: e.reason details: e.name]);
147- [e raise ];
148- }
149- } else if ([call.method isEqualToString: @" getTokens" ]) {
150- GIDGoogleUser *currentUser = self.signIn .currentUser ;
151- GIDAuthentication *auth = currentUser.authentication ;
152- [auth doWithFreshTokens: ^void (GIDAuthentication *authentication, NSError *error) {
153- result (error != nil ? getFlutterError (error) : @{
154- @" idToken" : authentication.idToken ,
155- @" accessToken" : authentication.accessToken ,
156- });
157- }];
158- } else if ([call.method isEqualToString: @" signOut" ]) {
159- [self .signIn signOut ];
160- result (nil );
161- } else if ([call.method isEqualToString: @" disconnect" ]) {
162- [self .signIn disconnectWithCallback: ^(NSError *error) {
163- [self respondWithAccount: @{} result: result error: nil ];
164- }];
165- } else if ([call.method isEqualToString: @" requestScopes" ]) {
166- id scopeArgument = call.arguments [@" scopes" ];
167- if ([scopeArgument isKindOfClass: [NSArray class ]]) {
168- self.requestedScopes = [self .requestedScopes setByAddingObjectsFromArray: scopeArgument];
169- }
170- NSSet <NSString *> *requestedScopes = self.requestedScopes ;
171-
172- @try {
173- [self .signIn addScopes: requestedScopes.allObjects
174- presentingViewController: [self topViewController ]
175- callback: ^(GIDGoogleUser *addedScopeUser, NSError *addedScopeError) {
176- if ([addedScopeError.domain isEqualToString: kGIDSignInErrorDomain ] &&
177- addedScopeError.code == kGIDSignInErrorCodeNoCurrentUser ) {
178- result ([FlutterError errorWithCode: @" sign_in_required"
179- message: @" No account to grant scopes."
180- details: nil ]);
181- } else if ([addedScopeError.domain
182- isEqualToString: kGIDSignInErrorDomain ] &&
183- addedScopeError.code ==
184- kGIDSignInErrorCodeScopesAlreadyGranted ) {
185- // Scopes already granted, report success.
186- result (@YES );
187- } else if (addedScopeUser == nil ) {
188- result (@NO );
189- } else {
190- NSSet <NSString *> *grantedScopes =
191- [NSSet setWithArray: addedScopeUser.grantedScopes];
192- BOOL granted = [requestedScopes isSubsetOfSet: grantedScopes];
193- result (@(granted));
194- }
195- }];
196- } @catch (NSException *e) {
197- result ([FlutterError errorWithCode: @" request_scopes" message: e.reason details: e.name]);
198- }
199- } else {
200- result (FlutterMethodNotImplemented);
123+ details: nil ];
201124 }
202125}
203126
204- - (BOOL )application : (UIApplication *)app openURL : (NSURL *)url options : (NSDictionary *)options {
205- return [self .signIn handleURL: url];
127+ - (void )signInSilentlyWithCompletion : (nonnull void (^)(FSIUserData *_Nullable,
128+ FlutterError *_Nullable))completion {
129+ [self .signIn restorePreviousSignInWithCallback: ^(GIDGoogleUser *user, NSError *error) {
130+ [self didSignInForUser: user withCompletion: completion error: error];
131+ }];
132+ }
133+
134+ - (nullable NSNumber *)isSignedInWithError :
135+ (FlutterError *_Nullable __autoreleasing *_Nonnull)error {
136+ return @([self .signIn hasPreviousSignIn ]);
137+ }
138+
139+ - (void )signInWithCompletion : (nonnull void (^)(FSIUserData *_Nullable,
140+ FlutterError *_Nullable))completion {
141+ @try {
142+ GIDConfiguration *configuration = self.configuration
143+ ?: [self configurationWithClientIdArgument: nil
144+ serverClientIdArgument: nil
145+ hostedDomainArgument: nil ];
146+ [self .signIn signInWithConfiguration: configuration
147+ presentingViewController: [self topViewController ]
148+ hint: nil
149+ additionalScopes: self .requestedScopes.allObjects
150+ callback: ^(GIDGoogleUser *user, NSError *error) {
151+ [self didSignInForUser: user
152+ withCompletion: completion
153+ error: error];
154+ }];
155+ } @catch (NSException *e) {
156+ completion (nil , [FlutterError errorWithCode: @" google_sign_in" message: e.reason details: e.name]);
157+ [e raise ];
158+ }
159+ }
160+
161+ - (void )getAccessTokenWithCompletion : (nonnull void (^)(FSITokenData *_Nullable,
162+ FlutterError *_Nullable))completion {
163+ GIDGoogleUser *currentUser = self.signIn .currentUser ;
164+ GIDAuthentication *auth = currentUser.authentication ;
165+ [auth doWithFreshTokens: ^void (GIDAuthentication *authentication, NSError *error) {
166+ if (error) {
167+ completion (nil , getFlutterError (error));
168+ } else {
169+ completion ([FSITokenData makeWithIdToken: authentication.idToken
170+ accessToken: authentication.accessToken],
171+ nil );
172+ }
173+ }];
174+ }
175+
176+ - (void )signOutWithError : (FlutterError *_Nullable *_Nonnull)error ;
177+ { [self .signIn signOut ]; }
178+
179+ - (void )disconnectWithCompletion : (nonnull void (^)(FlutterError *_Nullable))completion {
180+ [self .signIn disconnectWithCallback: ^(NSError *error) {
181+ // TODO(stuartmorgan): This preserves the pre-Pigeon-migration behavior, but it's unclear why
182+ // 'error' is being ignored here.
183+ completion (nil );
184+ }];
185+ }
186+
187+ - (void )requestScopes : (nonnull NSArray <NSString *> *)scopes
188+ completion : (nonnull void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion {
189+ self.requestedScopes = [self .requestedScopes setByAddingObjectsFromArray: scopes];
190+ NSSet <NSString *> *requestedScopes = self.requestedScopes ;
191+
192+ @try {
193+ [self .signIn addScopes: requestedScopes.allObjects
194+ presentingViewController: [self topViewController ]
195+ callback: ^(GIDGoogleUser *addedScopeUser, NSError *addedScopeError) {
196+ BOOL granted = NO ;
197+ FlutterError *error = nil ;
198+ if ([addedScopeError.domain isEqualToString: kGIDSignInErrorDomain ] &&
199+ addedScopeError.code == kGIDSignInErrorCodeNoCurrentUser ) {
200+ error = [FlutterError errorWithCode: @" sign_in_required"
201+ message: @" No account to grant scopes."
202+ details: nil ];
203+ } else if ([addedScopeError.domain
204+ isEqualToString: kGIDSignInErrorDomain ] &&
205+ addedScopeError.code ==
206+ kGIDSignInErrorCodeScopesAlreadyGranted ) {
207+ // Scopes already granted, report success.
208+ granted = YES ;
209+ } else if (addedScopeUser == nil ) {
210+ granted = NO ;
211+ } else {
212+ NSSet <NSString *> *grantedScopes =
213+ [NSSet setWithArray: addedScopeUser.grantedScopes];
214+ granted = [requestedScopes isSubsetOfSet: grantedScopes];
215+ }
216+ completion (error == nil ? @(granted) : nil , error);
217+ }];
218+ } @catch (NSException *e) {
219+ completion (nil , [FlutterError errorWithCode: @" request_scopes" message: e.reason details: e.name]);
220+ }
206221}
207222
208223#pragma mark - <GIDSignInUIDelegate> protocol
@@ -250,35 +265,27 @@ - (GIDConfiguration *)configurationWithClientIdArgument:(id)clientIDArg
250265}
251266
252267- (void )didSignInForUser : (GIDGoogleUser *)user
253- result : (FlutterResult)result
254- withError : (NSError *)error {
268+ withCompletion : (nonnull void (^)(FSIUserData *_Nullable,
269+ FlutterError *_Nullable))completion
270+ error:(NSError *)error {
255271 if (error != nil ) {
256272 // Forward all errors and let Dart side decide how to handle.
257- [ self respondWithAccount: nil result: result error: error] ;
273+ completion ( nil , getFlutterError ( error)) ;
258274 } else {
259275 NSURL *photoUrl;
260276 if (user.profile .hasImage ) {
261277 // Placeholder that will be replaced by on the Dart side based on screen size.
262278 photoUrl = [user.profile imageURLWithDimension: 1337 ];
263279 }
264- [self respondWithAccount: @{
265- @" displayName" : user.profile .name ?: [NSNull null ],
266- @" email" : user.profile .email ?: [NSNull null ],
267- @" id" : user.userID ?: [NSNull null ],
268- @" photoUrl" : [photoUrl absoluteString ] ?: [NSNull null ],
269- @" serverAuthCode" : user.serverAuthCode ?: [NSNull null ]
270- }
271- result: result
272- error: nil ];
280+ completion ([FSIUserData makeWithDisplayName: user.profile.name
281+ email: user.profile.email
282+ userId: user.userID
283+ photoUrl: [photoUrl absoluteString ]
284+ serverAuthCode: user.serverAuthCode],
285+ nil );
273286 }
274287}
275288
276- - (void )respondWithAccount : (NSDictionary <NSString *, id> *)account
277- result : (FlutterResult)result
278- error : (NSError *)error {
279- result (error != nil ? getFlutterError (error) : account);
280- }
281-
282289- (UIViewController *)topViewController {
283290#pragma clang diagnostic push
284291#pragma clang diagnostic ignored "-Wdeprecated-declarations"
@@ -316,4 +323,5 @@ - (UIViewController *)topViewControllerFromViewController:(UIViewController *)vi
316323 }
317324 return viewController;
318325}
326+
319327@end
0 commit comments