@@ -72,12 +72,9 @@ - (instancetype)init;
72
72
@implementation FLTGoogleSignInPlugin
73
73
74
74
+ (void )registerWithRegistrar : (NSObject <FlutterPluginRegistrar> *)registrar {
75
- FlutterMethodChannel *channel =
76
- [FlutterMethodChannel methodChannelWithName: @" plugins.flutter.io/google_sign_in_ios"
77
- binaryMessenger: [registrar messenger ]];
78
75
FLTGoogleSignInPlugin *instance = [[FLTGoogleSignInPlugin alloc ] init ];
79
76
[registrar addApplicationDelegate: instance];
80
- [ registrar addMethodCallDelegate: instance channel: channel] ;
77
+ FSIGoogleSignInApiSetup ( registrar. messenger , instance) ;
81
78
}
82
79
83
80
- (instancetype )init {
@@ -105,104 +102,122 @@ - (instancetype)initWithSignIn:(GIDSignIn *)signIn
105
102
106
103
#pragma mark - <FlutterPlugin> protocol
107
104
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"
122
121
message: @" GoogleService-Info.plist file not found and clientId "
123
122
@" 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 ];
201
124
}
202
125
}
203
126
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
+ }
206
221
}
207
222
208
223
#pragma mark - <GIDSignInUIDelegate> protocol
@@ -250,35 +265,27 @@ - (GIDConfiguration *)configurationWithClientIdArgument:(id)clientIDArg
250
265
}
251
266
252
267
- (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 {
255
271
if (error != nil ) {
256
272
// Forward all errors and let Dart side decide how to handle.
257
- [ self respondWithAccount: nil result: result error: error] ;
273
+ completion ( nil , getFlutterError ( error)) ;
258
274
} else {
259
275
NSURL *photoUrl;
260
276
if (user.profile .hasImage ) {
261
277
// Placeholder that will be replaced by on the Dart side based on screen size.
262
278
photoUrl = [user.profile imageURLWithDimension: 1337 ];
263
279
}
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 );
273
286
}
274
287
}
275
288
276
- - (void )respondWithAccount : (NSDictionary <NSString *, id> *)account
277
- result : (FlutterResult)result
278
- error : (NSError *)error {
279
- result (error != nil ? getFlutterError (error) : account);
280
- }
281
-
282
289
- (UIViewController *)topViewController {
283
290
#pragma clang diagnostic push
284
291
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
@@ -316,4 +323,5 @@ - (UIViewController *)topViewControllerFromViewController:(UIViewController *)vi
316
323
}
317
324
return viewController;
318
325
}
326
+
319
327
@end
0 commit comments