Эх сурвалжийг харах

watchOS support for FirebaseAuth. (#6260)

* watchOS support for FirebaseAuth.

This is a redo of #5585, which was a re-implementation of #4632. This
ignores any changes to GoogleUtilities, those will be done in a later
PR to create a common KeyedArchiver utility.

Co-authored-by: Harri Hohteri <harri.hohteri@gmail.com>

* Fixed lint errors, added GHA tests.

* Enabled GHA for PRs as well.

Co-authored-by: Harri Hohteri <harri.hohteri@gmail.com>
Ryan Wilson 5 жил өмнө
parent
commit
5fb9d2a448

+ 3 - 2
.github/workflows/auth.yml

@@ -21,7 +21,7 @@ jobs:
 
     strategy:
       matrix:
-        target: [ios, tvos, macos]
+        target: [ios, tvos, macos, watchos]
     steps:
     - uses: actions/checkout@v2
     - name: Setup Bundler
@@ -104,7 +104,8 @@ jobs:
     runs-on: macos-latest
     strategy:
       matrix:
-        target: [ios, tvos --skip-tests, macos --skip-tests] # The macos and tvos tests can hang
+        # The macos and tvos tests can hang, and watchOS doesn't have tests.
+        target: [ios, tvos --skip-tests, macos --skip-tests, watchos --skip-tests]
         flags: [
           '--use-modular-headers',
           '--use-libraries'

+ 3 - 0
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
@@ -54,6 +55,8 @@ 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 can't run on watchOS.
+    unit_tests.platforms = {:ios => '8.0', :osx => '10.11', :tvos => '10.0'}
     unit_tests.source_files = 'FirebaseAuth/Tests/Unit/*.[mh]'
     unit_tests.osx.exclude_files = [
       'FirebaseAuth/Tests/Unit/FIRAuthAPNSTokenManagerTests.m',

+ 3 - 0
FirebaseAuth/CHANGELOG.md

@@ -1,3 +1,6 @@
+# Unreleased
+- [added] Added basic watchOS support. (#4621)
+
 # v6.8.0
 - [fixed] Fix bug where multiple keychain entries would result in user persistence failure. (#5906)
 - [changed] Added support for using GOOGLE_APP_ID in generic IDP and phone auth reCAPTCHA fallback flows. (#6121)

+ 24 - 0
FirebaseAuth/Sources/Auth/FIRAuth.m

@@ -2000,6 +2000,9 @@ static NSMutableDictionary *gKeychainServiceNameForAppName;
     if (!user) {
       success = [_keychainServices removeDataForKey:userKey error:outError];
     } else {
+#if TARGET_OS_WATCH
+      NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:false];
+#else
       // Encode the user object.
       NSMutableData *archiveData = [NSMutableData data];
 // iOS 12 deprecation
@@ -2008,9 +2011,14 @@ static NSMutableDictionary *gKeychainServiceNameForAppName;
       NSKeyedArchiver *archiver =
           [[NSKeyedArchiver alloc] initForWritingWithMutableData:archiveData];
 #pragma clang diagnostic pop
+#endif  // TARGET_OS_WATCH
       [archiver encodeObject:user forKey:userKey];
       [archiver finishEncoding];
 
+#if TARGET_OS_WATCH
+      NSData *archiveData = archiver.encodedData;
+#endif  // TARGET_OS_WATCH
+
       // Save the user object's encoded value.
       success = [_keychainServices setData:archiveData forKey:userKey error:outError];
     }
@@ -2053,12 +2061,20 @@ static NSMutableDictionary *gKeychainServiceNameForAppName;
       *outUser = nil;
       return YES;
     }
+#if TARGET_OS_WATCH
+    NSKeyedUnarchiver *unarchiver =
+        [[NSKeyedUnarchiver alloc] initForReadingFromData:encodedUserData error:error];
+    if (error && *error) {
+      return NO;
+    }
+#else
 // iOS 12 deprecation
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
     NSKeyedUnarchiver *unarchiver =
         [[NSKeyedUnarchiver alloc] initForReadingWithData:encodedUserData];
 #pragma clang diagnostic pop
+#endif  // TARGET_OS_WATCH
     FIRUser *user = [unarchiver decodeObjectOfClass:[FIRUser class] forKey:userKey];
     user.auth = self;
     *outUser = user;
@@ -2225,12 +2241,20 @@ static NSMutableDictionary *gKeychainServiceNameForAppName;
       return nil;
     }
 
+#if TARGET_OS_WATCH
+    NSKeyedUnarchiver *unarchiver =
+        [[NSKeyedUnarchiver alloc] initForReadingFromData:encodedUserData error:outError];
+    if (outError && *outError) {
+      return nil;
+    }
+#else
 // iOS 12 deprecation
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
     NSKeyedUnarchiver *unarchiver =
         [[NSKeyedUnarchiver alloc] initForReadingWithData:encodedUserData];
 #pragma clang diagnostic pop
+#endif  // TARGET_OS_WATCH
     user = [unarchiver decodeObjectOfClass:[FIRUser class] forKey:userKey];
   } else {
     user = [self.storedUserManager getStoredUserForAccessGroup:self.userAccessGroup

+ 1 - 1
FirebaseAuth/Sources/MultiFactor/FIRMultiFactor+Internal.h

@@ -23,7 +23,7 @@
 
 NS_ASSUME_NONNULL_BEGIN
 
-@interface FIRMultiFactor ()
+@interface FIRMultiFactor () <NSSecureCoding>
 
 @property(nonatomic, weak) FIRUser *user;
 

+ 5 - 4
FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h

@@ -456,7 +456,7 @@ NS_SWIFT_NAME(Auth)
 
 - (void)signInWithEmail:(NSString *)email
                    link:(NSString *)link
-             completion:(nullable FIRAuthDataResultCallback)completion;
+             completion:(nullable FIRAuthDataResultCallback)completion API_UNAVAILABLE(watchos);
 
 /** @fn signInWithProvider:UIDelegate:completion:
     @brief Signs in using the provided auth provider instance.
@@ -504,7 +504,7 @@ NS_SWIFT_NAME(Auth)
  */
 - (void)signInWithProvider:(id<FIRFederatedAuthProvider>)provider
                 UIDelegate:(nullable id<FIRAuthUIDelegate>)UIDelegate
-                completion:(nullable FIRAuthDataResultCallback)completion;
+                completion:(nullable FIRAuthDataResultCallback)completion API_UNAVAILABLE(watchos);
 
 /** @fn signInAndRetrieveDataWithCredential:completion:
     @brief Please use signInWithCredential:completion: for Objective-C or "
@@ -736,7 +736,8 @@ NS_SWIFT_NAME(Auth)
  */
 - (void)sendSignInLinkToEmail:(NSString *)email
            actionCodeSettings:(FIRActionCodeSettings *)actionCodeSettings
-                   completion:(nullable FIRSendSignInLinkToEmailCallback)completion;
+                   completion:(nullable FIRSendSignInLinkToEmailCallback)completion
+    API_UNAVAILABLE(watchos);
 
 /** @fn signOut:
     @brief Signs out the current user.
@@ -762,7 +763,7 @@ NS_SWIFT_NAME(Auth)
     @param link The email sign-in link.
     @return @YES when the link passed matches the expected format of an email sign-in link.
  */
-- (BOOL)isSignInWithEmailLink:(NSString *)link;
+- (BOOL)isSignInWithEmailLink:(NSString *)link API_UNAVAILABLE(watchos);
 
 /** @fn addAuthStateDidChangeListener:
     @brief Registers a block as an "auth state did change" listener. To be invoked when:

+ 3 - 1
FirebaseAuth/Sources/Public/FirebaseAuth/FIRGameCenterAuthProvider.h

@@ -41,8 +41,10 @@ typedef void (^FIRGameCenterCredentialCallback)(FIRAuthCredential *_Nullable cre
     NS_SWIFT_NAME(GameCenterCredentialCallback);
 
 /** @class FIRGameCenterAuthProvider
-    @brief A concrete implementation of @c FIRAuthProvider for Game Center Sign In.
+    @brief A concrete implementation of @c FIRAuthProvider for Game Center Sign In. Not available on
+           watchOS.
  */
+API_UNAVAILABLE(watchos)
 NS_SWIFT_NAME(GameCenterAuthProvider)
 @interface FIRGameCenterAuthProvider : NSObject
 

+ 2 - 2
FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.h

@@ -15,7 +15,7 @@
  */
 
 #import <TargetConditionals.h>
-#if !TARGET_OS_OSX
+#if !TARGET_OS_OSX && !TARGET_OS_WATCH
 
 #import <Foundation/Foundation.h>
 #import <UIKit/UIKit.h>
@@ -56,7 +56,7 @@ typedef void (^FIRAuthAPNSTokenCallback)(FIRAuthAPNSToken *_Nullable token,
  */
 - (instancetype)init NS_UNAVAILABLE;
 
-/** @fn initWithApplication:bundle
+/** @fn initWithApplication:
     @brief Initializes the instance.
     @param application The @c UIApplication to request the token from.
     @return The initialized instance.

+ 1 - 1
FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.m

@@ -15,7 +15,7 @@
  */
 
 #import <TargetConditionals.h>
-#if !TARGET_OS_OSX
+#if !TARGET_OS_OSX && !TARGET_OS_WATCH
 
 #import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
 #import "GoogleUtilities/Environment/Private/GULAppEnvironmentUtil.h"

+ 6 - 1
FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.m

@@ -69,15 +69,20 @@ static const NSUInteger kMaximumNumberOfPendingReceipts = 32;
     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
 // iOS 12 deprecation
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
       NSKeyedUnarchiver *unarchiver =
           [[NSKeyedUnarchiver alloc] initForReadingWithData:encodedData];
 #pragma clang diagnostic pop
+#endif  // TARGET_OS_WATCH
       FIRAuthAppCredential *credential =
           [unarchiver decodeObjectOfClass:[FIRAuthAppCredential class] forKey:kFullCredentialKey];
-      if ([credential isKindOfClass:[FIRAuthAppCredential class]]) {
+      if ([credential isKindOfClass:[FIRAuthAppCredential class]] && !error) {
         _credential = credential;
       }
       NSSet<Class> *allowedClasses =

+ 1 - 1
FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.h

@@ -15,7 +15,7 @@
  */
 
 #import <TargetConditionals.h>
-#if !TARGET_OS_OSX
+#if !TARGET_OS_OSX && !TARGET_OS_WATCH
 
 #import <Foundation/Foundation.h>
 #import <UIKit/UIKit.h>

+ 1 - 1
FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.m

@@ -15,7 +15,7 @@
  */
 
 #import <TargetConditionals.h>
-#if !TARGET_OS_OSX
+#if !TARGET_OS_OSX && !TARGET_OS_WATCH
 
 #import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
 

+ 4 - 4
FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.h

@@ -49,7 +49,7 @@ NS_ASSUME_NONNULL_BEGIN
     @brief Get the user access group stored locally.
     @param outError Return value for any error which occurs.
  */
-- (NSString *_Nullable)getStoredUserAccessGroupWithError:(NSError *_Nullable *_Nullable)outError;
+- (nullable NSString *)getStoredUserAccessGroupWithError:(NSError *_Nullable *_Nullable)outError;
 
 /** @fn setStoredUserAccessGroup:error:
     @brief The setter of the user access group stored locally.
@@ -66,9 +66,9 @@ NS_ASSUME_NONNULL_BEGIN
         we use API KEY.
     @param outError Return value for any error which occurs.
  */
-- (FIRUser *)getStoredUserForAccessGroup:(NSString *)accessGroup
-                       projectIdentifier:(NSString *)projectIdentifier
-                                   error:(NSError *_Nullable *_Nullable)outError;
+- (nullable FIRUser *)getStoredUserForAccessGroup:(NSString *)accessGroup
+                                projectIdentifier:(NSString *)projectIdentifier
+                                            error:(NSError *_Nullable *_Nullable)outError;
 
 /** @fn setStoredUser:forAccessGroup:projectID:error:
     @brief The setter of the user stored locally.

+ 22 - 0
FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.m

@@ -16,6 +16,8 @@
 
 #import "FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.h"
 
+#import "FirebaseAuth/Sources/User/FIRUser_Internal.h"
+
 /** @var kUserAccessGroupKey
     @brief Key of user access group stored in user defaults. Used for retrieve the user access
         group at launch.
@@ -80,11 +82,23 @@ static NSString *kStoredUserCoderKey = @"firebase_auth_stored_user_coder_key";
   query[(__bridge id)kSecAttrAccount] = kSharedKeychainAccountValue;
 
   NSData *data = [self.keychainServices getItemWithQuery:query error:outError];
+  // If there's an outError parameter and it's populated, or there's no data, return.
+  if ((outError && *outError) || !data) {
+    return nil;
+  }
+#if TARGET_OS_WATCH
+  NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data
+                                                                              error:outError];
+  if (outError && *outError) {
+    return nil;
+  }
+#else
 // iOS 12 deprecation
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
   NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
 #pragma clang diagnostic pop
+#endif  // TARGET_OS_WATCH
   FIRUser *user = [unarchiver decodeObjectOfClass:[FIRUser class] forKey:kStoredUserCoderKey];
 
   return user;
@@ -103,15 +117,23 @@ static NSString *kStoredUserCoderKey = @"firebase_auth_stored_user_coder_key";
   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];
 // iOS 12 deprecation
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
   NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
 #pragma clang diagnostic pop
+#endif  // TARGET_OS_WATCH
   [archiver encodeObject:user forKey:kStoredUserCoderKey];
   [archiver finishEncoding];
 
+#if TARGET_OS_WATCH
+  NSData *data = archiver.encodedData;
+#endif  // TARGET_OS_WATCH
+
   return [self.keychainServices setItem:data withQuery:query error:outError];
 }
 

+ 1 - 1
FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.h

@@ -15,7 +15,7 @@
  */
 
 #import <TargetConditionals.h>
-#if !TARGET_OS_OSX
+#if !TARGET_OS_OSX && !TARGET_OS_WATCHOS
 
 #import <Foundation/Foundation.h>
 #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthUIDelegate.h"

+ 1 - 1
FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.m

@@ -15,7 +15,7 @@
  */
 
 #import <TargetConditionals.h>
-#if !TARGET_OS_OSX
+#if !TARGET_OS_OSX && !TARGET_OS_WATCH
 
 #import <UIKit/UIKit.h>
 #import "GoogleUtilities/Environment/Private/GULAppEnvironmentUtil.h"

+ 1 - 1
README.md

@@ -245,7 +245,7 @@ To install, add a subset of the following to the Podfile:
 
 ```
 pod 'Firebase/ABTesting'     # No watchOS support yet
-pod 'Firebase/Auth'          # No watchOS support yet
+pod 'Firebase/Auth'          # Limited watchOS support
 pod 'Firebase/Crashlytics'   # No watchOS support yet
 pod 'Firebase/Database'      # No watchOS support yet
 pod 'Firebase/Firestore'     # No watchOS support yet