Skip to content
Merged
2 changes: 1 addition & 1 deletion Firebase.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ Simplify your iOS development, grow your user base, and monetize more effectivel

s.subspec 'Auth' do |ss|
ss.dependency 'Firebase/CoreOnly'
ss.dependency 'FirebaseAuth', '~> 6.4.3'
ss.dependency 'FirebaseAuth', '~> 6.5.0'
end

s.subspec 'Crashlytics' do |ss|
Expand Down
3 changes: 2 additions & 1 deletion FirebaseRemoteConfig.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ app update.
s.dependency 'FirebaseAnalyticsInterop', '~> 1.4'
s.dependency 'FirebaseABTesting', '~> 3.1'
s.dependency 'FirebaseCore', '~> 6.2'
s.dependency 'FirebaseInstanceID', '~> 4.2'
s.dependency 'FirebaseInstallations', '~> 1.1'
s.dependency 'GoogleUtilities/Environment', '~> 6.2'
s.dependency 'GoogleUtilities/NSData+zlib', '~> 6.2'
s.dependency 'Protobuf', '~> 3.9', '>= 3.9.2'
Expand Down Expand Up @@ -69,5 +69,6 @@ app update.
'FirebaseRemoteConfig/Tests/Unit/SecondApp-GoogleService-Info.plist'
unit_tests.requires_app_host = true
unit_tests.dependency 'OCMock'
unit_tests.requires_arc = true
end
end
8 changes: 4 additions & 4 deletions FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@
@property(nonatomic, copy) NSString *secretToken;
/// Device data version of checkin information.
@property(nonatomic, copy) NSString *deviceDataVersion;
/// InstanceID.
@property(nonatomic, copy) NSString *configInstanceID;
/// InstanceID token.
@property(nonatomic, copy) NSString *configInstanceIDToken;
/// InstallationsID.
@property(nonatomic, copy) NSString *configInstallationsIdentifier;
/// Installations token.
@property(nonatomic, copy) NSString *configInstallationsToken;

/// A list of successful fetch timestamps in milliseconds.
/// TODO Not used anymore. Safe to remove.
Expand Down
4 changes: 2 additions & 2 deletions FirebaseRemoteConfig/Sources/RCNConfigSettings.m
Original file line number Diff line number Diff line change
Expand Up @@ -334,9 +334,9 @@ - (NSString *)nextRequestWithUserProperties:(NSDictionary *)userProperties {
// Note: We only set user properties as mentioned in the new REST API Design doc
NSString *ret = [NSString stringWithFormat:@"{"];
ret = [ret stringByAppendingString:[NSString stringWithFormat:@"app_instance_id:'%@'",
_configInstanceID]];
_configInstallationsIdentifier]];
ret = [ret stringByAppendingString:[NSString stringWithFormat:@", app_instance_id_token:'%@'",
_configInstanceIDToken]];
_configInstallationsToken]];
ret = [ret stringByAppendingString:[NSString stringWithFormat:@", app_id:'%@'", _googleAppID]];

ret = [ret stringByAppendingString:[NSString stringWithFormat:@", country_code:'%@'",
Expand Down
95 changes: 34 additions & 61 deletions FirebaseRemoteConfig/Sources/RCNFetch.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@

#import "FirebaseRemoteConfig/Sources/RCNConfigFetch.h"

#import <FirebaseCore/FIRApp.h>
#import <FirebaseCore/FIRLogger.h>
#import <FirebaseCore/FIROptions.h>
#import <FirebaseInstanceID/FIRInstanceID+Private.h>
#import <FirebaseInstanceID/FIRInstanceIDCheckinPreferences.h>
#import <FirebaseInstallations/FirebaseInstallations.h>
#import <GoogleUtilities/GULNSData+zlib.h>
#import "FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h"
#import "FirebaseRemoteConfig/Sources/RCNConfigConstants.h"
Expand All @@ -40,7 +40,6 @@
static NSString *const kServerURLQuery = @":fetch?";
static NSString *const kServerURLKey = @"key=";
static NSString *const kRequestJSONKeyAppID = @"app_id";
static NSString *const kRequestJSONKeyAppInstanceID = @"app_instance_id";

static NSString *const kHTTPMethodPost = @"POST"; ///< HTTP request method config fetch using
static NSString *const kContentTypeHeaderName = @"Content-Type"; ///< HTTP Header Field Name
Expand All @@ -55,7 +54,6 @@

/// Config HTTP request content type proto buffer
static NSString *const kContentTypeValueJSON = @"application/json";
static NSString *const kInstanceIDScopeConfig = @"*"; /// InstanceID scope

/// HTTP status codes. Ref: https://cloud.google.com/apis/design/errors#error_retries
static NSInteger const kRCNFetchResponseHTTPStatusCodeOK = 200;
Expand Down Expand Up @@ -192,18 +190,24 @@ - (void)fetchConfigWithExpirationDuration:(NSTimeInterval)expirationDuration
withError:error];
}
strongSelf->_settings.isFetchInProgress = YES;
[strongSelf refreshInstanceIDTokenAndFetchCheckInInfoWithCompletionHandler:completionHandler];
[strongSelf refreshInstallationsTokenWithCompletionHandler:completionHandler];
});
}

