diff --git a/Firebase/Auth/Source/Auth/FIRAuth.m b/Firebase/Auth/Source/Auth/FIRAuth.m index adbb5f8377a..ed9f5b7392e 100644 --- a/Firebase/Auth/Source/Auth/FIRAuth.m +++ b/Firebase/Auth/Source/Auth/FIRAuth.m @@ -1136,10 +1136,16 @@ - (void)sendSignInLinkToEmail:(nonnull NSString *)email kMissingEmailInvalidParameterExceptionReason]; } + /* + The sign in can't happen fully in-app, i.e. watchOS does not support universal links but watchOS has a mail client that will open this link appropriately + in a browser. From the browser you trigger a cloud function which sends a push notification to complete the sign-in. + */ +#if !TARGET_OS_WATCH if (!actionCodeSettings.handleCodeInApp) { [FIRAuthExceptionUtils raiseInvalidParameterExceptionWithReason: kHandleCodeInAppFalseExceptionReason]; } +#endif FIRGetOOBConfirmationCodeRequest *request = [FIRGetOOBConfirmationCodeRequest signInWithEmailLinkRequest:email actionCodeSettings:actionCodeSettings @@ -1820,11 +1826,17 @@ - (BOOL)saveUser:(nullable FIRUser *)user success = [_keychainServices removeDataForKey:userKey error:outError]; } else { // Encode the user object. +#if TARGET_OS_WATCH + NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:false]; +#else NSMutableData *archiveData = [NSMutableData data]; NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:archiveData]; +#endif [archiver encodeObject:user forKey:userKey]; [archiver finishEncoding]; - +#if TARGET_OS_WATCH + NSData *archiveData = archiver.encodedData; +#endif // Save the user object's encoded value. success = [_keychainServices setData:archiveData forKey:userKey error:outError]; } @@ -1868,8 +1880,14 @@ - (BOOL)getUser:(FIRUser *_Nullable *)outUser *outUser = nil; return YES; } +#if TARGET_OS_WATCH + NSError *error; + NSKeyedUnarchiver *unarchiver = + [[NSKeyedUnarchiver alloc] initForReadingFromData:encodedUserData error:&error]; +#else NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:encodedUserData]; +#endif FIRUser *user = [unarchiver decodeObjectOfClass:[FIRUser class] forKey:userKey]; user.auth = self; *outUser = user; @@ -2027,8 +2045,14 @@ - (nullable FIRUser *)getStoredUserForAccessGroup:(NSString *_Nullable)accessGro return nil; } +#if TARGET_OS_WATCH + NSError *error; + NSKeyedUnarchiver *unarchiver = + [[NSKeyedUnarchiver alloc] initForReadingFromData:encodedUserData error:&error]; +#else NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:encodedUserData]; +#endif user = [unarchiver decodeObjectOfClass:[FIRUser class] forKey:userKey]; } else { user = [self.storedUserManager getStoredUserForAccessGroup:self.userAccessGroup diff --git a/Firebase/Auth/Source/AuthProvider/GameCenter/FIRGameCenterAuthProvider.m b/Firebase/Auth/Source/AuthProvider/GameCenter/FIRGameCenterAuthProvider.m index af8e7e6f74d..60b723ca45f 100644 --- a/Firebase/Auth/Source/AuthProvider/GameCenter/FIRGameCenterAuthProvider.m +++ b/Firebase/Auth/Source/AuthProvider/GameCenter/FIRGameCenterAuthProvider.m @@ -69,6 +69,9 @@ + (void)getCredentialWithCompletion:(FIRGameCenterCredentialCallback)completion `localPlayer.displayname`. For more information, check https://developer.apple.com/documentation/gamekit/gkplayer **/ +#if TARGET_OS_WATCH + completion(nil, [FIRAuthErrorUtils gameCenterNotSupportedError]); +#else NSString *displayName = localPlayer.alias; FIRGameCenterAuthCredential *credential = [[FIRGameCenterAuthCredential alloc] initWithPlayerID:localPlayer.playerID @@ -78,6 +81,7 @@ + (void)getCredentialWithCompletion:(FIRGameCenterCredentialCallback)completion timestamp:timestamp displayName:displayName]; completion(credential, nil); +#endif } } }]; diff --git a/Firebase/Auth/Source/AuthProvider/Phone/FIRPhoneAuthProvider.m b/Firebase/Auth/Source/AuthProvider/Phone/FIRPhoneAuthProvider.m index 5aa66b07c63..c3c4dd09ed5 100644 --- a/Firebase/Auth/Source/AuthProvider/Phone/FIRPhoneAuthProvider.m +++ b/Firebase/Auth/Source/AuthProvider/Phone/FIRPhoneAuthProvider.m @@ -15,7 +15,7 @@ */ #include -#if !TARGET_OS_OSX && !TARGET_OS_TV +#if !TARGET_OS_OSX && !TARGET_OS_TV && !TARGET_OS_WATCH #import "FIRPhoneAuthProvider.h" diff --git a/Firebase/Auth/Source/SystemService/FIRAuthAPNSTokenManager.h b/Firebase/Auth/Source/SystemService/FIRAuthAPNSTokenManager.h index 5e2acfeb81d..85a49053b09 100644 --- a/Firebase/Auth/Source/SystemService/FIRAuthAPNSTokenManager.h +++ b/Firebase/Auth/Source/SystemService/FIRAuthAPNSTokenManager.h @@ -18,7 +18,12 @@ #if !TARGET_OS_OSX #import + +#if TARGET_OS_WATCH +#import +#else #import +#endif @class FIRAuthAPNSToken; @@ -56,12 +61,21 @@ typedef void (^FIRAuthAPNSTokenCallback)(FIRAuthAPNSToken *_Nullable token, */ - (instancetype)init NS_UNAVAILABLE; +#if TARGET_OS_WATCH +/** @fn initWithApplication:bundle + @brief Initializes the instance. + @param application The @c WKExtension to request the token from. + @return The initialized instance. + */ +- (instancetype)initWithApplication:(WKExtension *)application NS_DESIGNATED_INITIALIZER; +#else /** @fn initWithApplication:bundle @brief Initializes the instance. @param application The @c UIApplication to request the token from. @return The initialized instance. */ - (instancetype)initWithApplication:(UIApplication *)application NS_DESIGNATED_INITIALIZER; +#endif /** @fn getTokenWithCallback: @brief Attempts to get the APNs token. diff --git a/Firebase/Auth/Source/SystemService/FIRAuthAPNSTokenManager.m b/Firebase/Auth/Source/SystemService/FIRAuthAPNSTokenManager.m index 1b37363e641..c167724d902 100644 --- a/Firebase/Auth/Source/SystemService/FIRAuthAPNSTokenManager.m +++ b/Firebase/Auth/Source/SystemService/FIRAuthAPNSTokenManager.m @@ -40,10 +40,19 @@ static const NSTimeInterval kLegacyRegistrationTimeout = 30; @implementation FIRAuthAPNSTokenManager { + #if TARGET_OS_WATCH + + /** @var _application + @brief The @c WKExtension to request the token from. + */ + WKExtension *_application; + #else + /** @var _application @brief The @c UIApplication to request the token from. */ UIApplication *_application; + #endif /** @var _pendingCallbacks @brief The list of all pending callbacks for the APNs token. @@ -51,7 +60,11 @@ @implementation FIRAuthAPNSTokenManager { NSMutableArray *_pendingCallbacks; } +#if TARGET_OS_WATCH +- (instancetype)initWithApplication:(WKExtension *)application { +#else - (instancetype)initWithApplication:(UIApplication *)application { +#endif self = [super init]; if (self) { _application = application; diff --git a/Firebase/Auth/Source/SystemService/FIRAuthAppCredentialManager.m b/Firebase/Auth/Source/SystemService/FIRAuthAppCredentialManager.m index 836456ddfdf..59eaa0ff7d8 100644 --- a/Firebase/Auth/Source/SystemService/FIRAuthAppCredentialManager.m +++ b/Firebase/Auth/Source/SystemService/FIRAuthAppCredentialManager.m @@ -70,8 +70,13 @@ - (instancetype)initWithKeychain:(FIRAuthKeychainServices *)keychain { NSError *error; NSData *encodedData = [_keychainServices dataForKey:kKeychainDataKey error:&error]; if (!error && encodedData) { +#if TARGET_OS_WATCH + NSKeyedUnarchiver *unarchiver = + [[NSKeyedUnarchiver alloc] initForReadingFromData:encodedData error:&error]; +#else NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:encodedData]; +#endif FIRAuthAppCredential *credential = [unarchiver decodeObjectOfClass:[FIRAuthAppCredential class] forKey:kFullCredentialKey]; @@ -137,11 +142,18 @@ - (void)clearCredential { @brief Save the data in memory to the keychain ignoring any errors. */ - (void)saveData { +#if TARGET_OS_WATCH + NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:false]; +#else NSMutableData *archiveData = [NSMutableData data]; NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:archiveData]; +#endif [archiver encodeObject:_credential forKey:kFullCredentialKey]; [archiver encodeObject:_pendingReceipts forKey:kPendingReceiptsKey]; [archiver finishEncoding]; +#if TARGET_OS_WATCH + NSData *archiveData = archiver.encodedData; +#endif [_keychainServices setData:archiveData forKey:kKeychainDataKey error:NULL]; } diff --git a/Firebase/Auth/Source/SystemService/FIRAuthNotificationManager.h b/Firebase/Auth/Source/SystemService/FIRAuthNotificationManager.h index 3de2e32e8b7..da21deedded 100644 --- a/Firebase/Auth/Source/SystemService/FIRAuthNotificationManager.h +++ b/Firebase/Auth/Source/SystemService/FIRAuthNotificationManager.h @@ -18,7 +18,11 @@ #if !TARGET_OS_OSX #import +#if TARGET_OS_WATCH +#import +#else #import +#endif @class FIRAuthAppCredentialManager; @@ -40,6 +44,17 @@ typedef void (^FIRAuthNotificationForwardingCallback)(BOOL isNotificationBeingFo */ @property(nonatomic, assign) NSTimeInterval timeout; +#if TARGET_OS_WATCH +/** @fn initWithApplication:appCredentialManager: + @brief Initializes the instance. + @param application The extension. + @param appCredentialManager The object to handle app credentials delivered via notification. + @return The initialized instance. + */ +- (instancetype)initWithApplication:(WKExtension *)application + appCredentialManager:(FIRAuthAppCredentialManager *)appCredentialManager + NS_DESIGNATED_INITIALIZER; +#else /** @fn initWithApplication:appCredentialManager: @brief Initializes the instance. @param application The application. @@ -49,6 +64,7 @@ typedef void (^FIRAuthNotificationForwardingCallback)(BOOL isNotificationBeingFo - (instancetype)initWithApplication:(UIApplication *)application appCredentialManager:(FIRAuthAppCredentialManager *)appCredentialManager NS_DESIGNATED_INITIALIZER; +#endif /** @fn init @brief please use initWithAppCredentialManager: instead. diff --git a/Firebase/Auth/Source/SystemService/FIRAuthNotificationManager.m b/Firebase/Auth/Source/SystemService/FIRAuthNotificationManager.m index 53488866fb3..dcaa594df49 100644 --- a/Firebase/Auth/Source/SystemService/FIRAuthNotificationManager.m +++ b/Firebase/Auth/Source/SystemService/FIRAuthNotificationManager.m @@ -52,10 +52,17 @@ static const NSTimeInterval kProbingTimeout = 1; @implementation FIRAuthNotificationManager { +#if TARGET_OS_WATCH + /** @var _application + @brief The extension. + */ + WKExtension *_application; +#else /** @var _application @brief The application. */ UIApplication *_application; +#endif /** @var _appCredentialManager @brief The object to handle app credentials delivered via notification. @@ -78,7 +85,11 @@ @implementation FIRAuthNotificationManager { NSMutableArray *_pendingCallbacks; } +#if TARGET_OS_WATCH +- (instancetype)initWithApplication:(WKExtension *)application +#else - (instancetype)initWithApplication:(UIApplication *)application +#endif appCredentialManager:(FIRAuthAppCredentialManager *)appCredentialManager { self = [super init]; if (self) { @@ -107,12 +118,20 @@ - (void)checkNotificationForwardingWithCallback:(FIRAuthNotificationForwardingCa kNotificationProberKey : @"This fake notification should be forwarded to Firebase Auth." } }; +#if TARGET_OS_WATCH + if ([self->_application.delegate respondsToSelector: + @selector(didReceiveRemoteNotification:fetchCompletionHandler:)]) { + [self->_application.delegate + didReceiveRemoteNotification:proberNotification + fetchCompletionHandler:^(WKBackgroundFetchResult result) {}]; +#else if ([self->_application.delegate respondsToSelector: @selector(application:didReceiveRemoteNotification:fetchCompletionHandler:)]) { [self->_application.delegate application:self->_application didReceiveRemoteNotification:proberNotification fetchCompletionHandler:^(UIBackgroundFetchResult result) {}]; -#if !TARGET_OS_TV +#endif +#if !TARGET_OS_TV && !TARGET_OS_WATCH } else if ([self->_application.delegate respondsToSelector: @selector(application:didReceiveRemoteNotification:)]) { [self->_application.delegate application:self->_application diff --git a/Firebase/Auth/Source/SystemService/FIRAuthStoredUserManager.m b/Firebase/Auth/Source/SystemService/FIRAuthStoredUserManager.m index 42f40d6af44..2841306bc08 100644 --- a/Firebase/Auth/Source/SystemService/FIRAuthStoredUserManager.m +++ b/Firebase/Auth/Source/SystemService/FIRAuthStoredUserManager.m @@ -82,7 +82,12 @@ - (FIRUser *)getStoredUserForAccessGroup:(NSString *)accessGroup query[(__bridge id)kSecAttrAccount] = kSharedKeychainAccountValue; NSData *data = [self.keychainServices getItemWithQuery:query error:outError]; +#if TARGET_OS_WATCH + NSError *error; + NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data error:&error]; +#else NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; +#endif FIRUser *user = [unarchiver decodeObjectOfClass:[FIRUser class] forKey:kStoredUserCoderKey]; return user; @@ -100,10 +105,17 @@ - (BOOL)setStoredUser:(FIRUser *)user query[(__bridge id)kSecAttrService] = projectIdentifier; query[(__bridge id)kSecAttrAccount] = kSharedKeychainAccountValue; +#if TARGET_OS_WATCH + NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:false]; +#else NSMutableData *data = [NSMutableData data]; NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; +#endif [archiver encodeObject:user forKey:kStoredUserCoderKey]; [archiver finishEncoding]; +#if TARGET_OS_WATCH + NSData *data = archiver.encodedData; +#endif return [self.keychainServices setItem:data withQuery:query error:outError]; } diff --git a/Firebase/Auth/Source/Utilities/FIRAuthDefaultUIDelegate.m b/Firebase/Auth/Source/Utilities/FIRAuthDefaultUIDelegate.m index f0447fefcf1..996d28f4ad8 100644 --- a/Firebase/Auth/Source/Utilities/FIRAuthDefaultUIDelegate.m +++ b/Firebase/Auth/Source/Utilities/FIRAuthDefaultUIDelegate.m @@ -15,7 +15,7 @@ */ #include -#if !TARGET_OS_OSX +#if !TARGET_OS_OSX && !TARGET_OS_WATCH #import "FIRAuthDefaultUIDelegate.h" diff --git a/Firebase/Auth/Source/Utilities/FIRAuthErrorUtils.h b/Firebase/Auth/Source/Utilities/FIRAuthErrorUtils.h index 31bbf5b3119..96f7c062597 100644 --- a/Firebase/Auth/Source/Utilities/FIRAuthErrorUtils.h +++ b/Firebase/Auth/Source/Utilities/FIRAuthErrorUtils.h @@ -563,6 +563,11 @@ NS_ASSUME_NONNULL_BEGIN */ + (NSError *)missingOrInvalidNonceErrorWithMessage:(nullable NSString *)message; +/** @fn gameCenterNotSupportedError + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInternalError code. + @return The NSError instance associated with the FIRAuthErrorCodeInternalError. + */ ++ (NSError *)gameCenterNotSupportedError; @end NS_ASSUME_NONNULL_END diff --git a/Firebase/Auth/Source/Utilities/FIRAuthErrorUtils.m b/Firebase/Auth/Source/Utilities/FIRAuthErrorUtils.m index 146c14f29b9..3eef57e6059 100644 --- a/Firebase/Auth/Source/Utilities/FIRAuthErrorUtils.m +++ b/Firebase/Auth/Source/Utilities/FIRAuthErrorUtils.m @@ -1200,6 +1200,10 @@ + (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSSt }]; } ++ (NSError *)gameCenterNotSupportedError; { + return [self errorWithCode:FIRAuthInternalErrorCodeGameKitNotAvailable message:@"Game Center not supported on watchOS"]; +} + @end NS_ASSUME_NONNULL_END diff --git a/Firebase/Auth/Source/Utilities/FIRAuthInternalErrors.h b/Firebase/Auth/Source/Utilities/FIRAuthInternalErrors.h index 8f34bdfc8d3..4b4e5e685fc 100644 --- a/Firebase/Auth/Source/Utilities/FIRAuthInternalErrors.h +++ b/Firebase/Auth/Source/Utilities/FIRAuthInternalErrors.h @@ -393,6 +393,11 @@ typedef NS_ENUM(NSInteger, FIRAuthInternalErrorCode) { FIRAuthInternalErrorCodeGameKitNotLinked = FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeGameKitNotLinked, + /** Indicates that the Game Center is not available on this platform. + */ + FIRAuthInternalErrorCodeGameKitNotAvailable = + FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeInternalError, + /** Indicates that the nonce is missing or invalid. */ FIRAuthInternalErrorCodeMissingOrInvalidNonce = diff --git a/Firebase/Auth/Source/Utilities/FIRAuthURLPresenter.m b/Firebase/Auth/Source/Utilities/FIRAuthURLPresenter.m index 2a4329271e8..cb65c020bad 100644 --- a/Firebase/Auth/Source/Utilities/FIRAuthURLPresenter.m +++ b/Firebase/Auth/Source/Utilities/FIRAuthURLPresenter.m @@ -15,7 +15,7 @@ */ #include -#if !TARGET_OS_OSX && !TARGET_OS_TV +#if !TARGET_OS_OSX && !TARGET_OS_TV && !TARGET_OS_WATCH #import "FIRAuthURLPresenter.h" diff --git a/Firebase/Auth/Source/Utilities/FIRAuthWebView.h b/Firebase/Auth/Source/Utilities/FIRAuthWebView.h index 4b7a5836be0..632451e8fa8 100644 --- a/Firebase/Auth/Source/Utilities/FIRAuthWebView.h +++ b/Firebase/Auth/Source/Utilities/FIRAuthWebView.h @@ -15,7 +15,7 @@ */ #include -#if !TARGET_OS_OSX && !TARGET_OS_TV +#if !TARGET_OS_OSX && !TARGET_OS_TV && !TARGET_OS_WATCH #import #import diff --git a/Firebase/Auth/Source/Utilities/FIRAuthWebView.m b/Firebase/Auth/Source/Utilities/FIRAuthWebView.m index 7b3a9eda04d..1eefb5260c7 100644 --- a/Firebase/Auth/Source/Utilities/FIRAuthWebView.m +++ b/Firebase/Auth/Source/Utilities/FIRAuthWebView.m @@ -15,7 +15,7 @@ */ #include -#if !TARGET_OS_OSX && !TARGET_OS_TV +#if !TARGET_OS_OSX && !TARGET_OS_TV && !TARGET_OS_WATCH #import "FIRAuthWebView.h" diff --git a/Firebase/Auth/Source/Utilities/FIRAuthWebViewController.h b/Firebase/Auth/Source/Utilities/FIRAuthWebViewController.h index 25926c59a3d..67ec4bb9061 100644 --- a/Firebase/Auth/Source/Utilities/FIRAuthWebViewController.h +++ b/Firebase/Auth/Source/Utilities/FIRAuthWebViewController.h @@ -15,7 +15,7 @@ */ #include -#if !TARGET_OS_OSX && !TARGET_OS_TV +#if !TARGET_OS_OSX && !TARGET_OS_TV && !TARGET_OS_WATCH #import diff --git a/Firebase/Auth/Source/Utilities/FIRAuthWebViewController.m b/Firebase/Auth/Source/Utilities/FIRAuthWebViewController.m index 163bfe814ee..0deffafd16b 100644 --- a/Firebase/Auth/Source/Utilities/FIRAuthWebViewController.m +++ b/Firebase/Auth/Source/Utilities/FIRAuthWebViewController.m @@ -15,7 +15,7 @@ */ #include -#if !TARGET_OS_OSX && !TARGET_OS_TV +#if !TARGET_OS_OSX && !TARGET_OS_TV && !TARGET_OS_WATCH #import "FIRAuthWebViewController.h" diff --git a/FirebaseAuth.podspec b/FirebaseAuth.podspec index fb706dd1224..f63ecdc9493 100644 --- a/FirebaseAuth.podspec +++ b/FirebaseAuth.podspec @@ -20,6 +20,7 @@ supports email and password accounts, as well as several 3rd party authenticatio s.ios.deployment_target = '8.0' s.osx.deployment_target = '10.11' s.tvos.deployment_target = '10.0' + s.watchos.deployment_target = '6.0' s.cocoapods_version = '>= 1.4.0' s.static_framework = true @@ -47,6 +48,7 @@ supports email and password accounts, as well as several 3rd party authenticatio s.dependency 'GTMSessionFetcher/Core', '~> 1.1' s.test_spec 'unit' do |unit_tests| + unit_tests.platforms = {:ios => '8.0', :osx => '10.11', :tvos => '10.0'} unit_tests.source_files = 'Example/Auth/Tests/*.[mh]' unit_tests.osx.exclude_files = [ 'Example/Auth/Tests/FIRAuthAPNSTokenManagerTests.m', diff --git a/FirebaseAuthInterop.podspec b/FirebaseAuthInterop.podspec index df08e2a64da..727438e5c42 100644 --- a/FirebaseAuthInterop.podspec +++ b/FirebaseAuthInterop.podspec @@ -24,6 +24,7 @@ Pod::Spec.new do |s| s.ios.deployment_target = '8.0' s.osx.deployment_target = '10.11' s.tvos.deployment_target = '10.0' + s.watchos.deployment_target = '6.0' s.source_files = 'Interop/Auth/**/*.h' s.public_header_files = 'Interop/Auth/Public/*.h' end