diff --git a/packages/google_sign_in/google_sign_in/CHANGELOG.md b/packages/google_sign_in/google_sign_in/CHANGELOG.md
index cb4a65f42fa2..186a1d39a223 100644
--- a/packages/google_sign_in/google_sign_in/CHANGELOG.md
+++ b/packages/google_sign_in/google_sign_in/CHANGELOG.md
@@ -1,6 +1,7 @@
-## NEXT
+## 5.0.5
* Add iOS unit and UI integration test targets.
+* Add iOS unit test module map.
* Exclude arm64 simulators in example app.
## 5.0.4
diff --git a/packages/google_sign_in/google_sign_in/example/ios/Flutter/AppFrameworkInfo.plist b/packages/google_sign_in/google_sign_in/example/ios/Flutter/AppFrameworkInfo.plist
index 6c2de8086bcd..3a9c234f96d4 100644
--- a/packages/google_sign_in/google_sign_in/example/ios/Flutter/AppFrameworkInfo.plist
+++ b/packages/google_sign_in/google_sign_in/example/ios/Flutter/AppFrameworkInfo.plist
@@ -25,6 +25,6 @@
arm64
MinimumOSVersion
- 8.0
+ 9.0
diff --git a/packages/google_sign_in/google_sign_in/example/ios/Runner.xcodeproj/project.pbxproj b/packages/google_sign_in/google_sign_in/example/ios/Runner.xcodeproj/project.pbxproj
index 0c3cc430d23e..06857ed2bd59 100644
--- a/packages/google_sign_in/google_sign_in/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/packages/google_sign_in/google_sign_in/example/ios/Runner.xcodeproj/project.pbxproj
@@ -539,7 +539,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -589,7 +589,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
diff --git a/packages/google_sign_in/google_sign_in/example/ios/RunnerTests/GoogleSignInTests.m b/packages/google_sign_in/google_sign_in/example/ios/RunnerTests/GoogleSignInTests.m
index adbf61326c8d..6f8b821a5299 100644
--- a/packages/google_sign_in/google_sign_in/example/ios/RunnerTests/GoogleSignInTests.m
+++ b/packages/google_sign_in/google_sign_in/example/ios/RunnerTests/GoogleSignInTests.m
@@ -6,6 +6,7 @@
@import XCTest;
@import google_sign_in;
+@import google_sign_in.Test;
@import GoogleSignIn;
// OCMock library doesn't generate a valid modulemap.
@@ -16,7 +17,7 @@ @interface FLTGoogleSignInPluginTest : XCTestCase
@property(strong, nonatomic) NSObject *mockBinaryMessenger;
@property(strong, nonatomic) NSObject *mockPluginRegistrar;
@property(strong, nonatomic) FLTGoogleSignInPlugin *plugin;
-@property(strong, nonatomic) GIDSignIn *mockSharedInstance;
+@property(strong, nonatomic) id mockSignIn;
@end
@@ -26,39 +27,377 @@ - (void)setUp {
[super setUp];
self.mockBinaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
self.mockPluginRegistrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar));
- self.mockSharedInstance = [OCMockObject partialMockForObject:[GIDSignIn sharedInstance]];
+
+ id mockSignIn = OCMClassMock([GIDSignIn class]);
+ self.mockSignIn = mockSignIn;
+
OCMStub(self.mockPluginRegistrar.messenger).andReturn(self.mockBinaryMessenger);
- self.plugin = [[FLTGoogleSignInPlugin alloc] init];
+ self.plugin = [[FLTGoogleSignInPlugin alloc] initWithSignIn:mockSignIn];
[FLTGoogleSignInPlugin registerWithRegistrar:self.mockPluginRegistrar];
}
-- (void)tearDown {
- [((OCMockObject *)self.mockSharedInstance) stopMocking];
- [super tearDown];
+- (void)testUnimplementedMethod {
+ FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"bogus"
+ arguments:nil];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
+ [self.plugin handleMethodCall:methodCall
+ result:^(id result) {
+ XCTAssertEqualObjects(result, FlutterMethodNotImplemented);
+ [expectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:5.0 handler:nil];
+}
+
+- (void)testSignOut {
+ FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"signOut"
+ arguments:nil];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
+ [self.plugin handleMethodCall:methodCall
+ result:^(id result) {
+ XCTAssertNil(result);
+ [expectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:5.0 handler:nil];
+ OCMVerify([self.mockSignIn signOut]);
+}
+
+- (void)testDisconnect {
+ FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"disconnect"
+ arguments:nil];
+
+ [self.plugin handleMethodCall:methodCall
+ result:^(id result){
+ }];
+ OCMVerify([self.mockSignIn disconnect]);
+}
+
+- (void)testClearAuthCache {
+ FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"clearAuthCache"
+ arguments:nil];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
+ [self.plugin handleMethodCall:methodCall
+ result:^(id result) {
+ XCTAssertNil(result);
+ [expectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:5.0 handler:nil];
+}
+
+#pragma mark - Init
+
+- (void)testInitGamesSignInUnsupported {
+ FlutterMethodCall *methodCall =
+ [FlutterMethodCall methodCallWithMethodName:@"init"
+ arguments:@{@"signInOption" : @"SignInOption.games"}];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
+ [self.plugin handleMethodCall:methodCall
+ result:^(FlutterError *result) {
+ XCTAssertEqualObjects(result.code, @"unsupported-options");
+ [expectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:5.0 handler:nil];
+}
+
+- (void)testInitGoogleServiceInfoPlist {
+ FlutterMethodCall *methodCall = [FlutterMethodCall
+ methodCallWithMethodName:@"init"
+ arguments:@{@"scopes" : @[ @"mockScope1" ], @"hostedDomain" : @"example.com"}];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
+ [self.plugin handleMethodCall:methodCall
+ result:^(id result) {
+ XCTAssertNil(result);
+ [expectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:5.0 handler:nil];
+
+ id mockSignIn = self.mockSignIn;
+ OCMVerify([mockSignIn setScopes:@[ @"mockScope1" ]]);
+ OCMVerify([mockSignIn setHostedDomain:@"example.com"]);
+
+ // Set in example app GoogleService-Info.plist.
+ OCMVerify([mockSignIn
+ setClientID:@"479882132969-9i9aqik3jfjd7qhci1nqf0bm2g71rm1u.apps.googleusercontent.com"]);
+ OCMVerify([mockSignIn setServerClientID:@"YOUR_SERVER_CLIENT_ID"]);
+}
+
+- (void)testInitNullDomain {
+ FlutterMethodCall *methodCall =
+ [FlutterMethodCall methodCallWithMethodName:@"init"
+ arguments:@{@"hostedDomain" : [NSNull null]}];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
+ [self.plugin handleMethodCall:methodCall
+ result:^(id r) {
+ [expectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:5.0 handler:nil];
+ OCMVerify([self.mockSignIn setHostedDomain:nil]);
+}
+
+- (void)testInitDynamicClientId {
+ FlutterMethodCall *methodCall =
+ [FlutterMethodCall methodCallWithMethodName:@"init"
+ arguments:@{@"clientId" : @"mockClientId"}];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
+ [self.plugin handleMethodCall:methodCall
+ result:^(id r) {
+ [expectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:5.0 handler:nil];
+ OCMVerify([self.mockSignIn setClientID:@"mockClientId"]);
+}
+
+#pragma mark - Is signed in
+
+- (void)testIsNotSignedIn {
+ OCMStub([self.mockSignIn hasPreviousSignIn]).andReturn(NO);
+
+ FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"isSignedIn"
+ arguments:nil];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
+ [self.plugin handleMethodCall:methodCall
+ result:^(NSNumber *result) {
+ XCTAssertFalse(result.boolValue);
+ [expectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:5.0 handler:nil];
+}
+
+- (void)testIsSignedIn {
+ OCMStub([self.mockSignIn hasPreviousSignIn]).andReturn(YES);
+
+ FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"isSignedIn"
+ arguments:nil];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
+ [self.plugin handleMethodCall:methodCall
+ result:^(NSNumber *result) {
+ XCTAssertTrue(result.boolValue);
+ [expectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:5.0 handler:nil];
+}
+
+#pragma mark - Sign in silently
+
+- (void)testSignInSilently {
+ OCMExpect([self.mockSignIn restorePreviousSignIn]);
+
+ FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"signInSilently"
+ arguments:nil];
+
+ [self.plugin handleMethodCall:methodCall
+ result:^(id result){
+ }];
+ OCMVerifyAll(self.mockSignIn);
+}
+
+- (void)testSignInSilentlyFailsConcurrently {
+ FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"signInSilently"
+ arguments:nil];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
+
+ OCMExpect([self.mockSignIn restorePreviousSignIn]).andDo(^(NSInvocation *invocation) {
+ // Simulate calling the same method while the previous one is in flight.
+ [self.plugin handleMethodCall:methodCall
+ result:^(FlutterError *result) {
+ XCTAssertEqualObjects(result.code, @"concurrent-requests");
+ [expectation fulfill];
+ }];
+ });
+
+ [self.plugin handleMethodCall:methodCall
+ result:^(id result){
+ }];
+
+ [self waitForExpectationsWithTimeout:5.0 handler:nil];
+}
+
+#pragma mark - Sign in
+
+- (void)testSignIn {
+ FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"signIn"
+ arguments:nil];
+
+ [self.plugin handleMethodCall:methodCall
+ result:^(NSNumber *result){
+ }];
+
+ id mockSignIn = self.mockSignIn;
+ OCMVerify([mockSignIn
+ setPresentingViewController:[OCMArg isKindOfClass:[FlutterViewController class]]]);
+ OCMVerify([mockSignIn signIn]);
+}
+
+- (void)testSignInExecption {
+ FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"signIn"
+ arguments:nil];
+ OCMExpect([self.mockSignIn signIn])
+ .andThrow([NSException exceptionWithName:@"MockName" reason:@"MockReason" userInfo:nil]);
+
+ __block FlutterError *error;
+ XCTAssertThrows([self.plugin handleMethodCall:methodCall
+ result:^(FlutterError *result) {
+ error = result;
+ }]);
+
+ XCTAssertEqualObjects(error.code, @"google_sign_in");
+ XCTAssertEqualObjects(error.message, @"MockReason");
+ XCTAssertEqualObjects(error.details, @"MockName");
+}
+
+#pragma mark - Get tokens
+
+- (void)testGetTokens {
+ id mockUser = OCMClassMock([GIDGoogleUser class]);
+ OCMStub([self.mockSignIn currentUser]).andReturn(mockUser);
+
+ id mockAuthentication = OCMClassMock([GIDAuthentication class]);
+ OCMStub([mockAuthentication idToken]).andReturn(@"mockIdToken");
+ OCMStub([mockAuthentication accessToken]).andReturn(@"mockAccessToken");
+ [[mockAuthentication stub]
+ getTokensWithHandler:[OCMArg invokeBlockWithArgs:mockAuthentication, [NSNull null], nil]];
+ OCMStub([mockUser authentication]).andReturn(mockAuthentication);
+
+ FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"getTokens"
+ arguments:nil];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
+ [self.plugin handleMethodCall:methodCall
+ result:^(NSDictionary *result) {
+ XCTAssertEqualObjects(result[@"idToken"], @"mockIdToken");
+ XCTAssertEqualObjects(result[@"accessToken"], @"mockAccessToken");
+ [expectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:5.0 handler:nil];
}
+- (void)testGetTokensNoAuthKeychainError {
+ id mockUser = OCMClassMock([GIDGoogleUser class]);
+ OCMStub([self.mockSignIn currentUser]).andReturn(mockUser);
+
+ id mockAuthentication = OCMClassMock([GIDAuthentication class]);
+ NSError *error = [NSError errorWithDomain:kGIDSignInErrorDomain
+ code:kGIDSignInErrorCodeHasNoAuthInKeychain
+ userInfo:nil];
+ [[mockAuthentication stub]
+ getTokensWithHandler:[OCMArg invokeBlockWithArgs:[NSNull null], error, nil]];
+ OCMStub([mockUser authentication]).andReturn(mockAuthentication);
+
+ FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"getTokens"
+ arguments:nil];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
+ [self.plugin handleMethodCall:methodCall
+ result:^(FlutterError *result) {
+ XCTAssertEqualObjects(result.code, @"sign_in_required");
+ XCTAssertEqualObjects(result.message, kGIDSignInErrorDomain);
+ [expectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:5.0 handler:nil];
+}
+
+- (void)testGetTokensCancelledError {
+ id mockUser = OCMClassMock([GIDGoogleUser class]);
+ OCMStub([self.mockSignIn currentUser]).andReturn(mockUser);
+
+ id mockAuthentication = OCMClassMock([GIDAuthentication class]);
+ NSError *error = [NSError errorWithDomain:kGIDSignInErrorDomain
+ code:kGIDSignInErrorCodeCanceled
+ userInfo:nil];
+ [[mockAuthentication stub]
+ getTokensWithHandler:[OCMArg invokeBlockWithArgs:[NSNull null], error, nil]];
+ OCMStub([mockUser authentication]).andReturn(mockAuthentication);
+
+ FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"getTokens"
+ arguments:nil];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
+ [self.plugin handleMethodCall:methodCall
+ result:^(FlutterError *result) {
+ XCTAssertEqualObjects(result.code, @"sign_in_canceled");
+ XCTAssertEqualObjects(result.message, kGIDSignInErrorDomain);
+ [expectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:5.0 handler:nil];
+}
+
+- (void)testGetTokensURLError {
+ id mockUser = OCMClassMock([GIDGoogleUser class]);
+ OCMStub([self.mockSignIn currentUser]).andReturn(mockUser);
+
+ id mockAuthentication = OCMClassMock([GIDAuthentication class]);
+ NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorTimedOut userInfo:nil];
+ [[mockAuthentication stub]
+ getTokensWithHandler:[OCMArg invokeBlockWithArgs:[NSNull null], error, nil]];
+ OCMStub([mockUser authentication]).andReturn(mockAuthentication);
+
+ FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"getTokens"
+ arguments:nil];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
+ [self.plugin handleMethodCall:methodCall
+ result:^(FlutterError *result) {
+ XCTAssertEqualObjects(result.code, @"network_error");
+ XCTAssertEqualObjects(result.message, NSURLErrorDomain);
+ [expectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:5.0 handler:nil];
+}
+
+- (void)testGetTokensUnknownError {
+ id mockUser = OCMClassMock([GIDGoogleUser class]);
+ OCMStub([self.mockSignIn currentUser]).andReturn(mockUser);
+
+ id mockAuthentication = OCMClassMock([GIDAuthentication class]);
+ NSError *error = [NSError errorWithDomain:@"BogusDomain" code:42 userInfo:nil];
+ [[mockAuthentication stub]
+ getTokensWithHandler:[OCMArg invokeBlockWithArgs:[NSNull null], error, nil]];
+ OCMStub([mockUser authentication]).andReturn(mockAuthentication);
+
+ FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"getTokens"
+ arguments:nil];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
+ [self.plugin handleMethodCall:methodCall
+ result:^(FlutterError *result) {
+ XCTAssertEqualObjects(result.code, @"sign_in_failed");
+ XCTAssertEqualObjects(result.message, @"BogusDomain");
+ [expectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:5.0 handler:nil];
+}
+
+#pragma mark - Request scopes
+
- (void)testRequestScopesResultErrorIfNotSignedIn {
- OCMStub(self.mockSharedInstance.currentUser).andReturn(nil);
+ OCMStub([self.mockSignIn currentUser]).andReturn(nil);
FlutterMethodCall *methodCall =
[FlutterMethodCall methodCallWithMethodName:@"requestScopes"
arguments:@{@"scopes" : @[ @"mockScope1" ]}];
XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
- __block id result;
[self.plugin handleMethodCall:methodCall
- result:^(id r) {
+ result:^(FlutterError *result) {
+ XCTAssertEqualObjects(result.code, @"sign_in_required");
[expectation fulfill];
- result = r;
}];
- [self waitForExpectations:@[ expectation ] timeout:5];
- XCTAssertEqualObjects([((FlutterError *)result) code], @"sign_in_required");
+ [self waitForExpectationsWithTimeout:5.0 handler:nil];
}
- (void)testRequestScopesIfNoMissingScope {
// Mock Google Signin internal calls
- GIDGoogleUser *mockUser = OCMClassMock(GIDGoogleUser.class);
- OCMStub(self.mockSharedInstance.currentUser).andReturn(mockUser);
+ GIDGoogleUser *mockUser = OCMClassMock([GIDGoogleUser class]);
+ OCMStub([self.mockSignIn currentUser]).andReturn(mockUser);
NSArray *requestedScopes = @[ @"mockScope1" ];
OCMStub(mockUser.grantedScopes).andReturn(requestedScopes);
FlutterMethodCall *methodCall =
@@ -66,22 +405,22 @@ - (void)testRequestScopesIfNoMissingScope {
arguments:@{@"scopes" : requestedScopes}];
XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
- __block id result;
[self.plugin handleMethodCall:methodCall
- result:^(id r) {
+ result:^(NSNumber *result) {
+ XCTAssertTrue(result.boolValue);
[expectation fulfill];
- result = r;
}];
- [self waitForExpectations:@[ expectation ] timeout:5];
- XCTAssertTrue([result boolValue]);
+ [self waitForExpectationsWithTimeout:5.0 handler:nil];
}
- (void)testRequestScopesRequestsIfNotGranted {
// Mock Google Signin internal calls
- GIDGoogleUser *mockUser = OCMClassMock(GIDGoogleUser.class);
- OCMStub(self.mockSharedInstance.currentUser).andReturn(mockUser);
+ GIDGoogleUser *mockUser = OCMClassMock([GIDGoogleUser class]);
+ OCMStub([self.mockSignIn currentUser]).andReturn(mockUser);
NSArray *requestedScopes = @[ @"mockScope1" ];
OCMStub(mockUser.grantedScopes).andReturn(@[]);
+ id mockSignIn = self.mockSignIn;
+ OCMStub([mockSignIn scopes]).andReturn(@[]);
FlutterMethodCall *methodCall =
[FlutterMethodCall methodCallWithMethodName:@"requestScopes"
@@ -91,19 +430,19 @@ - (void)testRequestScopesRequestsIfNotGranted {
result:^(id r){
}];
- XCTAssertTrue([self.mockSharedInstance.scopes containsObject:@"mockScope1"]);
- OCMVerify([self.mockSharedInstance signIn]);
+ OCMVerify([mockSignIn setScopes:@[ @"mockScope1" ]]);
+ OCMVerify([mockSignIn signIn]);
}
- (void)testRequestScopesReturnsFalseIfNotGranted {
// Mock Google Signin internal calls
- GIDGoogleUser *mockUser = OCMClassMock(GIDGoogleUser.class);
- OCMStub(self.mockSharedInstance.currentUser).andReturn(mockUser);
+ GIDGoogleUser *mockUser = OCMClassMock([GIDGoogleUser class]);
+ OCMStub([self.mockSignIn currentUser]).andReturn(mockUser);
NSArray *requestedScopes = @[ @"mockScope1" ];
OCMStub(mockUser.grantedScopes).andReturn(@[]);
- OCMStub([self.mockSharedInstance signIn]).andDo(^(NSInvocation *invocation) {
- [((NSObject *)self.plugin) signIn:self.mockSharedInstance
+ OCMStub([self.mockSignIn signIn]).andDo(^(NSInvocation *invocation) {
+ [((NSObject *)self.plugin) signIn:self.mockSignIn
didSignInForUser:mockUser
withError:nil];
});
@@ -113,27 +452,25 @@ - (void)testRequestScopesReturnsFalseIfNotGranted {
arguments:@{@"scopes" : requestedScopes}];
XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns false"];
- __block id result;
[self.plugin handleMethodCall:methodCall
- result:^(id r) {
+ result:^(NSNumber *result) {
+ XCTAssertFalse(result.boolValue);
[expectation fulfill];
- result = r;
}];
- [self waitForExpectations:@[ expectation ] timeout:5];
- XCTAssertFalse([result boolValue]);
+ [self waitForExpectationsWithTimeout:5.0 handler:nil];
}
- (void)testRequestScopesReturnsTrueIfGranted {
// Mock Google Signin internal calls
- GIDGoogleUser *mockUser = OCMClassMock(GIDGoogleUser.class);
- OCMStub(self.mockSharedInstance.currentUser).andReturn(mockUser);
+ GIDGoogleUser *mockUser = OCMClassMock([GIDGoogleUser class]);
+ OCMStub([self.mockSignIn currentUser]).andReturn(mockUser);
NSArray *requestedScopes = @[ @"mockScope1" ];
NSMutableArray *availableScopes = [NSMutableArray new];
OCMStub(mockUser.grantedScopes).andReturn(availableScopes);
- OCMStub([self.mockSharedInstance signIn]).andDo(^(NSInvocation *invocation) {
+ OCMStub([self.mockSignIn signIn]).andDo(^(NSInvocation *invocation) {
[availableScopes addObject:@"mockScope1"];
- [((NSObject *)self.plugin) signIn:self.mockSharedInstance
+ [((NSObject *)self.plugin) signIn:self.mockSignIn
didSignInForUser:mockUser
withError:nil];
});
@@ -143,14 +480,12 @@ - (void)testRequestScopesReturnsTrueIfGranted {
arguments:@{@"scopes" : requestedScopes}];
XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
- __block id result;
[self.plugin handleMethodCall:methodCall
- result:^(id r) {
+ result:^(NSNumber *result) {
+ XCTAssertTrue(result.boolValue);
[expectation fulfill];
- result = r;
}];
- [self waitForExpectations:@[ expectation ] timeout:5];
- XCTAssertTrue([result boolValue]);
+ [self waitForExpectationsWithTimeout:5.0 handler:nil];
}
@end
diff --git a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m
index 578f64d5a41c..d13d64d2ba04 100644
--- a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m
+++ b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m
@@ -3,6 +3,8 @@
// found in the LICENSE file.
#import "FLTGoogleSignInPlugin.h"
+#import "FLTGoogleSignInPlugin_Test.h"
+
#import
// The key within `GoogleService-Info.plist` used to hold the application's
@@ -35,11 +37,15 @@
}
@interface FLTGoogleSignInPlugin ()
+@property(strong, readonly) GIDSignIn *signIn;
+
+// Redeclared as not a designated initializer.
+- (instancetype)init;
@end
@implementation FLTGoogleSignInPlugin {
FlutterResult _accountRequest;
- NSArray *_additionalScopesRequest;
+ NSArray *_additionalScopesRequest;
}
+ (void)registerWithRegistrar:(NSObject *)registrar {
@@ -52,9 +58,14 @@ + (void)registerWithRegistrar:(NSObject *)registrar {
}
- (instancetype)init {
+ return [self initWithSignIn:GIDSignIn.sharedInstance];
+}
+
+- (instancetype)initWithSignIn:(GIDSignIn *)signIn {
self = [super init];
if (self) {
- [GIDSignIn sharedInstance].delegate = self;
+ _signIn = signIn;
+ _signIn.delegate = self;
// On the iOS simulator, we get "Broken pipe" errors after sign-in for some
// unknown reason. We can avoid crashing the app by ignoring them.
@@ -76,22 +87,22 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
NSString *path = [[NSBundle mainBundle] pathForResource:@"GoogleService-Info"
ofType:@"plist"];
if (path) {
- NSMutableDictionary *plist = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
- BOOL hasDynamicClientId =
- [[call.arguments valueForKey:@"clientId"] isKindOfClass:[NSString class]];
+ NSMutableDictionary *plist =
+ [[NSMutableDictionary alloc] initWithContentsOfFile:path];
+ BOOL hasDynamicClientId = [call.arguments[@"clientId"] isKindOfClass:[NSString class]];
if (hasDynamicClientId) {
- [GIDSignIn sharedInstance].clientID = [call.arguments valueForKey:@"clientId"];
+ self.signIn.clientID = call.arguments[@"clientId"];
} else {
- [GIDSignIn sharedInstance].clientID = plist[kClientIdKey];
+ self.signIn.clientID = plist[kClientIdKey];
}
- [GIDSignIn sharedInstance].serverClientID = plist[kServerClientIdKey];
- [GIDSignIn sharedInstance].scopes = call.arguments[@"scopes"];
+ self.signIn.serverClientID = plist[kServerClientIdKey];
+ self.signIn.scopes = call.arguments[@"scopes"];
if (call.arguments[@"hostedDomain"] == [NSNull null]) {
- [GIDSignIn sharedInstance].hostedDomain = nil;
+ self.signIn.hostedDomain = nil;
} else {
- [GIDSignIn sharedInstance].hostedDomain = call.arguments[@"hostedDomain"];
+ self.signIn.hostedDomain = call.arguments[@"hostedDomain"];
}
result(nil);
} else {
@@ -102,23 +113,23 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
}
} else if ([call.method isEqualToString:@"signInSilently"]) {
if ([self setAccountRequest:result]) {
- [[GIDSignIn sharedInstance] restorePreviousSignIn];
+ [self.signIn restorePreviousSignIn];
}
} else if ([call.method isEqualToString:@"isSignedIn"]) {
- result(@([[GIDSignIn sharedInstance] hasPreviousSignIn]));
+ result(@([self.signIn hasPreviousSignIn]));
} else if ([call.method isEqualToString:@"signIn"]) {
- [GIDSignIn sharedInstance].presentingViewController = [self topViewController];
+ self.signIn.presentingViewController = [self topViewController];
if ([self setAccountRequest:result]) {
@try {
- [[GIDSignIn sharedInstance] signIn];
+ [self.signIn signIn];
} @catch (NSException *e) {
result([FlutterError errorWithCode:@"google_sign_in" message:e.reason details:e.name]);
[e raise];
}
}
} else if ([call.method isEqualToString:@"getTokens"]) {
- GIDGoogleUser *currentUser = [GIDSignIn sharedInstance].currentUser;
+ GIDGoogleUser *currentUser = self.signIn.currentUser;
GIDAuthentication *auth = currentUser.authentication;
[auth getTokensWithHandler:^void(GIDAuthentication *authentication, NSError *error) {
result(error != nil ? getFlutterError(error) : @{
@@ -127,18 +138,18 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
});
}];
} else if ([call.method isEqualToString:@"signOut"]) {
- [[GIDSignIn sharedInstance] signOut];
+ [self.signIn signOut];
result(nil);
} else if ([call.method isEqualToString:@"disconnect"]) {
if ([self setAccountRequest:result]) {
- [[GIDSignIn sharedInstance] disconnect];
+ [self.signIn disconnect];
}
} else if ([call.method isEqualToString:@"clearAuthCache"]) {
// There's nothing to be done here on iOS since the expired/invalid
// tokens are refreshed automatically by getTokensWithHandler.
result(nil);
} else if ([call.method isEqualToString:@"requestScopes"]) {
- GIDGoogleUser *user = [GIDSignIn sharedInstance].currentUser;
+ GIDGoogleUser *user = self.signIn.currentUser;
if (user == nil) {
result([FlutterError errorWithCode:@"sign_in_required"
message:@"No account to grant scopes."
@@ -146,9 +157,9 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
return;
}
- NSArray *currentScopes = [GIDSignIn sharedInstance].scopes;
- NSArray *scopes = call.arguments[@"scopes"];
- NSArray *missingScopes = [scopes
+ NSArray *currentScopes = self.signIn.scopes;
+ NSArray *scopes = call.arguments[@"scopes"];
+ NSArray *missingScopes = [scopes
filteredArrayUsingPredicate:[NSPredicate
predicateWithBlock:^BOOL(id scope, NSDictionary *bindings) {
return ![user.grantedScopes containsObject:scope];
@@ -161,12 +172,11 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
if ([self setAccountRequest:result]) {
_additionalScopesRequest = missingScopes;
- [GIDSignIn sharedInstance].scopes =
- [currentScopes arrayByAddingObjectsFromArray:missingScopes];
- [GIDSignIn sharedInstance].presentingViewController = [self topViewController];
- [GIDSignIn sharedInstance].loginHint = user.profile.email;
+ self.signIn.scopes = [currentScopes arrayByAddingObjectsFromArray:missingScopes];
+ self.signIn.presentingViewController = [self topViewController];
+ self.signIn.loginHint = user.profile.email;
@try {
- [[GIDSignIn sharedInstance] signIn];
+ [self.signIn signIn];
} @catch (NSException *e) {
result([FlutterError errorWithCode:@"request_scopes" message:e.reason details:e.name]);
}
@@ -187,8 +197,10 @@ - (BOOL)setAccountRequest:(FlutterResult)request {
return YES;
}
-- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options {
- return [[GIDSignIn sharedInstance] handleURL:url];
+- (BOOL)application:(UIApplication *)app
+ openURL:(NSURL *)url
+ options:(NSDictionary *)options {
+ return [self.signIn handleURL:url];
}
#pragma mark - protocol
@@ -251,7 +263,7 @@ - (void)signIn:(GIDSignIn *)signIn
#pragma mark - private methods
-- (void)respondWithAccount:(id)account error:(NSError *)error {
+- (void)respondWithAccount:(NSDictionary *)account error:(NSError *)error {
FlutterResult result = _accountRequest;
_accountRequest = nil;
result(error != nil ? getFlutterError(error) : account);
diff --git a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.modulemap b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.modulemap
new file mode 100644
index 000000000000..271f509e7fd7
--- /dev/null
+++ b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.modulemap
@@ -0,0 +1,10 @@
+framework module google_sign_in {
+ umbrella header "google_sign_in-umbrella.h"
+
+ export *
+ module * { export * }
+
+ explicit module Test {
+ header "FLTGoogleSignInPlugin_Test.h"
+ }
+}
diff --git a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin_Test.h b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin_Test.h
new file mode 100644
index 000000000000..8fa6cf348018
--- /dev/null
+++ b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin_Test.h
@@ -0,0 +1,17 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This header is available in the Test module. Import via "@import google_sign_in.Test;"
+
+#import
+
+@class GIDSignIn;
+
+/// Methods exposed for unit testing.
+@interface FLTGoogleSignInPlugin ()
+
+/// Inject @c GIDSignIn for testing.
+- (instancetype)initWithSignIn:(GIDSignIn *)signIn NS_DESIGNATED_INITIALIZER;
+
+@end
diff --git a/packages/google_sign_in/google_sign_in/ios/Classes/google_sign_in-umbrella.h b/packages/google_sign_in/google_sign_in/ios/Classes/google_sign_in-umbrella.h
new file mode 100644
index 000000000000..343c390f1782
--- /dev/null
+++ b/packages/google_sign_in/google_sign_in/ios/Classes/google_sign_in-umbrella.h
@@ -0,0 +1,9 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import
+#import
+
+FOUNDATION_EXPORT double google_sign_inVersionNumber;
+FOUNDATION_EXPORT const unsigned char google_sign_inVersionString[];
diff --git a/packages/google_sign_in/google_sign_in/ios/google_sign_in.podspec b/packages/google_sign_in/google_sign_in/ios/google_sign_in.podspec
index bf0b75f2957d..6b0741c65122 100644
--- a/packages/google_sign_in/google_sign_in/ios/google_sign_in.podspec
+++ b/packages/google_sign_in/google_sign_in/ios/google_sign_in.podspec
@@ -12,8 +12,9 @@ Enables Google Sign-In in Flutter apps.
s.license = { :type => 'BSD', :file => '../LICENSE' }
s.author = { 'Flutter Team' => 'flutter-dev@googlegroups.com' }
s.source = { :http => 'https://github.com/flutter/plugins/tree/master/packages/google_sign_in' }
- s.source_files = 'Classes/**/*'
+ s.source_files = 'Classes/**/*.{h,m}'
s.public_header_files = 'Classes/**/*.h'
+ s.module_map = 'Classes/FLTGoogleSignInPlugin.modulemap'
s.dependency 'Flutter'
s.dependency 'GoogleSignIn', '~> 5.0'
s.static_framework = true
diff --git a/packages/google_sign_in/google_sign_in/pubspec.yaml b/packages/google_sign_in/google_sign_in/pubspec.yaml
index a57f2197576d..14f7d8901301 100644
--- a/packages/google_sign_in/google_sign_in/pubspec.yaml
+++ b/packages/google_sign_in/google_sign_in/pubspec.yaml
@@ -3,7 +3,7 @@ description: Flutter plugin for Google Sign-In, a secure authentication system
for signing in with a Google account on Android and iOS.
repository: https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_sign_in%22
-version: 5.0.4
+version: 5.0.5
environment:
sdk: ">=2.12.0 <3.0.0"