#pragma mark - Fetch helpers

/// Refresh instance ID token before fetching config. Instance ID is now mandatory for fetch
- (NSString *)FIRAppNameFromFullyQualifiedNamespace {
NSString *FIRAppName =
[_FIRNamespace substringFromIndex:[_FIRNamespace rangeOfString:@":"].location + 1];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am a bit worried that we compose the string at one place and parse it at another, because it increases probability of errors when the logic needs to be updated. Will it be better to just pass appName separately?

If you still would like to parse the string, I would suggest a safer way to do it to avoid crashing if the _FIRNamespace contains an unexpected string for some reason, e.g.:

return [[_FIRNamespace componentsSeparatedByString:@":"] lastObject];

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

return FIRAppName;
}
/// Refresh installation ID token before fetching config. installation ID is now mandatory for fetch
/// requests to work.(b/14751422).
- (void)refreshInstanceIDTokenAndFetchCheckInInfoWithCompletionHandler:
- (void)refreshInstallationsTokenWithCompletionHandler:
(FIRRemoteConfigFetchCompletion)completionHandler {
FIRInstanceID *instanceID = [FIRInstanceID instanceID];
if (!_options.GCMSenderID) {
FIRInstallations *installations = [FIRInstallations
installationsWithApp:[FIRApp appNamed:[self FIRAppNameFromFullyQualifiedNamespace]]];
if (!installations || !_options.GCMSenderID) {
NSString *errorDescription = @"Failed to get GCMSenderID";
FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000074", @"%@",
[NSString stringWithFormat:@"%@", errorDescription]);
Expand All @@ -217,10 +221,11 @@ - (void)refreshInstanceIDTokenAndFetchCheckInInfoWithCompletionHandler:
NSLocalizedDescriptionKey : errorDescription
}]];
}
FIRInstanceIDTokenHandler instanceIDHandler = ^(NSString *token, NSError *error) {
if (!token || error) {
FIRInstallationsTokenHandler installationsTokenHandler = ^(
FIRInstallationsAuthTokenResult *tokenResult, NSError *error) {
if (!tokenResult || !tokenResult.authToken || error) {
NSString *errorDescription =
[NSString stringWithFormat:@"Failed to get InstanceID token. Error : %@.", error];
[NSString stringWithFormat:@"Failed to get installations token. Error : %@.", error];
FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000073", @"%@",
[NSString stringWithFormat:@"%@", errorDescription]);
self->_settings.isFetchInProgress = NO;
Expand All @@ -234,20 +239,21 @@ - (void)refreshInstanceIDTokenAndFetchCheckInInfoWithCompletionHandler:
}]];
}

