diff --git a/FirebaseAuth/Tests/Unit/AuthLifecycleTests.swift b/FirebaseAuth/Tests/Unit/AuthLifecycleTests.swift index 6c43c93c3e4..1697647e2dd 100644 --- a/FirebaseAuth/Tests/Unit/AuthLifecycleTests.swift +++ b/FirebaseAuth/Tests/Unit/AuthLifecycleTests.swift @@ -20,12 +20,12 @@ import FirebaseCore @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) class AuthLifecycleTests: XCTestCase { - private let kFakeAPIKey = "FAKE_API_KEY" - private let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000", - gcmSenderID: "00000000000000000-00000000000-000000000") - + private static let kFakeAPIKey = "FAKE_API_KEY" + private let options = FirebaseOptions(appID: "0:0000000000000:ios:0000000000000000", + projectNumber: "00000000000000000-00000000000-000000000", + projectID: "", + apiKey: AuthLifecycleTests.kFakeAPIKey) override func setUp() { - options.apiKey = kFakeAPIKey FirebaseApp.resetApps() FirebaseApp.configure(options: options) } @@ -56,7 +56,7 @@ class AuthLifecycleTests: XCTestCase { */ func testAppAPIKey() { let auth = Auth.auth() - XCTAssertEqual(auth.requestConfiguration.apiKey, kFakeAPIKey) + XCTAssertEqual(auth.requestConfiguration.apiKey, AuthLifecycleTests.kFakeAPIKey) } /** @fn testAppAssociation diff --git a/FirebaseAuth/Tests/Unit/AuthTests.swift b/FirebaseAuth/Tests/Unit/AuthTests.swift index 1167bf22ca2..3d2b2b4037a 100644 --- a/FirebaseAuth/Tests/Unit/AuthTests.swift +++ b/FirebaseAuth/Tests/Unit/AuthTests.swift @@ -33,10 +33,10 @@ class AuthTests: RPCBaseTests { override func setUp() { super.setUp() - let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000", - gcmSenderID: "00000000000000000-00000000000-000000000") - options.apiKey = AuthTests.kFakeAPIKey - options.projectID = "myProjectID" + let options = FirebaseOptions(appID: "0:0000000000000:ios:0000000000000000", + projectNumber: "00000000000000000-00000000000-000000000", + projectID: "myProjectID", + apiKey: AuthTests.kFakeAPIKey) let name = "test-AuthTests\(AuthTests.testNum)" AuthTests.testNum = AuthTests.testNum + 1 FirebaseApp.configure(name: name, options: options) diff --git a/FirebaseAuth/Tests/Unit/AuthUseUserAccessGroupTests.swift b/FirebaseAuth/Tests/Unit/AuthUseUserAccessGroupTests.swift index 9deee328bab..cf1d3150ed2 100644 --- a/FirebaseAuth/Tests/Unit/AuthUseUserAccessGroupTests.swift +++ b/FirebaseAuth/Tests/Unit/AuthUseUserAccessGroupTests.swift @@ -24,10 +24,10 @@ class UseUserAccessGroupTests: RPCBaseTests { override class func setUp() { let kFakeAPIKey = "FAKE_API_KEY" - let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000", - gcmSenderID: "00000000000000000-00000000000-000000000") - options.apiKey = kFakeAPIKey - options.projectID = "myUserProjectID" + let options = FirebaseOptions(appID: "0:0000000000000:ios:0000000000000000", + projectNumber: "00000000000000000-00000000000-000000000", + projectID: "myUserProjectID", + apiKey: kFakeAPIKey) FirebaseApp.configure(name: "testUseUserAccessGroupTests", options: options) let keychainStorageProvider = FakeAuthKeychainStorage() auth = Auth( diff --git a/FirebaseAuth/Tests/Unit/FIROAuthProviderTests.m b/FirebaseAuth/Tests/Unit/FIROAuthProviderTests.m index b5921312caa..d50be87f98c 100644 --- a/FirebaseAuth/Tests/Unit/FIROAuthProviderTests.m +++ b/FirebaseAuth/Tests/Unit/FIROAuthProviderTests.m @@ -168,12 +168,10 @@ - (void)testObtainingOAuthCredentialWithIDToken { */ - (void)testGetCredentialWithUIDelegateWithClientIDOnMainThread { XCTestExpectation *expectation = [self expectationWithDescription:@"callback"]; - - FIROptions *options = - [[FIROptions alloc] initWithGoogleAppID:@"0:0000000000000:ios:0000000000000000" - GCMSenderID:@"00000000000000000-00000000000-000000000"]; - options.APIKey = kFakeAPIKey; - options.projectID = @"myProjectID"; + FIROptions *options = [[FIROptions alloc] initWithAppID:@"0:0000000000000:ios:0000000000000000" + projectNumber:@"00000000000000000-00000000000-000000000" + projectID:@"myProjectID" + apiKey:kFakeAPIKey]; options.clientID = kFakeClientID; [FIRApp configureWithName:@"objAppName" options:options]; FIRAuth *auth = [FIRAuth authWithApp:[FIRApp appNamed:@"objAppName"]]; diff --git a/FirebaseAuth/Tests/Unit/IdentityToolkitRequestTests.swift b/FirebaseAuth/Tests/Unit/IdentityToolkitRequestTests.swift index 441198a4d1f..44279d325f5 100644 --- a/FirebaseAuth/Tests/Unit/IdentityToolkitRequestTests.swift +++ b/FirebaseAuth/Tests/Unit/IdentityToolkitRequestTests.swift @@ -114,8 +114,10 @@ class IdentityToolkitRequestTests: XCTestCase { @brief Tests the request correctly populated the tenant ID from a non default app. */ func testExpectedTenantIDWithNonDefaultFIRApp() { - let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000", - gcmSenderID: "00000000000000000-00000000000-000000000") + let options = FirebaseOptions(appID: "0:0000000000000:ios:0000000000000000", + projectNumber: "00000000000000000-00000000000-000000000", + projectID: "myProjectID", + apiKey: kAPIKey) options.apiKey = kAPIKey let nonDefaultApp = FirebaseApp(instanceWithName: "nonDefaultApp", options: options) let nonDefaultAuth = Auth(app: nonDefaultApp) diff --git a/FirebaseAuth/Tests/Unit/MultiFactorResolverTests.swift b/FirebaseAuth/Tests/Unit/MultiFactorResolverTests.swift index 145ed8d6792..9e8ab4a5a05 100644 --- a/FirebaseAuth/Tests/Unit/MultiFactorResolverTests.swift +++ b/FirebaseAuth/Tests/Unit/MultiFactorResolverTests.swift @@ -24,10 +24,10 @@ import FirebaseCore static var auth: Auth? override class func setUp() { let kFakeAPIKey = "FAKE_API_KEY" - let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000", - gcmSenderID: "00000000000000000-00000000000-000000000") - options.apiKey = kFakeAPIKey - options.projectID = "myUserProjectID" + let options = FirebaseOptions(appID: "0:0000000000000:ios:0000000000000000", + projectNumber: "00000000000000000-00000000000-000000000", + projectID: "myUserProjectID", + apiKey: kFakeAPIKey) FirebaseApp.configure(name: "test-mfaResolver", options: options) auth = Auth( app: FirebaseApp.app(name: "test-mfaResolver")! diff --git a/FirebaseAuth/Tests/Unit/OAuthProviderTests.swift b/FirebaseAuth/Tests/Unit/OAuthProviderTests.swift index 6f1ed895b0a..d1dbc3ee68f 100644 --- a/FirebaseAuth/Tests/Unit/OAuthProviderTests.swift +++ b/FirebaseAuth/Tests/Unit/OAuthProviderTests.swift @@ -267,10 +267,10 @@ import FirebaseCore private func initApp(_ functionName: String, useAppID: Bool = false, omitClientID: Bool = false, scheme: String = OAuthProviderTests.kFakeReverseClientID) { - let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000", - gcmSenderID: "00000000000000000-00000000000-000000000") - options.apiKey = OAuthProviderTests.kFakeAPIKey - options.projectID = "myProjectID" + let options = FirebaseOptions(appID: "0:0000000000000:ios:0000000000000000", + projectNumber: "00000000000000000-00000000000-000000000", + projectID: "myProjectID", + apiKey: OAuthProviderTests.kFakeAPIKey) if useAppID { options.googleAppID = OAuthProviderTests.kFakeFirebaseAppID } diff --git a/FirebaseAuth/Tests/Unit/PhoneAuthProviderTests.swift b/FirebaseAuth/Tests/Unit/PhoneAuthProviderTests.swift index 0030c52776d..987f4320242 100644 --- a/FirebaseAuth/Tests/Unit/PhoneAuthProviderTests.swift +++ b/FirebaseAuth/Tests/Unit/PhoneAuthProviderTests.swift @@ -645,10 +645,10 @@ testMode: Bool = false, forwardingNotification: Bool = true, fakeToken: Bool = false) { - let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000", - gcmSenderID: "00000000000000000-00000000000-000000000") - options.apiKey = PhoneAuthProviderTests.kFakeAPIKey - options.projectID = "myProjectID" + let options = FirebaseOptions(appID: "0:0000000000000:ios:0000000000000000", + projectNumber: "00000000000000000-00000000000-000000000", + projectID: "myProjectID", + apiKey: PhoneAuthProviderTests.kFakeAPIKey) if useClientID { options.clientID = PhoneAuthProviderTests.kFakeClientID } diff --git a/FirebaseAuth/Tests/Unit/UserTests.swift b/FirebaseAuth/Tests/Unit/UserTests.swift index 77c1449792f..4580fba75c6 100644 --- a/FirebaseAuth/Tests/Unit/UserTests.swift +++ b/FirebaseAuth/Tests/Unit/UserTests.swift @@ -36,10 +36,10 @@ class UserTests: RPCBaseTests { static var auth: Auth? override class func setUp() { - let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000", - gcmSenderID: "00000000000000000-00000000000-000000000") - options.apiKey = kFakeAPIKey - options.projectID = "myUserProjectID" + let options = FirebaseOptions(appID: "0:0000000000000:ios:0000000000000000", + projectNumber: "00000000000000000-00000000000-000000000", + projectID: "myUserProjectID", + apiKey: kFakeAPIKey) FirebaseApp.configure(name: "test-UserTests", options: options) #if (os(macOS) && !FIREBASE_AUTH_TESTING_USE_MACOS_KEYCHAIN) || SWIFT_PACKAGE let keychainStorageProvider = FakeAuthKeychainStorage() diff --git a/FirebaseCore.podspec b/FirebaseCore.podspec index a69f318c4ce..a98d0558d51 100644 --- a/FirebaseCore.podspec +++ b/FirebaseCore.podspec @@ -76,7 +76,10 @@ Firebase Core includes FIRApp and FIROptions which provide central configuration unit_tests.requires_app_host = true unit_tests.dependency 'OCMock' - unit_tests.resources = 'FirebaseCore/Tests/Unit/Resources/GoogleService-Info.plist' + unit_tests.resources = [ + 'FirebaseCore/Tests/Unit/Resources/GoogleService-Info.plist', + 'FirebaseCore/Tests/Unit/Resources/firebase-sdk-config-apple.json', + ] end s.test_spec 'swift-unit' do |swift_unit_tests| @@ -97,6 +100,9 @@ Firebase Core includes FIRApp and FIROptions which provide central configuration } swift_unit_tests.requires_app_host = true swift_unit_tests.dependency 'OCMock' - swift_unit_tests.resources = 'FirebaseCore/Tests/Unit/Resources/GoogleService-Info.plist' + swift_unit_tests.resources = [ + 'FirebaseCore/Tests/Unit/Resources/GoogleService-Info.plist', + 'FirebaseCore/Tests/Unit/Resources/firebase-sdk-config-apple.json', + ] end end diff --git a/FirebaseCore/Extension/FIROptionsInternal.h b/FirebaseCore/Extension/FIROptionsInternal.h index 93a03d6894c..2e6a2e028d0 100644 --- a/FirebaseCore/Extension/FIROptionsInternal.h +++ b/FirebaseCore/Extension/FIROptionsInternal.h @@ -31,11 +31,13 @@ extern NSString *const kFIRBundleID; extern NSString *const kFIRProjectID; /** - * Keys for the plist file name + * Keys for the config file names. */ +// TODO(next major): Rename from "kServiceInfo*" to "kPlist*" extern NSString *const kServiceInfoFileName; - extern NSString *const kServiceInfoFileType; +extern NSString *const kJsonFileName; +extern NSString *const kJsonFileType; /** * This header file exposes the initialization of FirebaseOptions to internal use. @@ -85,8 +87,9 @@ extern NSString *const kServiceInfoFileType; */ @property(nonatomic, readonly, copy) NSString *libraryVersionID; +// TODO(next major): Rename to usingOptionsFromDefaultConfig. /** - * The flag indicating whether this object was constructed with the values in the default plist + * The flag indicating whether this object was constructed with the values in the default config * file. */ @property(nonatomic) BOOL usingOptionsFromDefaultPlist; diff --git a/FirebaseCore/Sources/FIRApp.m b/FirebaseCore/Sources/FIRApp.m index abec9669f9b..26973ef1948 100644 --- a/FirebaseCore/Sources/FIRApp.m +++ b/FirebaseCore/Sources/FIRApp.m @@ -80,9 +80,9 @@ NSString *const kFirebaseCoreErrorDomain = @"com.firebase.core"; /** - * The URL to download plist files. + * The URL to download config files. */ -static NSString *const kPlistURL = @"https://console.firebase.google.com/"; +static NSString *const kConfigFileURL = @"https://console.firebase.google.com/"; @interface FIRApp () @@ -104,13 +104,13 @@ + (void)configure { FIROptions *options = [FIROptions defaultOptions]; if (!options) { #if DEBUG - [self findMisnamedGoogleServiceInfoPlist]; + [self findMisnamedJsonConfig]; #endif // DEBUG [NSException raise:kFirebaseCoreErrorDomain format:@"`FirebaseApp.configure()` could not find " - @"a valid GoogleService-Info.plist in your project. Please download one " - @"from %@.", - kPlistURL]; + @"a valid firebase-sdk-config-apple.json in your project. Please " + @"download one from %@.", + kConfigFileURL]; } [FIRApp configureWithOptions:options]; } @@ -541,7 +541,7 @@ - (void)checkExpectedBundleID { @"plist file, you may change your app's bundle identifier to '%@'. Or you can " @"download a new configuration file that matches your bundle identifier from %@ " @"and replace the current one.", - kServiceInfoFileName, kServiceInfoFileType, expectedBundleID, kPlistURL); + kJsonFileName, kJsonFileType, expectedBundleID, kConfigFileURL); } } @@ -560,13 +560,13 @@ - (BOOL)isAppIDValid { if (!isValid) { NSString *expectedBundleID = [self expectedBundleID]; FIRLogError(kFIRLoggerCore, @"I-COR000009", - @"The GOOGLE_APP_ID either in the plist file " + @"The GOOGLE_APP_ID either in the config file " @"'%@.%@' or the one set in the customized options is invalid. If you are using " - @"the plist file, use the iOS version of bundle identifier to download the file, " + @"the config file, use the iOS version of bundle identifier to download the file, " @"and do not manually edit the GOOGLE_APP_ID. You may change your app's bundle " @"identifier to '%@'. Or you can download a new configuration file that matches " @"your bundle identifier from %@ and replace the current one.", - kServiceInfoFileName, kServiceInfoFileType, expectedBundleID, kPlistURL); + kJsonFileName, kJsonFileType, expectedBundleID, kConfigFileURL); }; return isValid; } @@ -624,7 +624,7 @@ + (NSString *)actualBundleID { * This method does not verify that the contents of the app id are correct, just that they fulfill * the expected format. * - * @param appID Contents of GOOGLE_APP_ID from the plist file. + * @param appID Contents of GOOGLE_APP_ID from the config file. * @param version Indicates what version of the app id format this string should be. * @return YES if provided string fulfills the expected format, NO otherwise. */ @@ -706,7 +706,7 @@ + (BOOL)validateAppIDFormat:(NSString *)appID withVersion:(NSString *)version { * * Note that the v1 hash algorithm is not permitted on the client and cannot be fully validated. * - * @param appID Contents of GOOGLE_APP_ID from the plist file. + * @param appID Contents of GOOGLE_APP_ID from the config file. * @param version Indicates what version of the app id format this string should be. * @return YES if provided string fulfills the expected hashed bundle ID and the version is known, * NO otherwise. @@ -747,7 +747,7 @@ - (NSString *)expectedBundleID { // end App ID validation -#pragma mark - Reading From Plist & User Defaults +#pragma mark - Reading From Config file & User Defaults /** * Clears the data collection switch from the standard NSUserDefaults for easier testing and @@ -866,11 +866,11 @@ - (void)appDidBecomeActive:(NSNotification *)notification { } #if DEBUG -+ (void)findMisnamedGoogleServiceInfoPlist { ++ (void)findMisnamedJsonConfig { for (NSBundle *bundle in [NSBundle allBundles]) { // Not recursive, but we're looking for misnames, not people accidentally // hiding their config file in a subdirectory of their bundle. - NSArray *plistPaths = [bundle pathsForResourcesOfType:@"plist" inDirectory:nil]; + NSArray *plistPaths = [bundle pathsForResourcesOfType:@"json" inDirectory:nil]; for (NSString *path in plistPaths) { @autoreleasepool { NSDictionary *contents = [NSDictionary dictionaryWithContentsOfFile:path]; @@ -883,7 +883,7 @@ + (void)findMisnamedGoogleServiceInfoPlist { [NSException raise:kFirebaseCoreErrorDomain format:@"`FirebaseApp.configure()` could not find the default " @"configuration plist in your project, but did find one at " - @"%@. Please rename this file to GoogleService-Info.plist to " + @"%@. Please rename this file to firebase-sdk-config-apple.json to " @"use it as the default configuration.", path]; } diff --git a/FirebaseCore/Sources/FIRComponentContainer.m b/FirebaseCore/Sources/FIRComponentContainer.m index b70881cc2e3..3396d3deb1e 100644 --- a/FirebaseCore/Sources/FIRComponentContainer.m +++ b/FirebaseCore/Sources/FIRComponentContainer.m @@ -241,7 +241,7 @@ - (BOOL)isAppForARCore:(FIRApp *)app { p1[7], p2[7], p1[8], p2[8], p1[9], p2[9], p1[10], p2[10], p1[11], p2[11], p1[12], p2[12], '\0'}; NSString *gcmSenderID = [NSString stringWithUTF8String:gcmSenderIDKey]; - return [app.options.GCMSenderID isEqualToString:gcmSenderID]; + return [app.options.projectNumber isEqualToString:gcmSenderID]; } return NO; } diff --git a/FirebaseCore/Sources/FIROptions.m b/FirebaseCore/Sources/FIROptions.m index 4676a5737f1..ed6111ea6c1 100644 --- a/FirebaseCore/Sources/FIROptions.m +++ b/FirebaseCore/Sources/FIROptions.m @@ -36,6 +36,17 @@ NSString *const kFIRIsAnalyticsCollectionEnabled = @"FIREBASE_ANALYTICS_COLLECTION_ENABLED"; NSString *const kFIRIsAnalyticsCollectionDeactivated = @"FIREBASE_ANALYTICS_COLLECTION_DEACTIVATED"; +// Keys for the JSON config file +NSString *const kFIRJSONConfigVersion = @"version"; +NSString *const kFIRJSONConfigProjectNumber = @"project_number"; +NSString *const kFIRJSONConfigProjectID = @"project_id"; +NSString *const kFIRJSONConfigAppID = @"app_id"; +NSString *const kFIRJSONConfigBundleID = @"bundle_id"; +NSString *const kFIRJSONConfigApiKey = @"api_key"; +NSString *const kFIRJSONConfigRTDBURL = @"realtime_database_url"; +NSString *const kFIRJSONConfigStorageBucket = @"storage_bucket"; +NSString *const kFIRJSONConfigClientID = @"oauth_client_id"; + // Library version ID formatted like: // @"5" // Major version (one or more digits) // @"04" // Minor version (exactly 2 digits) @@ -48,6 +59,11 @@ // Plist file type. NSString *const kServiceInfoFileType = @"plist"; +// json file name. +NSString *const kJsonFileName = @"firebase-sdk-config-apple"; +// json file type. +NSString *const kJsonFileType = @"json"; + // Exception raised from attempting to modify a FIROptions after it's been copied to a FIRApp. NSString *const kFIRExceptionBadModification = @"Attempted to modify options after it's set on FIRApp. Please modify all properties before " @@ -62,11 +78,16 @@ @interface FIROptions () /** * Calls `analyticsOptionsDictionaryWithInfoDictionary:` using [NSBundle mainBundle].infoDictionary. - * It combines analytics options from both the infoDictionary and the GoogleService-Info.plist. + * It combines analytics options from both the infoDictionary and the config file. * Values which are present in the main plist override values from the GoogleService-Info.plist. */ @property(nonatomic, readonly) NSDictionary *analyticsOptionsDictionary; +/** + * Version of the config file. + */ +@property(nonatomic, readonly) NSInteger version; + /** * Combination of analytics options from both the infoDictionary and the GoogleService-Info.plist. * Values which are present in the infoDictionary override values from the GoogleService-Info.plist. @@ -108,34 +129,58 @@ + (FIROptions *)defaultOptions { + (NSDictionary *)defaultOptionsDictionary { dispatch_once(&sDefaultOptionsDictionaryOnceToken, ^{ - NSString *plistFilePath = [FIROptions plistFilePathWithName:kServiceInfoFileName]; - if (plistFilePath == nil) { + NSString *jsonFilePath = [FIROptions filePathWithName:kJsonFileName type:kJsonFileType]; + NSString *plistFilePath = [FIROptions filePathWithName:kServiceInfoFileName + type:kServiceInfoFileType]; + if (jsonFilePath == nil && plistFilePath == nil) { return; } - sDefaultOptionsDictionary = [NSDictionary dictionaryWithContentsOfFile:plistFilePath]; + if (jsonFilePath != nil && plistFilePath != nil) { + FIRLogError(kFIRLoggerCore, @"I-COR000015", + @"Found both '%@.%@' and '%@.%@'." + @"Ignoring the plist file and using the json file", + kJsonFileName, kJsonFileType, kServiceInfoFileName, kServiceInfoFileType); + } + if (jsonFilePath != nil) { + sDefaultOptionsDictionary = [self dictionaryFromJsonPath:jsonFilePath]; + } else { + sDefaultOptionsDictionary = [NSDictionary dictionaryWithContentsOfFile:plistFilePath]; + } if (sDefaultOptionsDictionary == nil) { FIRLogError(kFIRLoggerCore, @"I-COR000011", @"The configuration file is not a dictionary: " - @"'%@.%@'.", - kServiceInfoFileName, kServiceInfoFileType); + @"'%@'.", + plistFilePath); } }); return sDefaultOptionsDictionary; } -// Returns the path of the plist file with a given file name. -+ (NSString *)plistFilePathWithName:(NSString *)fileName { - NSArray *bundles = [FIRBundleUtil relevantBundles]; - NSString *plistFilePath = - [FIRBundleUtil optionsDictionaryPathWithResourceName:fileName - andFileType:kServiceInfoFileType - inBundles:bundles]; - if (plistFilePath == nil) { - FIRLogError(kFIRLoggerCore, @"I-COR000012", @"Could not locate configuration file: '%@.%@'.", - fileName, kServiceInfoFileType); +/// Generate the options dictionary from a JSON file. ++ (NSDictionary *)dictionaryFromJsonPath:(NSString *)path { + NSData *data = [NSData dataWithContentsOfFile:path]; + if (data == nil) { + return nil; } - return plistFilePath; + NSError *error; + NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data + options:kNilOptions + error:&error]; + if (error != nil) { + FIRLogError(kFIRLoggerCore, @"I-COR000018", @"Decoding JSON: %@ at path: '%@.", error, path); + return nil; + } + return dict; +} + +// Returns the path of the file with a given file name and file type. ++ (NSString *)filePathWithName:(NSString *)fileName type:(NSString *)fileType { + NSArray *bundles = [FIRBundleUtil relevantBundles]; + NSString *filePath = [FIRBundleUtil optionsDictionaryPathWithResourceName:fileName + andFileType:fileType + inBundles:bundles]; + return filePath; } + (void)resetDefaultOptions { @@ -152,6 +197,11 @@ - (instancetype)initInternalWithOptionsDictionary:(NSDictionary *)optionsDiction if (self) { _optionsDictionary = [optionsDictionary mutableCopy]; _usingOptionsFromDefaultPlist = YES; + if ([_optionsDictionary[kFIRJSONConfigVersion] isEqual:@"2"]) { + _version = 2; + } else { + _version = 1; + } } return self; } @@ -176,19 +226,30 @@ - (instancetype)init { return nil; } -- (instancetype)initWithContentsOfFile:(NSString *)plistPath { +- (instancetype)initWithContentsOfFile:(NSString *)path { self = [super init]; if (self) { - if (plistPath == nil) { - FIRLogError(kFIRLoggerCore, @"I-COR000013", @"The plist file path is nil."); + if (path == nil) { + FIRLogError(kFIRLoggerCore, @"I-COR000013", @"The file path is nil."); return nil; } - _optionsDictionary = [[NSDictionary dictionaryWithContentsOfFile:plistPath] mutableCopy]; + if ([path hasSuffix:@".json"]) { + _optionsDictionary = [[FIROptions dictionaryFromJsonPath:path] mutableCopy]; + if (![_optionsDictionary[kFIRJSONConfigVersion] isEqual:@"2"]) { + FIRLogError(kFIRLoggerCore, @"I-COR000016", + @"Only version 2 is currently supported for JSON config files"); + return nil; + } + _version = 2; + } else { + _optionsDictionary = [[NSDictionary dictionaryWithContentsOfFile:path] mutableCopy]; + _version = 1; + } if (_optionsDictionary == nil) { FIRLogError(kFIRLoggerCore, @"I-COR000014", @"The configuration file at %@ does not exist or " @"is not a well-formed plist file.", - plistPath); + path); return nil; } // TODO: Do we want to validate the dictionary here? It says we do that already in @@ -205,12 +266,34 @@ - (instancetype)initWithGoogleAppID:(NSString *)googleAppID GCMSenderID:(NSStrin [mutableOptionsDict setValue:GCMSenderID forKey:kFIRGCMSenderID]; [mutableOptionsDict setValue:[[NSBundle mainBundle] bundleIdentifier] forKey:kFIRBundleID]; self.optionsDictionary = mutableOptionsDict; + _version = 1; + } + return self; +} + +- (instancetype)initWithAppID:(NSString *)appID + projectNumber:(NSString *)projectNumber + projectID:(NSString *)projectID + apiKey:(NSString *)apiKey { + self = [super init]; + if (self) { + NSMutableDictionary *mutableOptionsDict = [NSMutableDictionary dictionary]; + [mutableOptionsDict setValue:appID forKey:kFIRJSONConfigAppID]; + [mutableOptionsDict setValue:projectNumber forKey:kFIRJSONConfigProjectNumber]; + [mutableOptionsDict setValue:projectID forKey:kFIRJSONConfigProjectID]; + [mutableOptionsDict setValue:apiKey forKey:kFIRJSONConfigApiKey]; + [mutableOptionsDict setValue:@"2" forKey:kFIRJSONConfigVersion]; + [mutableOptionsDict setValue:[[NSBundle mainBundle] bundleIdentifier] + forKey:kFIRJSONConfigBundleID]; + self.optionsDictionary = mutableOptionsDict; + _version = 2; } return self; } - (NSString *)APIKey { - return self.optionsDictionary[kFIRAPIKey]; + NSString *key = _version == 2 ? kFIRJSONConfigApiKey : kFIRAPIKey; + return self.optionsDictionary[key]; } - (void)checkEditingLocked { @@ -221,16 +304,19 @@ - (void)checkEditingLocked { - (void)setAPIKey:(NSString *)APIKey { [self checkEditingLocked]; - _optionsDictionary[kFIRAPIKey] = [APIKey copy]; + NSString *key = _version == 2 ? kFIRJSONConfigApiKey : kFIRAPIKey; + _optionsDictionary[key] = [APIKey copy]; } - (NSString *)clientID { - return self.optionsDictionary[kFIRClientID]; + NSString *key = _version == 2 ? kFIRJSONConfigClientID : kFIRClientID; + return self.optionsDictionary[key]; } - (void)setClientID:(NSString *)clientID { [self checkEditingLocked]; - _optionsDictionary[kFIRClientID] = [clientID copy]; + NSString *key = _version == 2 ? kFIRJSONConfigClientID : kFIRClientID; + _optionsDictionary[key] = [clientID copy]; } - (NSString *)trackingID { @@ -242,22 +328,34 @@ - (void)setTrackingID:(NSString *)trackingID { _optionsDictionary[kFIRTrackingID] = [trackingID copy]; } +- (NSString *)projectNumber { + NSString *key = _version == 2 ? kFIRJSONConfigProjectNumber : kFIRGCMSenderID; + return self.optionsDictionary[key]; +} + +- (void)setProjectNumber:(NSString *)projectNumber { + [self checkEditingLocked]; + NSString *key = _version == 2 ? kFIRJSONConfigProjectNumber : kFIRGCMSenderID; + _optionsDictionary[key] = [projectNumber copy]; +} + - (NSString *)GCMSenderID { - return self.optionsDictionary[kFIRGCMSenderID]; + return self.projectNumber; } - (void)setGCMSenderID:(NSString *)GCMSenderID { - [self checkEditingLocked]; - _optionsDictionary[kFIRGCMSenderID] = [GCMSenderID copy]; + [self setProjectNumber:GCMSenderID]; } - (NSString *)projectID { - return self.optionsDictionary[kFIRProjectID]; + NSString *key = _version == 2 ? kFIRJSONConfigProjectID : kFIRProjectID; + return self.optionsDictionary[key]; } - (void)setProjectID:(NSString *)projectID { [self checkEditingLocked]; - _optionsDictionary[kFIRProjectID] = [projectID copy]; + NSString *key = _version == 2 ? kFIRJSONConfigProjectID : kFIRProjectID; + _optionsDictionary[key] = [projectID copy]; } - (NSString *)androidClientID { @@ -270,12 +368,14 @@ - (void)setAndroidClientID:(NSString *)androidClientID { } - (NSString *)googleAppID { - return self.optionsDictionary[kFIRGoogleAppID]; + NSString *key = _version == 2 ? kFIRJSONConfigAppID : kFIRGoogleAppID; + return self.optionsDictionary[key]; } - (void)setGoogleAppID:(NSString *)googleAppID { [self checkEditingLocked]; - _optionsDictionary[kFIRGoogleAppID] = [googleAppID copy]; + NSString *key = _version == 2 ? kFIRJSONConfigAppID : kFIRGoogleAppID; + _optionsDictionary[key] = [googleAppID copy]; } - (NSString *)libraryVersionID { @@ -297,22 +397,25 @@ - (void)setLibraryVersionID:(NSString *)libraryVersionID { } - (NSString *)databaseURL { - return self.optionsDictionary[kFIRDatabaseURL]; + NSString *key = _version == 2 ? kFIRJSONConfigRTDBURL : kFIRDatabaseURL; + return self.optionsDictionary[key]; } - (void)setDatabaseURL:(NSString *)databaseURL { [self checkEditingLocked]; - - _optionsDictionary[kFIRDatabaseURL] = [databaseURL copy]; + NSString *key = _version == 2 ? kFIRJSONConfigRTDBURL : kFIRDatabaseURL; + _optionsDictionary[key] = [databaseURL copy]; } - (NSString *)storageBucket { - return self.optionsDictionary[kFIRStorageBucket]; + NSString *key = _version == 2 ? kFIRJSONConfigStorageBucket : kFIRStorageBucket; + return self.optionsDictionary[key]; } - (void)setStorageBucket:(NSString *)storageBucket { [self checkEditingLocked]; - _optionsDictionary[kFIRStorageBucket] = [storageBucket copy]; + NSString *key = _version == 2 ? kFIRJSONConfigStorageBucket : kFIRStorageBucket; + _optionsDictionary[key] = [storageBucket copy]; } - (void)setDeepLinkURLScheme:(NSString *)deepLinkURLScheme { @@ -321,12 +424,14 @@ - (void)setDeepLinkURLScheme:(NSString *)deepLinkURLScheme { } - (NSString *)bundleID { - return self.optionsDictionary[kFIRBundleID]; + NSString *key = _version == 2 ? kFIRJSONConfigBundleID : kFIRBundleID; + return self.optionsDictionary[key]; } - (void)setBundleID:(NSString *)bundleID { [self checkEditingLocked]; - _optionsDictionary[kFIRBundleID] = [bundleID copy]; + NSString *key = _version == 2 ? kFIRJSONConfigBundleID : kFIRBundleID; + _optionsDictionary[key] = [bundleID copy]; } - (void)setAppGroupID:(NSString *)appGroupID { diff --git a/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h b/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h index 8f8d945d765..c7791ead501 100644 --- a/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h +++ b/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h @@ -58,7 +58,13 @@ NS_SWIFT_NAME(FirebaseOptions) * The Project Number from the Google Developer's console, for example @"012345678901", used to * configure Firebase Cloud Messaging. */ -@property(nonatomic, copy) NSString *GCMSenderID NS_SWIFT_NAME(gcmSenderID); +@property(nonatomic, copy) NSString *projectNumber; + +/** + * The Project Number from the Google Developer's console, for example @"012345678901", used to + * configure Firebase Cloud Messaging. + */ +@property(nonatomic, copy) NSString *GCMSenderID NS_SWIFT_NAME(gcmSenderID) DEPRECATED_ATTRIBUTE; /** * The Project ID from the Firebase console, for example @"abc-xyz-123". @@ -98,30 +104,44 @@ NS_SWIFT_NAME(FirebaseOptions) @property(nonatomic, copy, nullable) NSString *appGroupID; /** - * Initializes a customized instance of FirebaseOptions from the file at the given plist file path. + * Initializes a customized instance of FirebaseOptions from the file at the given config file path. * This will read the file synchronously from disk. * For example: * ```swift - * if let path = Bundle.main.path(forResource:"GoogleServices-Info", ofType:"plist") { + * if let path = Bundle.main.path(forResource:"firebase-sdk-config-apple", ofType:"json") { * let options = FirebaseOptions(contentsOfFile: path) * } * ``` * Note that it is not possible to customize `FirebaseOptions` for Firebase Analytics which expects - * a static file named `GoogleServices-Info.plist` - + * a static file named `firebase-sdk-config-apple.json` - * https://github.com/firebase/firebase-ios-sdk/issues/230. - * Returns `nil` if the plist file does not exist or is invalid. + * Returns `nil` if the config file does not exist or is invalid. */ -- (nullable instancetype)initWithContentsOfFile:(NSString *)plistPath NS_DESIGNATED_INITIALIZER; +- (nullable instancetype)initWithContentsOfFile:(NSString *)configPath NS_DESIGNATED_INITIALIZER; /** * Initializes a customized instance of `FirebaseOptions` with required fields. Use the mutable * properties to modify fields for configuring specific services. Note that it is not possible to * customize `FirebaseOptions` for Firebase Analytics which expects a static file named - * `GoogleServices-Info.plist` - https://github.com/firebase/firebase-ios-sdk/issues/230. + * `firebase-sdk-config-apple.json` - https://github.com/firebase/firebase-ios-sdk/issues/230. */ - (instancetype)initWithGoogleAppID:(NSString *)googleAppID GCMSenderID:(NSString *)GCMSenderID - NS_SWIFT_NAME(init(googleAppID:gcmSenderID:))NS_DESIGNATED_INITIALIZER; + DEPRECATED_MSG_ATTRIBUTE( + "Deprecated API. Use `init(appID:projectNumber:projectID:apiKey:` instead") + NS_SWIFT_NAME(init(googleAppID:gcmSenderID:))NS_DESIGNATED_INITIALIZER; + +/** + * Initializes a customized instance of `FirebaseOptions` with required fields. Use the mutable + * properties to modify fields for configuring specific services. Note that it is not possible to + * customize `FirebaseOptions` for Firebase Analytics which expects a static file named + * `firebase-sdk-config-apple.json` - https://github.com/firebase/firebase-ios-sdk/issues/230. + */ +- (instancetype)initWithAppID:(NSString *)appID + projectNumber:(NSString *)projectNumber + projectID:(NSString *)projectID + apiKey:(NSString *)apiKey + NS_SWIFT_NAME(init(appID:projectNumber:projectID:apiKey:)) NS_DESIGNATED_INITIALIZER; /** Unavailable. Please use `init(contentsOfFile:)` or `init(googleAppID:gcmSenderID:)` instead. */ - (instancetype)init NS_UNAVAILABLE; diff --git a/FirebaseCore/Tests/SwiftUnit/CoreAPITests.swift b/FirebaseCore/Tests/SwiftUnit/CoreAPITests.swift index 8a0e1445263..2a3d657a263 100644 --- a/FirebaseCore/Tests/SwiftUnit/CoreAPITests.swift +++ b/FirebaseCore/Tests/SwiftUnit/CoreAPITests.swift @@ -101,7 +101,7 @@ final class CoreAPITests { } // FirebaseOptions initializers - _ = FirebaseOptions(googleAppID: "googleAppID", gcmSenderID: "gcmSenderID") + _ = FirebaseOptions(appID: "appID", projectNumber: "pno", projectID: "pid", apiKey: "api") if let _ /* options */ = FirebaseOptions(contentsOfFile: "path/to/file") { // ... @@ -110,7 +110,7 @@ final class CoreAPITests { // Properties if let options = FirebaseOptions.defaultOptions() { _ = options.bundleID - _ = options.gcmSenderID + _ = options.projectNumber _ = options.googleAppID if let _ /* apiKey */ = options.apiKey { diff --git a/FirebaseCore/Tests/SwiftUnit/FirebaseAppTests.swift b/FirebaseCore/Tests/SwiftUnit/FirebaseAppTests.swift index 61922fbe740..efb3c7cb10a 100644 --- a/FirebaseCore/Tests/SwiftUnit/FirebaseAppTests.swift +++ b/FirebaseCore/Tests/SwiftUnit/FirebaseAppTests.swift @@ -86,8 +86,7 @@ class FirebaseAppTests: XCTestCase { func testConfigureWithOptions() throws { expectAppConfigurationNotification(appName: Constants.App.defaultName, isDefaultApp: true) - let options = FirebaseOptions(googleAppID: Constants.Options.googleAppID, - gcmSenderID: Constants.Options.gcmSenderID) + let options = appOptions() options.clientID = Constants.Options.clientID let configurationAttempt = { try ExceptionCatcher.catchException { @@ -99,7 +98,7 @@ class FirebaseAppTests: XCTestCase { let app = try XCTUnwrap(FirebaseApp.app(), "Failed to unwrap default app") XCTAssertEqual(app.name, Constants.App.defaultName) XCTAssertEqual(app.options.googleAppID, Constants.Options.googleAppID) - XCTAssertEqual(app.options.gcmSenderID, Constants.Options.gcmSenderID) + XCTAssertEqual(app.options.projectNumber, Constants.Options.projectNumber) XCTAssertEqual(app.options.clientID, Constants.Options.clientID) XCTAssertTrue(FirebaseApp.allApps?.count == 1) @@ -109,8 +108,7 @@ class FirebaseAppTests: XCTestCase { func testConfigureWithNameAndOptions() throws { expectAppConfigurationNotification(appName: Constants.testAppName1, isDefaultApp: false) - let options = FirebaseOptions(googleAppID: Constants.Options.googleAppID, - gcmSenderID: Constants.Options.gcmSenderID) + let options = appOptions() options.clientID = Constants.Options.clientID let configurationAttempt = { @@ -126,7 +124,7 @@ class FirebaseAppTests: XCTestCase { ) XCTAssertEqual(app.name, Constants.testAppName1) XCTAssertEqual(app.options.googleAppID, Constants.Options.googleAppID) - XCTAssertEqual(app.options.gcmSenderID, Constants.Options.gcmSenderID) + XCTAssertEqual(app.options.projectNumber, Constants.Options.projectNumber) XCTAssertEqual(app.options.clientID, Constants.Options.clientID) XCTAssertTrue(FirebaseApp.allApps?.count == 1) @@ -142,8 +140,7 @@ class FirebaseAppTests: XCTestCase { } func testConfigureMultipleApps() throws { - let options1 = FirebaseOptions(googleAppID: Constants.Options.googleAppID, - gcmSenderID: Constants.Options.gcmSenderID) + let options1 = appOptions() options1.deepLinkURLScheme = Constants.Options.deepLinkURLScheme expectAppConfigurationNotification(appName: Constants.testAppName1, isDefaultApp: false) @@ -153,15 +150,13 @@ class FirebaseAppTests: XCTestCase { let app1 = try XCTUnwrap(FirebaseApp.app(name: Constants.testAppName1), "Failed to unwrap app1") XCTAssertEqual(app1.name, Constants.testAppName1) XCTAssertEqual(app1.options.googleAppID, Constants.Options.googleAppID) - XCTAssertEqual(app1.options.gcmSenderID, Constants.Options.gcmSenderID) + XCTAssertEqual(app1.options.projectNumber, Constants.Options.projectNumber) XCTAssertEqual(app1.options.deepLinkURLScheme, Constants.Options.deepLinkURLScheme) XCTAssertTrue(FirebaseApp.allApps?.count == 1) // Configure a different app with valid customized options. - let options2 = FirebaseOptions(googleAppID: Constants.Options.googleAppID, - gcmSenderID: Constants.Options.gcmSenderID) + let options2 = appOptions() options2.bundleID = Constants.Options.bundleID - options2.apiKey = Constants.Options.apiKey expectAppConfigurationNotification(appName: Constants.testAppName2, isDefaultApp: false) @@ -175,7 +170,7 @@ class FirebaseAppTests: XCTestCase { let app2 = try XCTUnwrap(FirebaseApp.app(name: Constants.testAppName2), "Failed to unwrap app2") XCTAssertEqual(app2.name, Constants.testAppName2) XCTAssertEqual(app2.options.googleAppID, Constants.Options.googleAppID) - XCTAssertEqual(app2.options.gcmSenderID, Constants.Options.gcmSenderID) + XCTAssertEqual(app2.options.projectNumber, Constants.Options.projectNumber) XCTAssertEqual(app2.options.bundleID, Constants.Options.bundleID) XCTAssertEqual(app2.options.apiKey, Constants.Options.apiKey) XCTAssertTrue(FirebaseApp.allApps?.count == 2) @@ -211,16 +206,14 @@ class FirebaseAppTests: XCTestCase { func testAllApps() throws { XCTAssertNil(FirebaseApp.allApps) - let options1 = FirebaseOptions(googleAppID: Constants.Options.googleAppID, - gcmSenderID: Constants.Options.gcmSenderID) + let options1 = appOptions() FirebaseApp.configure(name: Constants.testAppName1, options: options1) let app1 = try XCTUnwrap( FirebaseApp.app(name: Constants.testAppName1), "App1 could not be unwrapped" ) - let options2 = FirebaseOptions(googleAppID: Constants.Options.googleAppID, - gcmSenderID: Constants.Options.gcmSenderID) + let options2 = appOptions() FirebaseApp.configure(name: Constants.testAppName2, options: options2) let app2 = try XCTUnwrap( FirebaseApp.app(name: Constants.testAppName2), @@ -242,8 +235,7 @@ class FirebaseAppTests: XCTestCase { expectAppConfigurationNotification(appName: Constants.testAppName1, isDefaultApp: false) - let options = FirebaseOptions(googleAppID: Constants.Options.googleAppID, - gcmSenderID: Constants.Options.gcmSenderID) + let options = appOptions() FirebaseApp.configure(name: Constants.testAppName1, options: options) let app = try XCTUnwrap(FirebaseApp.app(name: Constants.testAppName1), "Could not unwrap app") @@ -269,8 +261,7 @@ class FirebaseAppTests: XCTestCase { func testGetNameOfApp() throws { XCTAssertNil(FirebaseApp.app(name: Constants.testAppName1)) - let options = FirebaseOptions(googleAppID: Constants.Options.googleAppID, - gcmSenderID: Constants.Options.gcmSenderID) + let options = appOptions() FirebaseApp.configure(name: Constants.testAppName1, options: options) let app = try XCTUnwrap( @@ -286,8 +277,7 @@ class FirebaseAppTests: XCTestCase { let defaultOptions = FirebaseOptions.defaultOptions() XCTAssertEqual(defaultApp.options, defaultOptions) - let options = FirebaseOptions(googleAppID: Constants.Options.googleAppID, - gcmSenderID: Constants.Options.gcmSenderID) + let options = appOptions() let superSecretURLScheme = "com.supersecret.googledeeplinkurl" options.deepLinkURLScheme = superSecretURLScheme FirebaseApp.configure(name: Constants.testAppName1, options: options) @@ -298,14 +288,12 @@ class FirebaseAppTests: XCTestCase { ) XCTAssertEqual(app.name, Constants.testAppName1) XCTAssertEqual(app.options.googleAppID, Constants.Options.googleAppID) - XCTAssertEqual(app.options.gcmSenderID, Constants.Options.gcmSenderID) + XCTAssertEqual(app.options.projectNumber, Constants.Options.projectNumber) XCTAssertEqual(app.options.deepLinkURLScheme, superSecretURLScheme) } func testFirebaseDataCollectionDefaultEnabled() throws { - let app = FirebaseApp(instanceWithName: "emptyApp", - options: FirebaseOptions(googleAppID: Constants.Options.googleAppID, - gcmSenderID: Constants.Options.gcmSenderID)) + let app = FirebaseApp(instanceWithName: "emptyApp", options: appOptions()) // defaults to true unless otherwise set to no in app's Info.plist XCTAssertTrue(app.isDataCollectionDefaultEnabled) @@ -356,4 +344,13 @@ class FirebaseAppTests: XCTestCase { NSDictionary(dictionary: userInfo) }) } + + private func appOptions() -> FirebaseOptions { + return FirebaseOptions( + appID: Constants.Options.googleAppID, + projectNumber: Constants.Options.projectNumber, + projectID: Constants.Options.projectID, + apiKey: Constants.Options.apiKey + ) + } } diff --git a/FirebaseCore/Tests/SwiftUnit/FirebaseOptionsTests.swift b/FirebaseCore/Tests/SwiftUnit/FirebaseOptionsTests.swift index 1de4a86d090..7b735b5035c 100644 --- a/FirebaseCore/Tests/SwiftUnit/FirebaseOptionsTests.swift +++ b/FirebaseCore/Tests/SwiftUnit/FirebaseOptionsTests.swift @@ -47,12 +47,16 @@ class FirebaseOptionsTests: XCTestCase { func testInitWithCustomFields() throws { let googleAppID = "5:678:ios:678def" - let gcmSenderID = "custom_gcm_sender_id" - let options = FirebaseOptions(googleAppID: googleAppID, - gcmSenderID: gcmSenderID) + let projectNumber = "custom_gcm_sender_id" + let options = FirebaseOptions( + appID: googleAppID, + projectNumber: projectNumber, + projectID: Constants.Options.projectID, + apiKey: Constants.Options.apiKey + ) XCTAssertEqual(options.googleAppID, googleAppID) - XCTAssertEqual(options.gcmSenderID, gcmSenderID) + XCTAssertEqual(options.projectNumber, projectNumber) let bundleID = try XCTUnwrap(Bundle.main.bundleIdentifier, "Could not retrieve bundle identifier") @@ -62,10 +66,7 @@ class FirebaseOptionsTests: XCTestCase { } func testCustomizedOptions() { - let googleAppID = Constants.Options.googleAppID - let gcmSenderID = Constants.Options.gcmSenderID - let options = FirebaseOptions(googleAppID: googleAppID, - gcmSenderID: gcmSenderID) + let options = appOptions() options.bundleID = Constants.Options.bundleID options.apiKey = Constants.Options.apiKey options.clientID = Constants.Options.clientID @@ -78,14 +79,11 @@ class FirebaseOptionsTests: XCTestCase { } func testEditingCustomOptions() { - let googleAppID = Constants.Options.googleAppID - let gcmSenderID = Constants.Options.gcmSenderID - let options = FirebaseOptions(googleAppID: googleAppID, - gcmSenderID: gcmSenderID) + let options = appOptions() - let newGCMSenderID = "newgcmSenderID" - options.gcmSenderID = newGCMSenderID - XCTAssertEqual(options.gcmSenderID, newGCMSenderID) + let newprojectNumber = "newprojectNumber" + options.projectNumber = newprojectNumber + XCTAssertEqual(options.projectNumber, newprojectNumber) let newGoogleAppID = "newGoogleAppID" options.googleAppID = newGoogleAppID @@ -101,10 +99,7 @@ class FirebaseOptionsTests: XCTestCase { } func testCopyingProperties() { - let googleAppID = Constants.Options.googleAppID - let gcmSenderID = Constants.Options.gcmSenderID - let options = FirebaseOptions(googleAppID: googleAppID, - gcmSenderID: gcmSenderID) + let options = appOptions() var apiKey = "123456789" options.apiKey = apiKey XCTAssertEqual(options.apiKey, apiKey) @@ -131,8 +126,7 @@ class FirebaseOptionsTests: XCTestCase { XCTAssertEqual(defaultOptions1.hash, defaultOptions2.hash) XCTAssertTrue(defaultOptions1.isEqual(defaultOptions2)) - let plainOptions = FirebaseOptions(googleAppID: Constants.Options.googleAppID, - gcmSenderID: Constants.Options.gcmSenderID) + let plainOptions = appOptions() XCTAssertFalse(plainOptions.isEqual(defaultOptions1)) } @@ -142,7 +136,7 @@ class FirebaseOptionsTests: XCTestCase { XCTAssertEqual(options.apiKey, Constants.Options.apiKey) XCTAssertEqual(options.bundleID, Constants.Options.bundleID) XCTAssertEqual(options.clientID, Constants.Options.clientID) - XCTAssertEqual(options.gcmSenderID, Constants.Options.gcmSenderID) + XCTAssertEqual(options.projectNumber, Constants.Options.projectNumber) XCTAssertEqual(options.projectID, Constants.Options.projectID) XCTAssertEqual(options.googleAppID, Constants.Options.googleAppID) XCTAssertEqual(options.databaseURL, Constants.Options.databaseURL) @@ -152,12 +146,19 @@ class FirebaseOptionsTests: XCTestCase { } private func assertNullableOptionsAreEmpty(options: FirebaseOptions) { - XCTAssertNil(options.apiKey) XCTAssertNil(options.clientID) - XCTAssertNil(options.projectID) XCTAssertNil(options.databaseURL) XCTAssertNil(options.deepLinkURLScheme) XCTAssertNil(options.storageBucket) XCTAssertNil(options.appGroupID) } + + private func appOptions() -> FirebaseOptions { + return FirebaseOptions( + appID: Constants.Options.googleAppID, + projectNumber: Constants.Options.projectNumber, + projectID: Constants.Options.projectID, + apiKey: Constants.Options.apiKey + ) + } } diff --git a/FirebaseCore/Tests/SwiftUnit/SwiftTestingUtilities/Constants.swift b/FirebaseCore/Tests/SwiftUnit/SwiftTestingUtilities/Constants.swift index cf6e5bf6530..8e3f141effb 100644 --- a/FirebaseCore/Tests/SwiftUnit/SwiftTestingUtilities/Constants.swift +++ b/FirebaseCore/Tests/SwiftUnit/SwiftTestingUtilities/Constants.swift @@ -24,7 +24,7 @@ public enum Constants { static let apiKey = "correct_api_key" static let bundleID = "com.google.FirebaseSDKTests" static let clientID = "correct_client_id" - static let gcmSenderID = "correct_gcm_sender_id" + static let projectNumber = "correct_gcm_sender_id" static let projectID = "abc-xyz-123" static let googleAppID = "1:123:ios:123abc" static let databaseURL = "https://abc-xyz-123.firebaseio.com" diff --git a/FirebaseCore/Tests/Unit/FIRAppTest.m b/FirebaseCore/Tests/Unit/FIRAppTest.m index b231e608b92..b2e8c273379 100644 --- a/FirebaseCore/Tests/Unit/FIRAppTest.m +++ b/FirebaseCore/Tests/Unit/FIRAppTest.m @@ -171,8 +171,7 @@ - (void)testConfigureWithOptions { userInfo:expectedUserInfo]; // Use a valid instance of options. - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options = [self appOptions]; options.clientID = kClientID; XCTAssertNoThrow([FIRApp configureWithOptions:options]); [self waitForExpectations:@[ notificationExpectation ] timeout:0.1]; @@ -182,14 +181,13 @@ - (void)testConfigureWithOptions { XCTAssertNotNil(app); XCTAssertEqualObjects(app.name, kFIRDefaultAppName); XCTAssertEqualObjects(app.options.googleAppID, kGoogleAppID); - XCTAssertEqualObjects(app.options.GCMSenderID, kGCMSenderID); + XCTAssertEqualObjects(app.options.GCMSenderID, kProjectNumber); XCTAssertEqualObjects(app.options.clientID, kClientID); XCTAssertTrue([FIRApp allApps].count == 1); } - (void)testConfigureWithNameAndOptions { - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options = [self appOptions]; options.clientID = kClientID; #pragma clang diagnostic push @@ -220,8 +218,7 @@ - (void)testConfigureWithNameAndOptions { } - (void)testConfigureWithMultipleApps { - FIROptions *options1 = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options1 = [self appOptions]; options1.deepLinkURLScheme = kDeepLinkURLScheme; NSDictionary *expectedUserInfo1 = [self expectedUserInfoWithAppName:kFIRTestAppName1 @@ -234,8 +231,7 @@ - (void)testConfigureWithMultipleApps { XCTAssertTrue([FIRApp allApps].count == 1); // Configure a different app with valid customized options. - FIROptions *options2 = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options2 = [self appOptions]; options2.bundleID = kBundleID; options2.APIKey = kCustomizedAPIKey; @@ -261,8 +257,7 @@ - (void)testConfigureWithMultipleApps { } - (void)testConfigureThrowsAfterConfigured { - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options = [self appOptions]; [FIRApp configureWithOptions:options]; XCTAssertNotNil([FIRApp defaultApp]); @@ -282,8 +277,7 @@ - (void)testConfigureDefaultAppInExtension { OCMStub([environmentMock isAppExtension]).andReturn(YES); // Set up the default app like a standard app. - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options = [self appOptions]; [FIRApp configureWithOptions:options]; XCTAssertNotNil([FIRApp defaultApp]); XCTAssertEqual([FIRApp allApps].count, 1); @@ -297,7 +291,7 @@ - (void)testConfigureDefaultAppInExtension { // Use a set of a different options to call configure again, which should throw. FIROptions *differentOptions = [[FIROptions alloc] initWithGoogleAppID:@"1:789:ios:789XYZ" - GCMSenderID:kGCMSenderID]; + GCMSenderID:kProjectNumber]; XCTAssertThrows([FIRApp configureWithOptions:differentOptions]); XCTAssertEqual([FIRApp allApps].count, 1); @@ -311,8 +305,7 @@ - (void)testConfigureCustomAppInExtension { OCMStub([environmentMock isAppExtension]).andReturn(YES); // Set up a custom named app like a standard app. - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options = [self appOptions]; [FIRApp configureWithName:kFIRTestAppName1 options:options]; XCTAssertNotNil([FIRApp appNamed:kFIRTestAppName1]); XCTAssertEqual([FIRApp allApps].count, 1); @@ -326,7 +319,7 @@ - (void)testConfigureCustomAppInExtension { // Use a set of a different options to call configure again, which should throw. FIROptions *differentOptions = [[FIROptions alloc] initWithGoogleAppID:@"1:789:ios:789XYZ" - GCMSenderID:kGCMSenderID]; + GCMSenderID:kProjectNumber]; XCTAssertThrows([FIRApp configureWithName:kFIRTestAppName1 options:differentOptions]); XCTAssertEqual([FIRApp allApps].count, 1); @@ -370,8 +363,7 @@ - (void)testDeleteApp { ]]; NSString *name = NSStringFromSelector(_cmd); - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options = [self appOptions]; [FIRApp configureWithName:name options:options]; FIRApp *app = [FIRApp appNamed:name]; XCTAssertNotNil(app); @@ -405,8 +397,7 @@ - (void)testDeleteApp { } - (void)testOptionsLocking { - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options = [self appOptions]; options.projectID = kProjectID; options.databaseURL = kDatabaseURL; @@ -614,8 +605,7 @@ - (void)testAppIDContainsInvalidBundleIDHash { - (void)testGlobalDataCollectionNoFlags { // Test: No flags set. NSString *name = NSStringFromSelector(_cmd); - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options = [self appOptions]; FIRApp *app = [[FIRApp alloc] initInstanceWithName:name options:options]; OCMStub([self.appClassMock readDataCollectionSwitchFromPlist]).andReturn(nil); OCMStub([self.appClassMock readDataCollectionSwitchFromUserDefaultsForApp:OCMOCK_ANY]) @@ -627,8 +617,7 @@ - (void)testGlobalDataCollectionNoFlags { - (void)testGlobalDataCollectionPlistSetEnabled { // Test: Plist set to enabled, no override. NSString *name = NSStringFromSelector(_cmd); - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options = [self appOptions]; FIRApp *app = [[FIRApp alloc] initInstanceWithName:name options:options]; OCMStub([self.appClassMock readDataCollectionSwitchFromPlist]).andReturn(@YES); OCMStub([self.appClassMock readDataCollectionSwitchFromUserDefaultsForApp:OCMOCK_ANY]) @@ -640,8 +629,7 @@ - (void)testGlobalDataCollectionPlistSetEnabled { - (void)testGlobalDataCollectionPlistSetDisabled { // Test: Plist set to disabled, no override. NSString *name = NSStringFromSelector(_cmd); - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options = [self appOptions]; FIRApp *app = [[FIRApp alloc] initInstanceWithName:name options:options]; OCMStub([self.appClassMock readDataCollectionSwitchFromPlist]).andReturn(@NO); OCMStub([self.appClassMock readDataCollectionSwitchFromUserDefaultsForApp:OCMOCK_ANY]) @@ -653,8 +641,7 @@ - (void)testGlobalDataCollectionPlistSetDisabled { - (void)testGlobalDataCollectionUserSpecifiedEnabled { // Test: User specified as enabled, no plist value. NSString *name = NSStringFromSelector(_cmd); - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options = [self appOptions]; FIRApp *app = [[FIRApp alloc] initInstanceWithName:name options:options]; OCMStub([self.appClassMock readDataCollectionSwitchFromPlist]).andReturn(nil); OCMStub([self.appClassMock readDataCollectionSwitchFromUserDefaultsForApp:OCMOCK_ANY]) @@ -666,8 +653,7 @@ - (void)testGlobalDataCollectionUserSpecifiedEnabled { - (void)testGlobalDataCollectionUserSpecifiedDisabled { // Test: User specified as disabled, no plist value. NSString *name = NSStringFromSelector(_cmd); - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options = [self appOptions]; FIRApp *app = [[FIRApp alloc] initInstanceWithName:name options:options]; OCMStub([self.appClassMock readDataCollectionSwitchFromPlist]).andReturn(nil); OCMStub([self.appClassMock readDataCollectionSwitchFromUserDefaultsForApp:OCMOCK_ANY]) @@ -679,8 +665,7 @@ - (void)testGlobalDataCollectionUserSpecifiedDisabled { - (void)testGlobalDataCollectionUserOverriddenEnabled { // Test: User specified as enabled, with plist set as disabled. NSString *name = NSStringFromSelector(_cmd); - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options = [self appOptions]; FIRApp *app = [[FIRApp alloc] initInstanceWithName:name options:options]; OCMStub([self.appClassMock readDataCollectionSwitchFromPlist]).andReturn(@NO); OCMStub([self.appClassMock readDataCollectionSwitchFromUserDefaultsForApp:OCMOCK_ANY]) @@ -692,8 +677,8 @@ - (void)testGlobalDataCollectionUserOverriddenEnabled { - (void)testGlobalDataCollectionUserOverriddenDisabled { // Test: User specified as disabled, with plist set as enabled. NSString *name = NSStringFromSelector(_cmd); - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options = [self appOptions]; + ; FIRApp *app = [[FIRApp alloc] initInstanceWithName:name options:options]; OCMStub([self.appClassMock readDataCollectionSwitchFromPlist]).andReturn(@YES); OCMStub([self.appClassMock readDataCollectionSwitchFromUserDefaultsForApp:OCMOCK_ANY]) @@ -705,8 +690,7 @@ - (void)testGlobalDataCollectionUserOverriddenDisabled { - (void)testGlobalDataCollectionWriteToDefaults { id defaultsMock = OCMPartialMock([NSUserDefaults standardUserDefaults]); NSString *name = NSStringFromSelector(_cmd); - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options = [self appOptions]; [FIRApp configureWithName:name options:options]; FIRApp *app = [FIRApp appNamed:name]; app.dataCollectionDefaultEnabled = YES; @@ -723,8 +707,7 @@ - (void)testGlobalDataCollectionWriteToDefaults { - (void)testGlobalDataCollectionClearedAfterDelete { // Configure and disable data collection for the default FIRApp. NSString *name = NSStringFromSelector(_cmd); - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options = [self appOptions]; [FIRApp configureWithName:name options:options]; FIRApp *app = [FIRApp appNamed:name]; app.dataCollectionDefaultEnabled = NO; @@ -747,8 +730,7 @@ - (void)testGlobalDataCollectionClearedAfterDelete { } - (void)testGlobalDataCollectionNoDiagnosticsSent { - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options = [self appOptions]; FIRApp *app = [[FIRApp alloc] initInstanceWithName:NSStringFromSelector(_cmd) options:options]; app.dataCollectionDefaultEnabled = NO; @@ -883,7 +865,10 @@ - (FIRApp *)createConfiguredAppWithName:(NSString *)name { } - (FIROptions *)appOptions { - return [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID GCMSenderID:kGCMSenderID]; + return [[FIROptions alloc] initWithAppID:kGoogleAppID + projectNumber:kProjectNumber + projectID:kProjectID + apiKey:kAPIKey]; } - (void)registerLibrariesWithClasses:(NSArray *)classes { diff --git a/FirebaseCore/Tests/Unit/FIRComponentContainerTest.m b/FirebaseCore/Tests/Unit/FIRComponentContainerTest.m index 7b2d8cacf01..507ffa80a2b 100644 --- a/FirebaseCore/Tests/Unit/FIRComponentContainerTest.m +++ b/FirebaseCore/Tests/Unit/FIRComponentContainerTest.m @@ -223,8 +223,10 @@ - (void)testDependencyRemoveAllCachedInstancesDoesntBlock { /// Create a container that has registered the test class. - (FIRComponentContainer *)containerWithRegistrants:(NSArray *)registrants { - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options = [[FIROptions alloc] initWithAppID:kGoogleAppID + projectNumber:kProjectNumber + projectID:kProjectID + apiKey:kAPIKey]; _hostApp = [[FIRApp alloc] initInstanceWithName:@"fake_app" options:options]; NSMutableSet *allRegistrants = [NSMutableSet set]; diff --git a/FirebaseCore/Tests/Unit/FIROptionsTest.m b/FirebaseCore/Tests/Unit/FIROptionsTest.m index fd5c901598f..75f1dd9e70c 100644 --- a/FirebaseCore/Tests/Unit/FIROptionsTest.m +++ b/FirebaseCore/Tests/Unit/FIROptionsTest.m @@ -47,7 +47,7 @@ - (void)testInit { [FIROptionsMock mockFIROptions]; NSDictionary *optionsDictionary = [FIROptions defaultOptionsDictionary]; FIROptions *options = [[FIROptions alloc] initInternalWithOptionsDictionary:optionsDictionary]; - [self assertOptionsMatchDefaults:options andProjectID:YES]; + [self assertOptionsMatchDefaults:options]; XCTAssertNil(options.deepLinkURLScheme); XCTAssertTrue(options.usingOptionsFromDefaultPlist); @@ -57,8 +57,8 @@ - (void)testInit { - (void)testDefaultOptionsDictionaryWithNilFilePath { id mockBundleUtil = OCMClassMock([FIRBundleUtil class]); - OCMStub([mockBundleUtil optionsDictionaryPathWithResourceName:kServiceInfoFileName - andFileType:kServiceInfoFileType + OCMStub([mockBundleUtil optionsDictionaryPathWithResourceName:kJsonFileName + andFileType:kJsonFileType inBundles:[FIRBundleUtil relevantBundles]]) .andReturn(nil); XCTAssertNil([FIROptions defaultOptionsDictionary]); @@ -66,8 +66,8 @@ - (void)testDefaultOptionsDictionaryWithNilFilePath { - (void)testDefaultOptionsDictionaryWithInvalidSourceFile { id mockBundleUtil = OCMClassMock([FIRBundleUtil class]); - OCMStub([mockBundleUtil optionsDictionaryPathWithResourceName:kServiceInfoFileName - andFileType:kServiceInfoFileType + OCMStub([mockBundleUtil optionsDictionaryPathWithResourceName:kJsonFileName + andFileType:kJsonFileType inBundles:[FIRBundleUtil relevantBundles]]) .andReturn(@"invalid.plist"); XCTAssertNil([FIROptions defaultOptionsDictionary]); @@ -76,7 +76,7 @@ - (void)testDefaultOptionsDictionaryWithInvalidSourceFile { - (void)testDefaultOptions { [FIROptionsMock mockFIROptions]; FIROptions *options = [FIROptions defaultOptions]; - [self assertOptionsMatchDefaults:options andProjectID:YES]; + [self assertOptionsMatchDefaults:options]; XCTAssertNil(options.deepLinkURLScheme); XCTAssertTrue(options.usingOptionsFromDefaultPlist); @@ -88,7 +88,7 @@ - (void)testDefaultOptions { // Another strategy is needed for these tests to pass with SWIFT_PACKAGE, since the mocking // prevents the file path traversals. -- (void)testDefaultOptionsAreInitializedOnce { +- (void)testDefaultOptionsAreInitializedOncePlist { id mockBundleUtil = OCMClassMock([FIRBundleUtil class]); OCMExpect([mockBundleUtil optionsDictionaryPathWithResourceName:kServiceInfoFileName andFileType:kServiceInfoFileType @@ -104,7 +104,23 @@ - (void)testDefaultOptionsAreInitializedOnce { OCMVerifyAll(mockBundleUtil); } -- (void)testDefaultOptionsDictionaryIsInitializedOnce { +- (void)testDefaultOptionsAreInitializedOnceJson { + id mockBundleUtil = OCMClassMock([FIRBundleUtil class]); + OCMExpect([mockBundleUtil optionsDictionaryPathWithResourceName:kJsonFileName + andFileType:kJsonFileType + inBundles:[FIRBundleUtil relevantBundles]]) + .andReturn([self validJsonConfigPath]); + XCTAssertNotNil([FIROptions defaultOptions]); + OCMVerifyAll(mockBundleUtil); + + OCMReject([mockBundleUtil optionsDictionaryPathWithResourceName:OCMOCK_ANY + andFileType:OCMOCK_ANY + inBundles:OCMOCK_ANY]); + XCTAssertNotNil([FIROptions defaultOptions]); + OCMVerifyAll(mockBundleUtil); +} + +- (void)testDefaultOptionsDictionaryIsInitializedOncePlist { id mockBundleUtil = OCMClassMock([FIRBundleUtil class]); OCMExpect([mockBundleUtil optionsDictionaryPathWithResourceName:kServiceInfoFileName andFileType:kServiceInfoFileType @@ -120,10 +136,26 @@ - (void)testDefaultOptionsDictionaryIsInitializedOnce { OCMVerifyAll(mockBundleUtil); } -- (void)testInitWithContentsOfFile { +- (void)testDefaultOptionsDictionaryIsInitializedOnceJson { + id mockBundleUtil = OCMClassMock([FIRBundleUtil class]); + OCMExpect([mockBundleUtil optionsDictionaryPathWithResourceName:kJsonFileName + andFileType:kJsonFileType + inBundles:[FIRBundleUtil relevantBundles]]) + .andReturn([self validJsonConfigPath]); + XCTAssertNotNil([FIROptions defaultOptionsDictionary]); + OCMVerifyAll(mockBundleUtil); + + OCMReject([mockBundleUtil optionsDictionaryPathWithResourceName:OCMOCK_ANY + andFileType:OCMOCK_ANY + inBundles:OCMOCK_ANY]); + XCTAssertNotNil([FIROptions defaultOptionsDictionary]); + OCMVerifyAll(mockBundleUtil); +} + +- (void)testInitWithContentsOfPlistFile { NSString *filePath = [self validGoogleServicesInfoPlistPath]; FIROptions *options = [[FIROptions alloc] initWithContentsOfFile:filePath]; - [self assertOptionsMatchDefaults:options andProjectID:YES]; + [self assertOptionsMatchDefaults:options]; XCTAssertNil(options.deepLinkURLScheme); XCTAssertFalse(options.usingOptionsFromDefaultPlist); @@ -136,11 +168,27 @@ - (void)testInitWithContentsOfFile { FIROptions *invalidOptions = [[FIROptions alloc] initWithContentsOfFile:@"invalid.plist"]; XCTAssertNil(invalidOptions); } + +- (void)testInitWithContentsOfJsonFile { + NSString *filePath = [self validJsonConfigPath]; + FIROptions *options = [[FIROptions alloc] initWithContentsOfFile:filePath]; + [self assertOptionsMatchDefaults:options]; + XCTAssertNil(options.deepLinkURLScheme); + XCTAssertFalse(options.usingOptionsFromDefaultPlist); + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnonnull" + FIROptions *emptyOptions = [[FIROptions alloc] initWithContentsOfFile:nil]; +#pragma clang diagnostic pop + XCTAssertNil(emptyOptions); + + FIROptions *invalidOptions = [[FIROptions alloc] initWithContentsOfFile:@"invalid.json"]; + XCTAssertNil(invalidOptions); +} #endif -- (void)testInitCustomizedOptions { - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; +- (void)testInitCustomizedOptionsPlist { + FIROptions *options = [self oldAppOptions]; options.APIKey = kAPIKey; options.bundleID = kBundleID; options.clientID = kClientID; @@ -148,32 +196,92 @@ - (void)testInitCustomizedOptions { options.deepLinkURLScheme = kDeepLinkURLScheme; options.projectID = kProjectID; options.storageBucket = kStorageBucket; - [self assertOptionsMatchDefaults:options andProjectID:YES]; + [self assertOptionsMatchDefaults:options]; + XCTAssertEqualObjects(options.deepLinkURLScheme, kDeepLinkURLScheme); + XCTAssertFalse(options.usingOptionsFromDefaultPlist); +} + +- (void)testInitCustomizedOptionsJson { + FIROptions *options = [self appOptions]; + options.bundleID = kBundleID; + options.clientID = kClientID; + options.databaseURL = kDatabaseURL; + options.deepLinkURLScheme = kDeepLinkURLScheme; + options.storageBucket = kStorageBucket; + [self assertOptionsMatchDefaults:options]; XCTAssertEqualObjects(options.deepLinkURLScheme, kDeepLinkURLScheme); XCTAssertFalse(options.usingOptionsFromDefaultPlist); } -- (void)assertOptionsMatchDefaults:(FIROptions *)options andProjectID:(BOOL)matchProjectID { +- (void)assertOptionsMatchDefaults:(FIROptions *)options { XCTAssertEqualObjects(options.googleAppID, kGoogleAppID); XCTAssertEqualObjects(options.APIKey, kAPIKey); XCTAssertEqualObjects(options.clientID, kClientID); - XCTAssertEqualObjects(options.GCMSenderID, kGCMSenderID); + XCTAssertEqualObjects(options.GCMSenderID, kProjectNumber); XCTAssertEqualObjects(options.libraryVersionID, kFIRLibraryVersionID); XCTAssertEqualObjects(options.databaseURL, kDatabaseURL); XCTAssertEqualObjects(options.storageBucket, kStorageBucket); XCTAssertEqualObjects(options.bundleID, kBundleID); + XCTAssertEqualObjects(options.projectID, kProjectID); +} - // Custom `matchProjectID` parameter to be removed once the deprecated `FIROptions` constructor is - // removed. - if (matchProjectID) { - XCTAssertEqualObjects(options.projectID, kProjectID); - } +- (void)testCopyingPropertiesPlist { + NSMutableString *mutableString; + FIROptions *options = [self appOptions]; + mutableString = [[NSMutableString alloc] initWithString:@"1"]; + options.APIKey = mutableString; + [mutableString appendString:@"2"]; + XCTAssertEqualObjects(options.APIKey, @"1"); + + mutableString = [[NSMutableString alloc] initWithString:@"1"]; + options.bundleID = mutableString; + [mutableString appendString:@"2"]; + XCTAssertEqualObjects(options.bundleID, @"1"); + + mutableString = [[NSMutableString alloc] initWithString:@"1"]; + options.clientID = mutableString; + [mutableString appendString:@"2"]; + XCTAssertEqualObjects(options.clientID, @"1"); + + mutableString = [[NSMutableString alloc] initWithString:@"1"]; + options.GCMSenderID = mutableString; + [mutableString appendString:@"2"]; + XCTAssertEqualObjects(options.GCMSenderID, @"1"); + + mutableString = [[NSMutableString alloc] initWithString:@"1"]; + options.projectID = mutableString; + [mutableString appendString:@"2"]; + XCTAssertEqualObjects(options.projectID, @"1"); + + mutableString = [[NSMutableString alloc] initWithString:@"1"]; + options.googleAppID = mutableString; + [mutableString appendString:@"2"]; + XCTAssertEqualObjects(options.googleAppID, @"1"); + + mutableString = [[NSMutableString alloc] initWithString:@"1"]; + options.databaseURL = mutableString; + [mutableString appendString:@"2"]; + XCTAssertEqualObjects(options.databaseURL, @"1"); + + mutableString = [[NSMutableString alloc] initWithString:@"1"]; + options.deepLinkURLScheme = mutableString; + [mutableString appendString:@"2"]; + XCTAssertEqualObjects(options.deepLinkURLScheme, @"1"); + + mutableString = [[NSMutableString alloc] initWithString:@"1"]; + options.storageBucket = mutableString; + [mutableString appendString:@"2"]; + XCTAssertEqualObjects(options.storageBucket, @"1"); + + mutableString = [[NSMutableString alloc] initWithString:@"1"]; + options.appGroupID = mutableString; + [mutableString appendString:@"2"]; + XCTAssertEqualObjects(options.appGroupID, @"1"); } -- (void)testCopyingProperties { +- (void)testCopyingPropertiesJSON { NSMutableString *mutableString; - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options = [self appOptions]; mutableString = [[NSMutableString alloc] initWithString:@"1"]; options.APIKey = mutableString; [mutableString appendString:@"2"]; @@ -239,14 +347,21 @@ - (void)testCopyWithZone { XCTAssertEqualObjects(options.deepLinkURLScheme, kNewDeepLinkURLScheme); XCTAssertEqualObjects(newOptions.deepLinkURLScheme, kDeepLinkURLScheme); - // customized options - FIROptions *customizedOptions = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + // customized options with plist + FIROptions *customizedOptions = [self oldAppOptions]; customizedOptions.deepLinkURLScheme = kDeepLinkURLScheme; FIROptions *copyCustomizedOptions = [customizedOptions copy]; [copyCustomizedOptions setDeepLinkURLScheme:kNewDeepLinkURLScheme]; XCTAssertEqualObjects(customizedOptions.deepLinkURLScheme, kDeepLinkURLScheme); XCTAssertEqualObjects(copyCustomizedOptions.deepLinkURLScheme, kNewDeepLinkURLScheme); + + // customized options with json + FIROptions *customizedOptionsJSON = [self appOptions]; + customizedOptionsJSON.deepLinkURLScheme = kDeepLinkURLScheme; + FIROptions *copyCustomizedOptionsJSON = [customizedOptionsJSON copy]; + [copyCustomizedOptionsJSON setDeepLinkURLScheme:kNewDeepLinkURLScheme]; + XCTAssertEqualObjects(customizedOptionsJSON.deepLinkURLScheme, kDeepLinkURLScheme); + XCTAssertEqualObjects(copyCustomizedOptionsJSON.deepLinkURLScheme, kNewDeepLinkURLScheme); } - (void)testAnalyticsConstants { @@ -579,8 +694,7 @@ - (void)testAnalyticsCollectionExplicitlySet { } - (void)testModifyingOptionsThrows { - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options = [self appOptions]; options.editingLocked = YES; // Modification to every property should result in an exception. @@ -597,8 +711,7 @@ - (void)testModifyingOptionsThrows { - (void)testVersionFormat { // `kFIRLibraryVersionID` is `nil` until `libraryVersion` is called on `FIROptions`. - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options = [self appOptions]; __unused NSString *libraryVersion = options.libraryVersionID; options = nil; @@ -613,8 +726,7 @@ - (void)testVersionFormat { - (void)testVersionConsistency { // `kFIRLibraryVersionID` is `nil` until `libraryVersion` is called on `FIROptions`. - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options = [self appOptions]; __unused NSString *libraryVersion = options.libraryVersionID; options = nil; @@ -630,8 +742,7 @@ - (void)testVersionConsistency { // Repeat test with more Objective-C. - (void)testVersionConsistency2 { // `kFIRLibraryVersionID` is `nil` until `libraryVersion` is called on `FIROptions`. - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; + FIROptions *options = [self appOptions]; __unused NSString *libraryVersion = options.libraryVersionID; options = nil; @@ -660,4 +771,30 @@ - (NSString *)validGoogleServicesInfoPlistPath { return filePath; } +- (NSString *)validJsonConfigPath { + NSString *filePath = [[NSBundle mainBundle] pathForResource:@"firebase-sdk-config-apple" + ofType:@"json"]; + if (filePath == nil) { + // Use bundleForClass to allow GoogleService-Info.plist to be in the test target's bundle. + NSBundle *bundle = [NSBundle bundleForClass:[self class]]; + filePath = [bundle pathForResource:@"firebase-sdk-config-apple" ofType:@"json"]; + } + + XCTAssertNotNil(filePath); + return filePath; +} + +- (FIROptions *)appOptions { + return [[FIROptions alloc] initWithAppID:kGoogleAppID + projectNumber:kProjectNumber + projectID:kProjectID + apiKey:kAPIKey]; +} + +- (FIROptions *)oldAppOptions { +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + return [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID GCMSenderID:kProjectNumber]; +#pragma clang diagnostic pop +} + @end diff --git a/FirebaseCore/Tests/Unit/Resources/firebase-sdk-config-apple.json b/FirebaseCore/Tests/Unit/Resources/firebase-sdk-config-apple.json new file mode 100644 index 00000000000..2321a1edde9 --- /dev/null +++ b/FirebaseCore/Tests/Unit/Resources/firebase-sdk-config-apple.json @@ -0,0 +1,12 @@ +{ + "version": "2", + "project_number": "correct_gcm_sender_id", + "project_id": "abc-xyz-123", + "app_id": "1:123:ios:123abc", + "bundle_id": "com.google.FirebaseSDKTests", + "api_key": "correct_api_key", + "realtime_database_url": "https://abc-xyz-123.firebaseio.com", + "storage_bucket": "project-id-123.storage.firebase.com", + "measurement_id": "Test-measurement-id", + "oauth_client_id": "correct_client_id" +} \ No newline at end of file diff --git a/FirebaseDynamicLinks/Sources/FIRDynamicLinks.m b/FirebaseDynamicLinks/Sources/FIRDynamicLinks.m index 7b340e6a9d6..fc0341b251a 100644 --- a/FirebaseDynamicLinks/Sources/FIRDynamicLinks.m +++ b/FirebaseDynamicLinks/Sources/FIRDynamicLinks.m @@ -168,7 +168,7 @@ - (void)configureDynamicLinks:(FIRApp *)app { if (error) { NSString *message = nil; if (options.usingOptionsFromDefaultPlist) { - // Configured using plist file + // Configured using config file message = [NSString stringWithFormat: @"Firebase Dynamic Links has stopped your project " diff --git a/FirebaseRemoteConfig/Tests/Unit/RCNRemoteConfig+FIRAppTest.m b/FirebaseRemoteConfig/Tests/Unit/RCNRemoteConfig+FIRAppTest.m index 0d65190403c..f6d716409f5 100644 --- a/FirebaseRemoteConfig/Tests/Unit/RCNRemoteConfig+FIRAppTest.m +++ b/FirebaseRemoteConfig/Tests/Unit/RCNRemoteConfig+FIRAppTest.m @@ -37,7 +37,7 @@ - (void)testConfigureConfigWithValidInput { XCTAssertNoThrow([FIRApp configure]); FIRRemoteConfig *rc = [FIRRemoteConfig remoteConfig]; XCTAssertEqualObjects(rc.GMPProjectID, kGoogleAppID); - XCTAssertEqualObjects(rc.senderID, kGCMSenderID); + XCTAssertEqualObjects(rc.senderID, kProjectNumber); } - (void)testConfigureConfigWithEmptyGoogleAppID { @@ -98,7 +98,7 @@ - (void)testConfigureWithMultipleProjects { XCTAssertNoThrow([FIRApp configure]); FIRRemoteConfig *rc = [FIRRemoteConfig remoteConfig]; XCTAssertEqualObjects(rc.GMPProjectID, kGoogleAppID); - XCTAssertEqualObjects(rc.senderID, kGCMSenderID); + XCTAssertEqualObjects(rc.senderID, kProjectNumber); FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:@"1:966600170131:ios:a750b5ff97fbf47d" @@ -106,7 +106,7 @@ - (void)testConfigureWithMultipleProjects { [FIRApp configureWithName:@"nonDefault" options:options]; XCTAssertEqualObjects(rc.GMPProjectID, kGoogleAppID); - XCTAssertEqualObjects(rc.senderID, kGCMSenderID); + XCTAssertEqualObjects(rc.senderID, kProjectNumber); } @end diff --git a/SharedTestUtilities/FIROptionsMock.h b/SharedTestUtilities/FIROptionsMock.h index 59707c00434..4bcc48ce17c 100644 --- a/SharedTestUtilities/FIROptionsMock.h +++ b/SharedTestUtilities/FIROptionsMock.h @@ -22,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN extern NSString *const kAPIKey; extern NSString *const kCustomizedAPIKey; extern NSString *const kClientID; -extern NSString *const kGCMSenderID; +extern NSString *const kProjectNumber; extern NSString *const kGoogleAppID; extern NSString *const kDatabaseURL; extern NSString *const kStorageBucket; diff --git a/SharedTestUtilities/FIROptionsMock.m b/SharedTestUtilities/FIROptionsMock.m index 8002fa867db..dc3a209d89c 100644 --- a/SharedTestUtilities/FIROptionsMock.m +++ b/SharedTestUtilities/FIROptionsMock.m @@ -20,7 +20,7 @@ NSString *const kAPIKey = @"correct_api_key"; NSString *const kCustomizedAPIKey = @"customized_api_key"; NSString *const kClientID = @"correct_client_id"; -NSString *const kGCMSenderID = @"correct_gcm_sender_id"; +NSString *const kProjectNumber = @"correct_gcm_sender_id"; NSString *const kGoogleAppID = @"1:123:ios:123abc"; NSString *const kDatabaseURL = @"https://abc-xyz-123.firebaseio.com"; NSString *const kStorageBucket = @"project-id-123.storage.firebase.com"; @@ -44,7 +44,7 @@ + (void)mockFIROptions { kFIRBundleID : kBundleID, kFIRClientID : kClientID, kFIRDatabaseURL : kDatabaseURL, - kFIRGCMSenderID : kGCMSenderID, + kFIRGCMSenderID : kProjectNumber, kFIRGoogleAppID : kGoogleAppID, kFIRProjectID : kProjectID, kFIRStorageBucket : kStorageBucket,