Files
firebase-ios-sdk/FirebaseRemoteConfig/Tests/Sample/RemoteConfigSampleApp/ViewController.m
T
4e5b83f2d9 Merge Realtime into Remote Config (#10060)
* Realtime rc dev (#9807)

* Remove commits from non-CLA account. Move TypeDef to private RCNRealtimeConfig file.

* Remove completion handler typedef

* Format file

* Update listener registration description

* Realtime rc dev (#9835)

* Remove commits from non-CLA account. Move TypeDef to private RCNRealtimeConfig file.

* Remove completion handler typedef

* Format file

* Update listener registration description

* Add http streaming and auto fetch. Also add template version number to cache for autofetch.

* Format file.

* Add unit tests

* Format files

* fix test

* update test and header file

* Change templateVersionNumber to ivar

* Fix async tests and update NSDictionary changes

* Format file

* Update fetch time

* remove define header

* Wrap auto fetch in async queue

* Add auto fetch test

* Change template version extraction check.

* Change realtime error code to start at 8001

* Realtime rc dev (#9914)

* Remove commits from non-CLA account. Move TypeDef to private RCNRealtimeConfig file.

* Remove completion handler typedef

* Format file

* Update listener registration description

* Add http streaming and auto fetch. Also add template version number to cache for autofetch.

* Format file.

* Add unit tests

* Format files

* fix test

* update test and header file

* Change templateVersionNumber to ivar

* Fix async tests and update NSDictionary changes

* Format file

* Update fetch time

* remove define header

* Add http stream retry and background change listener.

* Wrap auto fetch in async queue

* Expose realtime method in public

* Update comments

* Add auto fetch test

* Change template version extraction check.

* Change realtime error code to start at 8001

* Change from NSTimer to dispatch. Add flag to guard against retrying.

* Format and add comments.

* Update tests

* Qdpham13 patch 1 (#9913)

* Delete .SecondApp-GoogleService-Info.plist

* Delete SecondApp-GoogleService-Info.plist

* Delete GoogleService-Info.plist

* Delete SecondApp-GoogleService-Info.plist

* Update ViewController.m

* Delete clang-format directory

* format

* Change to NSExtensionHostWillEnterForegroundNotification

* Change to UIApplicationWillEnterForegroundNotification

* add import

* Remove import, use string literal instead of UIKit enum

* add test for new public method

* Update template version number retrieval function and update delay

* Fix test

* Fix test

* Update retry seconds and fetch interval seconds

* Update ddos to DDoS

* Update variable according to style guide.

* Replace NSLog with kFIRLoggerRemoteConfig (#10062)

* Replace NSLog with kFIRLoggerRemoteConfig

* Remove logs and change others from info to debug.

* update log messages.

* Format files

* Realtime rc failsafe (#10067)

* Add failsafe logic to request, response and application logic.

* Update flag name and conditions.

* Format file

* Add check for template version number

* Format files

* Changes based on PR comments

* move response parsing logic to separate function and add test for failsafe flag

* Update based on PR comments and add method to propagate error to listeners in queue.

* Realtime rc merge patch v1 (#10089)

* Fix foreground reconnection naming, add background check and flag, add check to see if fetch is currently in progress.

* Add check so fetches come only when the template version is greater than the current one.

* Format file changes

* Add debug log

* Make changes based on PR comments.

* Resolve failsafe changes

* Updating instance var names

* change template version check for auto fetch from >= to >

* Cherry-pick #10123 into Firebase 9.5.0

* [RC] Fix retry logic to respect max retry count (#10143)

* Fix retry logic to respect max retry count

* Rename to isRequestInProgress

* Save template version in settings (#10162)

* Save template version in settings

* Format files

* set last template version to 0

* Store template version in userDefaults instead of deviceContents

* return nil for unsuccessful fetches

* fix typo

* Realtime rc no change (#10188)

* Save template version in settings

* Format files

* set last template version to 0

* Store template version in userDefaults instead of deviceContents

* return nil for unsuccessful fetches

* fix typo

* put addEtagToHeader flag to fetch and propagate it to surrounding functions

* Add excludeEtagHeaderForRealtime flag to RCNConfigFetch

* Update mocks for Swift test

* Fix flag

* Add commentting

* reconcile master branch merge conflicts

* Revert "Realtime rc no change (#10188)" (#10346)

This reverts commit abe7939602.
In part of implementing a different solution.

* Add Http status check to Realtime stream (#10406)

* Check status code before retrying

* Change time out to 5 and a half minutes

* Throw exception if unable to establish connection due to non-retryable status code

* Format file

* Replace old realtime exceptions with new exceptions (#10482)

* Replace old realtime exceptions with new exceptions

* Fix word type

* Realtime RC Fetch ID (#10499)

* Add Realtime specific fetch method and fetch type header changes

* Add test

* Add comments and format

* Fix tests

* Update fetch header name

* Update tests and edit realtime fetch name and params

* refactor remainingAttempts var

* Realtime rc backoff (#10483)

* Change Realtime back off to use same system as Fetch and persist backoff state

* format and fix merge conflict

* Save retry count along with other throttling metadata

* Update var name

* Fix naming

* Return ConfigUpdate to realtime listeners (#10578)

* diff fetched and active config on realtime fetch

* Some refactoring and added tests

* Revert some unrelated changes to fetch

* Fix formatting

* Update branch and fix swift tests

* Rename updatedParams to updatedKeys (#10683)

* Update Realtime RC service URL. (#10713)

* Compare p13n metadata values as dictionaries. (#10756)

* Realtime RC 1P Bug Fix: Add checks for retryHttpConnection method (#10770)

* Add checks to retry method

* Move background check to beginning of retry

* Capitalize FetchType header (#10774)

* Remove Fetch Duplicate error and fix API misuse error (#10814)

* Remove fetch duplicate error

* Move completionHandler to bottom of didReceiveData

* Remove unused var

* Return Server produced error if Http status code is 403  (#10844)

* Add API message to enable Realtime

* Update error message parsing to return error message from backend

* Format file

* Add comment and remove unnecessary string

* Format and update error checks

* Change matcher string

* Update matcher string

* Address PR comments (#10845)

* Address PR comments

* Add Realtime Swift mocks

* Remove unnecessary mocks

* Format files

* Format tests

* Add Realtime mock

* Add missing quote

* Fix bugs

* Remove import

* Update import

* Change import

* Don't make connection call for Realtime mock

* Move around import of RCNConfigSettings

* Fix andDo

* Update test

* Add mockedRealtime flags

* trigger integration test

* Add integration and unit test

* change constant value

* Add new RC key

* Update update

* Remove deleted item

* Add registration removal

* Fix and format files

* remove semicolon

* Update error check

* remove space

* Update capitalization

* Add space

* Remove spaces

* remove more spaces

* Remove comment and add swift name

* format

* Add tests and sampleApp changes for updatedKeys (#10879)

* Update tests and sample app

* change key name

* remove unused var

* Add comment

* update sampleApp comments

* Update comments for public methods

* Update backoff commenting

* Add changelog entry for real-time updates. (#10942)

* Add changelog entry for RC real time updates.

* Hyphenation.

* Change doc references to hyphenate real-time (#10948)

* Change doc references to hyphenate real-time

* Run formatter.

* Re-word real-time paragraph to flow better.

---------

Co-authored-by: Andrew Heard <andrew@wizheard.com>
Co-authored-by: karenyz <58443706+karenyz@users.noreply.github.com>
Co-authored-by: Karen Zeng <karenzeng@google.com>
Co-authored-by: Dana Silver <dsilver1221@gmail.com>
Co-authored-by: Dana Silver <danasilver@google.com>
2023-03-13 16:02:56 -07:00

532 lines
22 KiB
Objective-C

// Copyright 2019 Google
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "ViewController.h"
#import <FirebaseAnalytics/FirebaseAnalytics.h>
#import <FirebaseCore/FIROptions.h>
#import <FirebaseCore/FirebaseCore.h>
#import <FirebaseInstallations/FirebaseInstallations.h>
#import <FirebaseRemoteConfig/FirebaseRemoteConfig.h>
#import "../../../Sources/Private/FIRRemoteConfig_Private.h"
#import "FRCLog.h"
static NSString *const FIRPerfNamespace = @"fireperf";
static NSString *const FIRDefaultFIRAppName = @"__FIRAPP_DEFAULT";
static NSString *const FIRSecondFIRAppName = @"secondFIRApp";
@interface FIRRemoteConfig (Sample)
+ (FIRRemoteConfig *)remoteConfigWithFIRNamespace:(NSString *)remoteConfigNamespace
app:(FIRApp *)app;
@end
@interface ViewController ()
@property(nonatomic, strong) IBOutlet UIButton *fetchButton;
@property(nonatomic, strong) IBOutlet UIButton *applyButton;
@property(nonatomic, strong) IBOutlet UIButton *refreshButton;
@property(nonatomic, strong) IBOutlet UIButton *clearLogsButton;
@property(nonatomic, strong) IBOutlet UITextView *mainTextView;
/// Key of custom variable to be added by user.
@property(nonatomic, weak) IBOutlet UITextField *keyLabel;
/// Value of custom variable to be added by user.
@property(nonatomic, weak) IBOutlet UITextField *valueLabel;
/// Expiration in seconds to be set by user.
@property(nonatomic, weak) IBOutlet UITextField *expirationLabel;
/// Config Defaults.
@property(nonatomic, strong) NSMutableDictionary *configDefaults;
/// developer mode switch.
@property(strong, nonatomic) IBOutlet UISwitch *developerModeEnabled;
/// Current selected namespace.
@property(nonatomic, copy) NSString *currentNamespace;
/// Curret selected FIRApp instance name.
@property(nonatomic, copy) NSString *FIRAppName;
/// Selected namespace picker control view.
@property(nonatomic, strong) IBOutlet UIPickerView *namespacePicker;
/// Selected app picker control view.
@property(nonatomic, strong) IBOutlet UIPickerView *appPicker;
/// Array of prepopulated namespaces supported by this app.
@property(nonatomic, strong) NSArray<NSString *> *namespacePickerData;
/// Array of prepopulated FIRApp names supported by this app.
@property(nonatomic, strong) NSArray<NSString *> *appPickerData;
/// Array of Remote Config instances.
@property(nonatomic, strong) NSMutableDictionary *RCInstances;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[[FRCLog sharedInstance] setLogView:self.mainTextView];
[[FRCLog sharedInstance] logToConsole:@"Viewcontroller loaded"];
[[FRCLog sharedInstance] logToConsole:[[NSBundle mainBundle] bundleIdentifier]];
// Setup UI
self.expirationLabel.text = [NSString stringWithFormat:@"0"];
self.configDefaults = [[NSMutableDictionary alloc] init];
self.keyLabel.delegate = self;
self.valueLabel.delegate = self;
self.expirationLabel.delegate = self;
self.mainTextView.editable = NO;
// TODO(mandard): Add support for deleting and adding namespaces in the app.
self.namespacePickerData =
[[NSArray alloc] initWithObjects:FIRNamespaceGoogleMobilePlatform, FIRPerfNamespace, nil];
self.appPickerData =
[[NSArray alloc] initWithObjects:FIRDefaultFIRAppName, FIRSecondFIRAppName, nil];
self.RCInstances = [[NSMutableDictionary alloc] init];
for (NSString *namespaceString in self.namespacePickerData) {
for (NSString *appString in self.appPickerData) {
// Check for the default instance.
if (!self.RCInstances[namespaceString]) {
self.RCInstances[namespaceString] = [[NSMutableDictionary alloc] init];
}
if ([namespaceString isEqualToString:FIRNamespaceGoogleMobilePlatform] &&
[appString isEqualToString:FIRDefaultFIRAppName]) {
self.RCInstances[namespaceString][appString] = [FIRRemoteConfig remoteConfig];
} else {
FIRApp *firebaseApp = ([appString isEqualToString:FIRDefaultFIRAppName])
? [FIRApp defaultApp]
: [FIRApp appNamed:appString];
self.RCInstances[namespaceString][appString] =
[FIRRemoteConfig remoteConfigWithFIRNamespace:namespaceString app:firebaseApp];
}
FIRRemoteConfigSettings *settings = [[FIRRemoteConfigSettings alloc] init];
settings.fetchTimeout = 300;
settings.minimumFetchInterval = 300;
((FIRRemoteConfig *)(self.RCInstances[namespaceString][appString])).configSettings = settings;
}
}
/// UI popup for Realtime that shows if realtime_test_key was included in update.
UIAlertController *alert = [UIAlertController
alertControllerWithTitle:@"Alert"
message:@"The value for realtime_test_key has been updated!"
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action){
}];
[alert addAction:defaultAction];
// Add realtime listener for firebase namespace
[self.RCInstances[FIRNamespaceGoogleMobilePlatform][FIRDefaultFIRAppName]
addOnConfigUpdateListener:^(FIRRemoteConfigUpdate *_Nullable update,
NSError *_Nullable error) {
if (error != nil) {
[[FRCLog sharedInstance]
logToConsole:[NSString
stringWithFormat:@"Realtime Error: %@", error.localizedDescription]];
} else {
[[FRCLog sharedInstance] logToConsole:[NSString stringWithFormat:@"Config updated!"]];
if (update != nil) {
/// UI popup that lets user know that fetch included realtime_test_key in updatedKeys.
if ([[update updatedKeys] containsObject:@"realtime_test_key"]) {
[self presentViewController:alert animated:YES completion:nil];
}
NSString *updatedParams = [update updatedKeys];
[[FRCLog sharedInstance]
logToConsole:[NSString stringWithFormat:[updatedParams description]]];
[self apply];
}
}
}];
[[FRCLog sharedInstance] logToConsole:@"RC instances inited"];
self.namespacePicker.dataSource = self;
self.namespacePicker.delegate = self;
self.appPicker.dataSource = self;
self.appPicker.delegate = self;
[self.developerModeEnabled setOn:true animated:false];
}
- (IBAction)fetchButtonPressed:(id)sender {
[[FRCLog sharedInstance] logToConsole:@"Fetch button pressed"];
// fetchConfig api callback, this is triggered when client receives response from server
ViewController *__weak weakSelf = self;
FIRRemoteConfigFetchCompletion completion = ^(FIRRemoteConfigFetchStatus status, NSError *error) {
ViewController *strongSelf = weakSelf;
if (!strongSelf) {
return;
}
[[FRCLog sharedInstance]
logToConsole:[NSString stringWithFormat:@"Fetch completed. Status=%@",
[strongSelf statusString:status]]];
if (error) {
[[FRCLog sharedInstance] logToConsole:[NSString stringWithFormat:@"Fetch Error=%@", error]];
}
NSMutableString *output = [NSMutableString
stringWithFormat:@"Fetch status : %@.\n\n", [strongSelf statusString:status]];
if (error) {
[output appendFormat:@"%@\n", error];
}
if (status == FIRRemoteConfigFetchStatusFailure) {
[output appendString:[NSString stringWithFormat:@"Fetch Error :%@.\n",
[strongSelf errorString:error.code]]];
if (error.code == FIRRemoteConfigErrorThrottled) {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
NSNumber *throttledTime =
(NSNumber *)error.userInfo[FIRRemoteConfigThrottledEndTimeInSecondsKey];
NSDate *date = [NSDate dateWithTimeIntervalSince1970:[throttledTime doubleValue]];
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSString *timeString = [dateFormatter stringFromDate:date];
[output appendString:[NSString stringWithFormat:@"Throttled end at: %@ \n", timeString]];
}
}
[[FRCLog sharedInstance] logToConsole:output];
};
// fetchConfig api call
[[FRCLog sharedInstance] logToConsole:@"Calling fetchWithExpirationDuration.."];
[self.RCInstances[self.currentNamespace][self.FIRAppName]
fetchWithExpirationDuration:self.expirationLabel.text.integerValue
completionHandler:completion];
}
- (IBAction)fetchAndActivateButtonPressed:(id)sender {
// fetchConfig api callback, this is triggered when client receives response from server
ViewController *__weak weakSelf = self;
FIRRemoteConfigFetchAndActivateCompletion fetchAndActivateCompletion = ^(
FIRRemoteConfigFetchAndActivateStatus status, NSError *error) {
ViewController *strongSelf = weakSelf;
if (!strongSelf) {
return;
}
NSMutableString *output = [@"Fetch and activate status :" mutableCopy];
if (status == FIRRemoteConfigFetchAndActivateStatusSuccessFetchedFromRemote) {
[output appendString:@"Success from remote fetch."];
} else if (status == FIRRemoteConfigFetchAndActivateStatusSuccessUsingPreFetchedData) {
[output appendString:@"Success using pre-fetched data."];
} else if (status == FIRRemoteConfigFetchAndActivateStatusError) {
[output
appendString:[NSString stringWithFormat:@"Failure: %@", [error localizedDescription]]];
}
if (error) {
[output appendFormat:@"%@\n", error];
}
if (status == FIRRemoteConfigFetchAndActivateStatusError) {
[output appendString:[NSString stringWithFormat:@"Fetch And Activate Error :%@.\n",
[strongSelf errorString:error.code]]];
if (error.code == FIRRemoteConfigErrorThrottled) {
[output appendString:[NSString stringWithFormat:@"Throttled.\n"]];
}
}
// activate status
[[FRCLog sharedInstance] logToConsole:output];
if (status == FIRRemoteConfigFetchAndActivateStatusSuccessFetchedFromRemote ||
status == FIRRemoteConfigFetchAndActivateStatusSuccessUsingPreFetchedData) {
[strongSelf printResult:[[NSMutableString alloc] init]];
}
};
// fetchConfig api call
[self.RCInstances[self.currentNamespace][self.FIRAppName]
fetchAndActivateWithCompletionHandler:fetchAndActivateCompletion];
}
- (IBAction)activateButtonPressed:(id)sender {
[self apply];
}
- (IBAction)refreshButtonPressed:(id)sender {
NSMutableString *output = [[NSMutableString alloc] init];
[self printResult:output];
}
- (IBAction)setDefaultFromPlistButtonPressed:(id)sender {
[self.RCInstances[self.currentNamespace][self.FIRAppName]
setDefaultsFromPlistFileName:@"Defaults"];
[self printDefaultConfigs];
}
- (IBAction)setDefaultButtonPressed:(id)sender {
if (self.configDefaults.count) {
[self.RCInstances[self.currentNamespace][self.FIRAppName] setDefaults:self.configDefaults];
[self.configDefaults removeAllObjects];
[self printDefaultConfigs];
} else {
[[FRCLog sharedInstance] logToConsole:@"Nothing to set for defaults."];
}
}
- (IBAction)onClearLogsButtonPressed:(id)sender {
self.mainTextView.text = @"";
}
- (void)printDefaultConfigs {
NSMutableString *output = [[NSMutableString alloc] init];
[output appendString:@"\n-------Default config------\n"];
NSArray<NSString *> *result = [self.RCInstances[self.currentNamespace][self.FIRAppName]
allKeysFromSource:FIRRemoteConfigSourceDefault];
if (result) {
NSString *stringPerNs = @"";
for (NSString *key in result) {
FIRRemoteConfigValue *value =
[self.RCInstances[self.currentNamespace][self.FIRAppName] defaultValueForKey:key];
stringPerNs = [NSString stringWithFormat:@"%@%@ : %@ : %@\n", stringPerNs,
self.currentNamespace, key, value.stringValue];
}
[output appendString:stringPerNs];
}
[[FRCLog sharedInstance] logToConsole:output];
}
- (IBAction)getValueButtonPressed:(id)sender {
[[FRCLog sharedInstance] logToConsole:[self.RCInstances[self.currentNamespace][self.FIRAppName]
configValueForKey:self.keyLabel.text]
.debugDescription];
}
- (IBAction)logValueButtonPressed:(id)sender {
[[FRCLog sharedInstance]
logToConsole:[NSString stringWithFormat:@"key: %@ logged", self.keyLabel.text]];
}
// add default variable button pressed
- (IBAction)addButtonPressed:(id)sender {
[self addNewEntryToVariables:self.configDefaults isDefaults:YES];
}
- (IBAction)developerModeSwitched:(id)sender {
FIRRemoteConfigSettings *configSettings = [[FIRRemoteConfigSettings alloc] init];
((FIRRemoteConfig *)(self.RCInstances[self.currentNamespace][self.FIRAppName])).configSettings =
configSettings;
}
- (void)addNewEntryToVariables:(NSMutableDictionary *)variables isDefaults:(BOOL)isDefaults {
if ([self.keyLabel.text length]) {
variables[self.keyLabel.text] = self.valueLabel.text;
NSString *showText = @"custom variables ";
if (isDefaults) {
showText = @"config defaults";
}
[[FRCLog sharedInstance]
logToConsole:[NSString stringWithFormat:@"New %@ added %@ : %@\n", showText,
self.keyLabel.text, self.valueLabel.text]];
self.keyLabel.text = @"";
self.valueLabel.text = @"";
}
}
- (void)apply {
[self.RCInstances[self.currentNamespace][self.FIRAppName]
activateWithCompletion:^(BOOL changed, NSError *_Nullable error) {
NSMutableString *output = [[NSMutableString alloc] init];
[output appendString:[NSString stringWithFormat:@"ActivateFetched = %@\n",
changed ? @"YES" : @"NO"]];
[[FRCLog sharedInstance] logToConsole:output];
if (!error) {
[self printResult:output];
} else {
[self printResult:[[NSString stringWithFormat:@"Activate failed. Error: %@",
error.localizedDescription] mutableCopy]];
}
}];
}
// print out fetch result
- (void)printResult:(NSMutableString *)output {
FIRRemoteConfig *currentRCInstance = self.RCInstances[self.currentNamespace][self.FIRAppName];
NSString *namespace_p = self.currentNamespace;
[output appendString:@"-------Active config------\n"];
NSArray<NSString *> *result = [self.RCInstances[self.currentNamespace][self.FIRAppName]
allKeysFromSource:FIRRemoteConfigSourceRemote];
if (result) {
NSString *stringPerNs = @"";
for (NSString *key in result) {
FIRRemoteConfigValue *value = [currentRCInstance configValueForKey:key];
stringPerNs = [NSString
stringWithFormat:@"%@%@ : %@ : %@\n", stringPerNs, namespace_p, key, value.stringValue];
}
[output appendString:stringPerNs];
}
[output appendString:@"\n-------Default config------\n"];
result = [currentRCInstance allKeysFromSource:FIRRemoteConfigSourceDefault];
if (result) {
NSString *stringPerNs = @"";
for (NSString *key in result) {
FIRRemoteConfigValue *value = [currentRCInstance defaultValueForKey:key];
stringPerNs = [NSString
stringWithFormat:@"%@%@ : %@ : %@\n", stringPerNs, namespace_p, key, value.stringValue];
}
[output appendString:stringPerNs];
}
[output appendString:@"\n--------Custom Variables--------\n"];
[output appendString:@"\n----------Last fetch time----------------\n"];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
[output
appendString:[NSString stringWithFormat:@"%@\n",
[dateFormatter
stringFromDate:currentRCInstance.lastFetchTime]]];
[output appendString:@"\n-----------Last fetch status------------\n"];
[output appendString:[NSString
stringWithFormat:@"%@\n",
[self statusString:currentRCInstance.lastFetchStatus]]];
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-----------Installation ID token------------\n"];
[installations authTokenWithCompletion:^(FIRInstallationsAuthTokenResult *_Nullable tokenResult,
NSError *_Nullable error) {
[output appendString:[NSString stringWithFormat:@"%@\n", tokenResult.authToken]];
[[FRCLog sharedInstance] logToConsole:output];
}];
}];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
- (NSString *)statusString:(FIRRemoteConfigFetchStatus)status {
switch (status) {
case FIRRemoteConfigFetchStatusSuccess:
return @"Success";
case FIRRemoteConfigFetchStatusNoFetchYet:
return @"NotFetchYet";
case FIRRemoteConfigFetchStatusFailure:
return @"Failure";
case FIRRemoteConfigFetchStatusThrottled:
return @"Throttled";
default:
return @"Unknown";
}
return @"";
}
- (NSString *)errorString:(FIRRemoteConfigError)error {
switch (error) {
case FIRRemoteConfigErrorInternalError:
return @"Internal Error";
case FIRRemoteConfigErrorUnknown:
return @"Unknown Error";
case FIRRemoteConfigErrorThrottled:
return @"Throttled";
default:
return @"unknown";
}
return @"";
}
- (IBAction)fetchIIDButtonClicked:(id)sender {
FIRInstallations *installations =
[FIRInstallations installationsWithApp:[FIRApp appNamed:self.FIRAppName]];
[installations installationIDWithCompletion:^(NSString *_Nullable identifier,
NSError *_Nullable error) {
if (error) {
[[FRCLog sharedInstance] logToConsole:[NSString stringWithFormat:@"%@", error]];
} 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]];
}
}];
}
}];
}
- (IBAction)searchButtonClicked:(id)sender {
NSString *output = @"-------Active Config------\n";
for (NSString *key in [self.RCInstances[self.currentNamespace][self.FIRAppName]
keysWithPrefix:self.keyLabel.text]) {
FIRRemoteConfigValue *value =
((FIRRemoteConfig *)(self.RCInstances[self.currentNamespace][self.FIRAppName]))[key];
output = [NSString stringWithFormat:@"%@%@ : %@ : %@\n", output, self.currentNamespace, key,
value.stringValue];
}
[[FRCLog sharedInstance] logToConsole:output];
}
- (IBAction)userPropertyButtonClicked:(id)sender {
[FIRAnalytics setUserPropertyString:self.valueLabel.text forName:self.keyLabel.text];
NSString *output = [NSString
stringWithFormat:@"Set User Property => %@ : %@\n", self.keyLabel.text, self.valueLabel.text];
[[FRCLog sharedInstance] logToConsole:output];
}
#pragma mark - picker
// The number of columns of data
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
// App and currentNamespace pickers.
return 2;
}
// The number of rows of data
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
NSInteger rowCount = (component == 0) ? self.namespacePickerData.count : self.appPickerData.count;
return rowCount;
}
// The data to return for the row and component (column) that's being passed in
- (NSString *)pickerView:(UIPickerView *)pickerView
titleForRow:(NSInteger)row
forComponent:(NSInteger)component {
if (component == 0) {
self.currentNamespace = self.namespacePickerData[row];
return self.namespacePickerData[row];
} else {
self.FIRAppName = self.appPickerData[row];
return self.appPickerData[row];
}
}
- (UIView *)pickerView:(UIPickerView *)pickerView
viewForRow:(NSInteger)row
forComponent:(NSInteger)component
reusingView:(UIView *)view {
UILabel *tView = (UILabel *)view;
if (!tView) {
tView = [[UILabel alloc] init];
[tView setFont:[UIFont fontWithName:@"Helvetica" size:15]];
tView.numberOfLines = 3;
}
if (component == 0) {
self.currentNamespace = self.namespacePickerData[row];
tView.text = self.namespacePickerData[row];
} else {
self.FIRAppName = self.appPickerData[row];
tView.text = self.appPickerData[row];
}
return tView;
}
@end