// If the token is available, try to get the instanceID.
// We have a valid token. Get the backing installationID.
__weak RCNConfigFetch *weakSelf = self;
[instanceID getIDWithHandler:^(NSString *_Nullable identity, NSError *_Nullable error) {
[installations installationIDWithCompletion:^(NSString *_Nullable identifier,
NSError *_Nullable error) {
RCNConfigFetch *strongSelf = weakSelf;

// Dispatch to the RC serial queue to update settings on the queue.
dispatch_async(strongSelf->_lockQueue, ^{
RCNConfigFetch *strongSelfQueue = weakSelf;

// Update config settings with the IID and token.
strongSelfQueue->_settings.configInstanceIDToken = [token copy];
strongSelfQueue->_settings.configInstanceID = identity;
strongSelfQueue->_settings.configInstallationsToken = [tokenResult.authToken copy];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: copy is not required here because configInstallationsToken property is defined with copy attribute already.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

strongSelfQueue->_settings.configInstallationsIdentifier = identifier;

if (!identity || error) {
if (!identifier || error) {
NSString *errorDescription =
[NSString stringWithFormat:@"Error getting iid : %@.", error];
FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000055", @"%@",
Expand All @@ -265,56 +271,23 @@ - (void)refreshInstanceIDTokenAndFetchCheckInInfoWithCompletionHandler:
}

FIRLogInfo(kFIRLoggerRemoteConfig, @"I-RCN000022", @"Success to get iid : %@.",
strongSelfQueue->_settings.configInstanceID);

// Continue the fetch regardless of whether fetch of instance ID succeeded.
[strongSelfQueue fetchCheckinInfoWithCompletionHandler:completionHandler];
strongSelfQueue->_settings.configInstallationsIdentifier);
[strongSelf
getAnalyticsUserPropertiesWithCompletionHandler:^(NSDictionary *userProperties) {
dispatch_async(strongSelf->_lockQueue, ^{
[strongSelf fetchWithUserProperties:userProperties
completionHandler:completionHandler];
});
}];
});
}];
};
FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000039", @"Starting requesting token.");
// Note: We expect the GCMSenderID to always be available by the time this request is made.
[instanceID tokenWithAuthorizedEntity:_options.GCMSenderID
scope:kInstanceIDScopeConfig
options:nil
handler:instanceIDHandler];
}

/// Fetch checkin info before fetching config. Checkin info including device authentication ID,
/// secret token and device data version are optional fields in config request.
- (void)fetchCheckinInfoWithCompletionHandler:(FIRRemoteConfigFetchCompletion)completionHandler {
FIRInstanceID *instanceID = [FIRInstanceID instanceID];
__weak RCNConfigFetch *weakSelf = self;
[instanceID fetchCheckinInfoWithHandler:^(FIRInstanceIDCheckinPreferences *preferences,
NSError *error) {
RCNConfigFetch *fetchCheckinInfoWithHandlerSelf = weakSelf;
dispatch_async(fetchCheckinInfoWithHandlerSelf->_lockQueue, ^{
RCNConfigFetch *strongSelf = fetchCheckinInfoWithHandlerSelf;
if (error) {
FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000023", @"Failed to fetch checkin info: %@.",
error);
} else {
strongSelf->_settings.deviceAuthID = preferences.deviceID;
strongSelf->_settings.secretToken = preferences.secretToken;
strongSelf->_settings.deviceDataVersion = preferences.deviceDataVersion;
if (strongSelf->_settings.deviceAuthID.length && strongSelf->_settings.secretToken.length) {
FIRLogInfo(kFIRLoggerRemoteConfig, @"I-RCN000024",
@"Success to get device authentication ID: %@, security token: %@.",
self->_settings.deviceAuthID, self->_settings.secretToken);
}
}
// Checkin info is optional, continue fetch config regardless fetch of checkin info
// succeeded.
[strongSelf fetchWithUserPropertiesCompletionHandler:^(NSDictionary *userProperties) {
dispatch_async(strongSelf->_lockQueue, ^{
[strongSelf fetchWithUserProperties:userProperties completionHandler:completionHandler];
});
}];
});
}];
FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000039", @"Starting requesting token.");
[installations authTokenWithCompletion:installationsTokenHandler];
}

- (void)fetchWithUserPropertiesCompletionHandler:
- (void)getAnalyticsUserPropertiesWithCompletionHandler:
(FIRAInteropUserPropertiesCallback)completionHandler {
FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000060", @"Fetch with user properties completed.");
id<FIRAnalyticsInterop> analytics = self->_analytics;
Expand Down
1 change: 0 additions & 1 deletion FirebaseRemoteConfig/Tests/Sample/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ target 'RemoteConfigSampleApp' do
pod 'FirebaseAnalytics'
pod 'FirebaseCore', :path => '../../../'
pod 'FirebaseInstallations', :path => '../../../'
pod 'FirebaseInstanceID', :path => '../../../'
pod 'FirebaseRemoteConfig', :path => '../../../'

# Pods for RemoteConfigSampleApp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#import <FirebaseAnalytics/FirebaseAnalytics.h>
#import <FirebaseCore/FIROptions.h>
#import <FirebaseCore/FirebaseCore.h>
#import <FirebaseInstanceID/FIRInstanceID+Private.h>
#import <FirebaseInstallations/FirebaseInstallations.h>
#import <FirebaseRemoteConfig/FIRRemoteConfig_Private.h>
#import <FirebaseRemoteConfig/FirebaseRemoteConfig.h>
#import "FRCLog.h"
Expand Down Expand Up @@ -355,21 +355,19 @@ - (void)printResult:(NSMutableString *)output {
stringWithFormat:@"%@\n",
[self statusString:currentRCInstance.lastFetchStatus]]];

FIRInstanceID *instanceID = [FIRInstanceID instanceID];
[instanceID getIDWithHandler:^(NSString *_Nullable identity, NSError *_Nullable error) {
[output appendString:@"\n-----------Instance ID------------------\n"];
[output appendString:[NSString stringWithFormat:@"%@\n", identity]];
FIRInstallations *installations = [FIRInstallations installations];
[installations installationIDWithCompletion:^(NSString *_Nullable identifier,
NSError *_Nullable error) {
[output appendString:@"\n-----------Installation ID------------------\n"];
[output appendString:[NSString stringWithFormat:@"%@\n", identifier]];

[output appendString:@"\n-----------Instance ID token------------\n"];
[output
appendString:[NSString stringWithFormat:@"%@\n",
currentRCInstance.settings.configInstanceIDToken]];
[output appendString:@"\n-----------Installation ID token------------\n"];

[output appendString:@"\n-----------Android ID------------\n"];
[output
appendString:[NSString stringWithFormat:@"%@\n", currentRCInstance.settings.deviceAuthID]];

[[FRCLog sharedInstance] logToConsole:output];
[installations authTokenWithCompletion:^(FIRInstallationsAuthTokenResult *_Nullable tokenResult,
NSError *_Nullable error) {
[output appendString:[NSString stringWithFormat:@"%@\n", tokenResult.authToken]];
[[FRCLog sharedInstance] logToConsole:output];
}];
}];
}

Expand Down Expand Up @@ -409,27 +407,28 @@ - (NSString *)errorString:(FIRRemoteConfigError)error {
}

- (IBAction)fetchIIDButtonClicked:(id)sender {
FIRInstanceID *instanceID = [FIRInstanceID instanceID];
FIRInstanceIDTokenHandler instanceIDHandler = ^(NSString *token, NSError *error) {
FIRInstallations *installations =
[FIRInstallations installationsWithApp:[FIRApp appNamed:self.FIRAppName]];
[installations installationIDWithCompletion:^(NSString *_Nullable identifier,
NSError *_Nullable error) {
if (error) {
[[FRCLog sharedInstance] logToConsole:[NSString stringWithFormat:@"%@", error]];
}
if (token) {
((FIRRemoteConfig *)self.RCInstances[self.currentNamespace][self.FIRAppName])
.settings.configInstanceIDToken = token;
[instanceID getIDWithHandler:^(NSString *_Nullable identity, NSError *_Nullable error) {
[[FRCLog sharedInstance]
logToConsole:[NSString
stringWithFormat:
@"Successfully getting InstanceID : \n\n%@\n\nToken : \n\n%@\n",
identity, token]];
} else {
[installations authTokenWithCompletion:^(
FIRInstallationsAuthTokenResult *_Nullable tokenResult,
NSError *_Nullable error) {
if (tokenResult.authToken) {
((FIRRemoteConfig *)self.RCInstances[self.currentNamespace][self.FIRAppName])
.settings.configInstallationsToken = tokenResult.authToken;
[[FRCLog sharedInstance]
logToConsole:[NSString
stringWithFormat:
@"Successfully got installation ID : \n\n%@\n\nToken : \n\n%@\n",
identifier, tokenResult.authToken]];
}
}];
}
};
[instanceID tokenWithAuthorizedEntity:[FIRApp appNamed:self.FIRAppName].options.GCMSenderID
scope:@"*"
options:nil
handler:instanceIDHandler];
}];
}

- (IBAction)searchButtonClicked:(id)sender {
Expand Down
Loading