ViewController.m 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. // Copyright 2019 Google
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #import "ViewController.h"
  15. #import <FirebaseAnalytics/FirebaseAnalytics.h>
  16. #import <FirebaseCore/FIROptions.h>
  17. #import <FirebaseCore/FirebaseCore.h>
  18. #import <FirebaseInstallations/FirebaseInstallations.h>
  19. @import FirebaseRemoteConfig;
  20. #import "FRCLog.h"
  21. @import FirebaseRemoteConfigInterop;
  22. typedef void (^FIRRemoteConfigFetchCompletion)(FIRRemoteConfigFetchStatus status,
  23. NSError *_Nullable error)
  24. NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead.");
  25. typedef void (^FIRRemoteConfigActivateCompletion)(NSError *_Nullable error)
  26. NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead.");
  27. typedef void (^FIRRemoteConfigFetchAndActivateCompletion)(
  28. FIRRemoteConfigFetchAndActivateStatus status, NSError *_Nullable error)
  29. NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead.");
  30. static NSString *const FIRPerfNamespace = @"fireperf";
  31. static NSString *const FIRDefaultFIRAppName = @"__FIRAPP_DEFAULT";
  32. static NSString *const FIRSecondFIRAppName = @"secondFIRApp";
  33. @interface FIRRemoteConfig (Sample)
  34. + (FIRRemoteConfig *)remoteConfigWithFIRNamespace:(NSString *)remoteConfigNamespace
  35. app:(FIRApp *)app;
  36. @end
  37. @interface ViewController ()
  38. @property(nonatomic, strong) IBOutlet UIButton *fetchButton;
  39. @property(nonatomic, strong) IBOutlet UIButton *applyButton;
  40. @property(nonatomic, strong) IBOutlet UIButton *refreshButton;
  41. @property(nonatomic, strong) IBOutlet UIButton *clearLogsButton;
  42. @property(nonatomic, strong) IBOutlet UITextView *mainTextView;
  43. /// Key of custom variable to be added by user.
  44. @property(nonatomic, weak) IBOutlet UITextField *keyLabel;
  45. /// Value of custom variable to be added by user.
  46. @property(nonatomic, weak) IBOutlet UITextField *valueLabel;
  47. /// Expiration in seconds to be set by user.
  48. @property(nonatomic, weak) IBOutlet UITextField *expirationLabel;
  49. /// Config Defaults.
  50. @property(nonatomic, strong) NSMutableDictionary *configDefaults;
  51. /// developer mode switch.
  52. @property(strong, nonatomic) IBOutlet UISwitch *developerModeEnabled;
  53. /// Current selected namespace.
  54. @property(nonatomic, copy) NSString *currentNamespace;
  55. /// Current selected FIRApp instance name.
  56. @property(nonatomic, copy) NSString *FIRAppName;
  57. /// Selected namespace picker control view.
  58. @property(nonatomic, strong) IBOutlet UIPickerView *namespacePicker;
  59. /// Selected app picker control view.
  60. @property(nonatomic, strong) IBOutlet UIPickerView *appPicker;
  61. /// Array of prepopulated namespaces supported by this app.
  62. @property(nonatomic, strong) NSArray<NSString *> *namespacePickerData;
  63. /// Array of prepopulated FIRApp names supported by this app.
  64. @property(nonatomic, strong) NSArray<NSString *> *appPickerData;
  65. /// Array of Remote Config instances.
  66. @property(nonatomic, strong) NSMutableDictionary *RCInstances;
  67. @end
  68. @implementation ViewController
  69. - (void)viewDidLoad {
  70. [super viewDidLoad];
  71. [[FRCLog sharedInstance] setLogView:self.mainTextView];
  72. [[FRCLog sharedInstance] logToConsole:@"Viewcontroller loaded"];
  73. [[FRCLog sharedInstance] logToConsole:[[NSBundle mainBundle] bundleIdentifier]];
  74. // Setup UI
  75. self.expirationLabel.text = [NSString stringWithFormat:@"0"];
  76. self.configDefaults = [[NSMutableDictionary alloc] init];
  77. self.keyLabel.delegate = self;
  78. self.valueLabel.delegate = self;
  79. self.expirationLabel.delegate = self;
  80. self.mainTextView.editable = NO;
  81. // TODO(mandard): Add support for deleting and adding namespaces in the app.
  82. self.namespacePickerData =
  83. [[NSArray alloc] initWithObjects:FIRRemoteConfigConstants.FIRNamespaceGoogleMobilePlatform,
  84. FIRPerfNamespace, nil];
  85. self.appPickerData =
  86. [[NSArray alloc] initWithObjects:FIRDefaultFIRAppName, FIRSecondFIRAppName, nil];
  87. self.RCInstances = [[NSMutableDictionary alloc] init];
  88. for (NSString *namespaceString in self.namespacePickerData) {
  89. for (NSString *appString in self.appPickerData) {
  90. // Check for the default instance.
  91. if (!self.RCInstances[namespaceString]) {
  92. self.RCInstances[namespaceString] = [[NSMutableDictionary alloc] init];
  93. }
  94. if ([namespaceString
  95. isEqualToString:FIRRemoteConfigConstants.FIRNamespaceGoogleMobilePlatform] &&
  96. [appString isEqualToString:FIRDefaultFIRAppName]) {
  97. self.RCInstances[namespaceString][appString] = [FIRRemoteConfig remoteConfig];
  98. } else {
  99. FIRApp *firebaseApp = ([appString isEqualToString:FIRDefaultFIRAppName])
  100. ? [FIRApp defaultApp]
  101. : [FIRApp appNamed:appString];
  102. self.RCInstances[namespaceString][appString] =
  103. [FIRRemoteConfig remoteConfigWithFIRNamespace:namespaceString app:firebaseApp];
  104. }
  105. FIRRemoteConfigSettings *settings = [[FIRRemoteConfigSettings alloc] init];
  106. settings.fetchTimeout = 300;
  107. settings.minimumFetchInterval = 300;
  108. ((FIRRemoteConfig *)(self.RCInstances[namespaceString][appString])).configSettings = settings;
  109. }
  110. }
  111. /// UI popup for Realtime that shows if realtime_test_key was included in update.
  112. UIAlertController *alert = [UIAlertController
  113. alertControllerWithTitle:@"Alert"
  114. message:@"The value for realtime_test_key has been updated!"
  115. preferredStyle:UIAlertControllerStyleAlert];
  116. UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"OK"
  117. style:UIAlertActionStyleDefault
  118. handler:^(UIAlertAction *action){
  119. }];
  120. [alert addAction:defaultAction];
  121. // Add realtime listener for firebase namespace
  122. [self.RCInstances[FIRRemoteConfigConstants.FIRNamespaceGoogleMobilePlatform][FIRDefaultFIRAppName]
  123. addOnConfigUpdateListener:^(FIRRemoteConfigUpdate *_Nullable update,
  124. NSError *_Nullable error) {
  125. if (error != nil) {
  126. [[FRCLog sharedInstance]
  127. logToConsole:[NSString
  128. stringWithFormat:@"Realtime Error: %@", error.localizedDescription]];
  129. } else {
  130. [[FRCLog sharedInstance] logToConsole:[NSString stringWithFormat:@"Config updated!"]];
  131. if (update != nil) {
  132. /// UI popup that lets user know that fetch included realtime_test_key in updatedKeys.
  133. if ([[update updatedKeys] containsObject:@"realtime_test_key"]) {
  134. [self presentViewController:alert animated:YES completion:nil];
  135. }
  136. NSSet<NSString *> *updatedParams = [update updatedKeys];
  137. [[FRCLog sharedInstance]
  138. logToConsole:[NSString stringWithFormat:@"%@", [updatedParams description]]];
  139. [self apply];
  140. }
  141. }
  142. }];
  143. [[FRCLog sharedInstance] logToConsole:@"RC instances inited"];
  144. self.namespacePicker.dataSource = self;
  145. self.namespacePicker.delegate = self;
  146. self.appPicker.dataSource = self;
  147. self.appPicker.delegate = self;
  148. [self.developerModeEnabled setOn:true animated:false];
  149. }
  150. - (IBAction)fetchButtonPressed:(id)sender {
  151. [[FRCLog sharedInstance] logToConsole:@"Fetch button pressed"];
  152. // fetchConfig api callback, this is triggered when client receives response from server
  153. ViewController *__weak weakSelf = self;
  154. FIRRemoteConfigFetchCompletion completion = ^(FIRRemoteConfigFetchStatus status, NSError *error) {
  155. ViewController *strongSelf = weakSelf;
  156. if (!strongSelf) {
  157. return;
  158. }
  159. [[FRCLog sharedInstance]
  160. logToConsole:[NSString stringWithFormat:@"Fetch completed. Status=%@",
  161. [strongSelf statusString:status]]];
  162. if (error) {
  163. [[FRCLog sharedInstance] logToConsole:[NSString stringWithFormat:@"Fetch Error=%@", error]];
  164. }
  165. NSMutableString *output = [NSMutableString
  166. stringWithFormat:@"Fetch status : %@.\n\n", [strongSelf statusString:status]];
  167. if (error) {
  168. [output appendFormat:@"%@\n", error];
  169. }
  170. if (status == FIRRemoteConfigFetchStatusFailure) {
  171. [output appendString:[NSString stringWithFormat:@"Fetch Error :%@.\n",
  172. [strongSelf errorString:error.code]]];
  173. if (error.code == FIRRemoteConfigErrorThrottled) {
  174. NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
  175. NSNumber *throttledTime =
  176. (NSNumber *)error.userInfo[FIRRemoteConfigThrottledEndTimeInSecondsKey];
  177. NSDate *date = [NSDate dateWithTimeIntervalSince1970:[throttledTime doubleValue]];
  178. [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
  179. NSString *timeString = [dateFormatter stringFromDate:date];
  180. [output appendString:[NSString stringWithFormat:@"Throttled end at: %@ \n", timeString]];
  181. }
  182. }
  183. [[FRCLog sharedInstance] logToConsole:output];
  184. };
  185. // fetchConfig api call
  186. [[FRCLog sharedInstance] logToConsole:@"Calling fetchWithExpirationDuration.."];
  187. [self.RCInstances[self.currentNamespace][self.FIRAppName]
  188. fetchWithExpirationDuration:self.expirationLabel.text.integerValue
  189. completionHandler:completion];
  190. }
  191. - (IBAction)fetchAndActivateButtonPressed:(id)sender {
  192. // fetchConfig api callback, this is triggered when client receives response from server
  193. ViewController *__weak weakSelf = self;
  194. FIRRemoteConfigFetchAndActivateCompletion fetchAndActivateCompletion = ^(
  195. FIRRemoteConfigFetchAndActivateStatus status, NSError *error) {
  196. ViewController *strongSelf = weakSelf;
  197. if (!strongSelf) {
  198. return;
  199. }
  200. NSMutableString *output = [@"Fetch and activate status :" mutableCopy];
  201. if (status == FIRRemoteConfigFetchAndActivateStatusSuccessFetchedFromRemote) {
  202. [output appendString:@"Success from remote fetch."];
  203. } else if (status == FIRRemoteConfigFetchAndActivateStatusSuccessUsingPreFetchedData) {
  204. [output appendString:@"Success using pre-fetched data."];
  205. } else if (status == FIRRemoteConfigFetchAndActivateStatusError) {
  206. [output
  207. appendString:[NSString stringWithFormat:@"Failure: %@", [error localizedDescription]]];
  208. }
  209. if (error) {
  210. [output appendFormat:@"%@\n", error];
  211. }
  212. if (status == FIRRemoteConfigFetchAndActivateStatusError) {
  213. [output appendString:[NSString stringWithFormat:@"Fetch And Activate Error :%@.\n",
  214. [strongSelf errorString:error.code]]];
  215. if (error.code == FIRRemoteConfigErrorThrottled) {
  216. [output appendString:[NSString stringWithFormat:@"Throttled.\n"]];
  217. }
  218. }
  219. // activate status
  220. [[FRCLog sharedInstance] logToConsole:output];
  221. if (status == FIRRemoteConfigFetchAndActivateStatusSuccessFetchedFromRemote ||
  222. status == FIRRemoteConfigFetchAndActivateStatusSuccessUsingPreFetchedData) {
  223. [strongSelf printResult:[[NSMutableString alloc] init]];
  224. }
  225. };
  226. // fetchConfig api call
  227. [self.RCInstances[self.currentNamespace][self.FIRAppName]
  228. fetchAndActivateWithCompletionHandler:fetchAndActivateCompletion];
  229. }
  230. - (IBAction)activateButtonPressed:(id)sender {
  231. [self apply];
  232. }
  233. - (IBAction)refreshButtonPressed:(id)sender {
  234. NSMutableString *output = [[NSMutableString alloc] init];
  235. [self printResult:output];
  236. }
  237. - (IBAction)setDefaultFromPlistButtonPressed:(id)sender {
  238. [self.RCInstances[self.currentNamespace][self.FIRAppName]
  239. setDefaultsFromPlistFileName:@"Defaults"];
  240. [self printDefaultConfigs];
  241. }
  242. - (IBAction)setDefaultButtonPressed:(id)sender {
  243. if (self.configDefaults.count) {
  244. [self.RCInstances[self.currentNamespace][self.FIRAppName] setDefaults:self.configDefaults];
  245. [self.configDefaults removeAllObjects];
  246. [self printDefaultConfigs];
  247. } else {
  248. [[FRCLog sharedInstance] logToConsole:@"Nothing to set for defaults."];
  249. }
  250. }
  251. - (IBAction)onClearLogsButtonPressed:(id)sender {
  252. self.mainTextView.text = @"";
  253. }
  254. - (void)printDefaultConfigs {
  255. NSMutableString *output = [[NSMutableString alloc] init];
  256. [output appendString:@"\n-------Default config------\n"];
  257. NSArray<NSString *> *result = [self.RCInstances[self.currentNamespace][self.FIRAppName]
  258. allKeysFromSource:FIRRemoteConfigSourceDefault];
  259. if (result) {
  260. NSString *stringPerNs = @"";
  261. for (NSString *key in result) {
  262. FIRRemoteConfigValue *value =
  263. [self.RCInstances[self.currentNamespace][self.FIRAppName] defaultValueForKey:key];
  264. stringPerNs = [NSString stringWithFormat:@"%@%@ : %@ : %@\n", stringPerNs,
  265. self.currentNamespace, key, value.stringValue];
  266. }
  267. [output appendString:stringPerNs];
  268. }
  269. [[FRCLog sharedInstance] logToConsole:output];
  270. }
  271. - (IBAction)getValueButtonPressed:(id)sender {
  272. [[FRCLog sharedInstance] logToConsole:[self.RCInstances[self.currentNamespace][self.FIRAppName]
  273. configValueForKey:self.keyLabel.text]
  274. .debugDescription];
  275. }
  276. - (IBAction)logValueButtonPressed:(id)sender {
  277. [[FRCLog sharedInstance]
  278. logToConsole:[NSString stringWithFormat:@"key: %@ logged", self.keyLabel.text]];
  279. }
  280. // add default variable button pressed
  281. - (IBAction)addButtonPressed:(id)sender {
  282. [self addNewEntryToVariables:self.configDefaults isDefaults:YES];
  283. }
  284. - (IBAction)developerModeSwitched:(id)sender {
  285. FIRRemoteConfigSettings *configSettings = [[FIRRemoteConfigSettings alloc] init];
  286. ((FIRRemoteConfig *)(self.RCInstances[self.currentNamespace][self.FIRAppName])).configSettings =
  287. configSettings;
  288. }
  289. - (void)addNewEntryToVariables:(NSMutableDictionary *)variables isDefaults:(BOOL)isDefaults {
  290. if ([self.keyLabel.text length]) {
  291. variables[self.keyLabel.text] = self.valueLabel.text;
  292. NSString *showText = @"custom variables ";
  293. if (isDefaults) {
  294. showText = @"config defaults";
  295. }
  296. [[FRCLog sharedInstance]
  297. logToConsole:[NSString stringWithFormat:@"New %@ added %@ : %@\n", showText,
  298. self.keyLabel.text, self.valueLabel.text]];
  299. self.keyLabel.text = @"";
  300. self.valueLabel.text = @"";
  301. }
  302. }
  303. - (void)apply {
  304. [self.RCInstances[self.currentNamespace][self.FIRAppName]
  305. activateWithCompletion:^(BOOL changed, NSError *_Nullable error) {
  306. NSMutableString *output = [[NSMutableString alloc] init];
  307. [output appendString:[NSString stringWithFormat:@"ActivateFetched = %@\n",
  308. changed ? @"YES" : @"NO"]];
  309. [[FRCLog sharedInstance] logToConsole:output];
  310. if (!error) {
  311. [self printResult:output];
  312. } else {
  313. [self printResult:[[NSString stringWithFormat:@"Activate failed. Error: %@",
  314. error.localizedDescription] mutableCopy]];
  315. }
  316. }];
  317. }
  318. // print out fetch result
  319. - (void)printResult:(NSMutableString *)output {
  320. FIRRemoteConfig *currentRCInstance = self.RCInstances[self.currentNamespace][self.FIRAppName];
  321. NSString *namespace_p = self.currentNamespace;
  322. [output appendString:@"-------Active config------\n"];
  323. NSArray<NSString *> *result = [self.RCInstances[self.currentNamespace][self.FIRAppName]
  324. allKeysFromSource:FIRRemoteConfigSourceRemote];
  325. if (result) {
  326. NSString *stringPerNs = @"";
  327. for (NSString *key in result) {
  328. FIRRemoteConfigValue *value = [currentRCInstance configValueForKey:key];
  329. stringPerNs = [NSString
  330. stringWithFormat:@"%@%@ : %@ : %@\n", stringPerNs, namespace_p, key, value.stringValue];
  331. }
  332. [output appendString:stringPerNs];
  333. }
  334. [output appendString:@"\n-------Default config------\n"];
  335. result = [currentRCInstance allKeysFromSource:FIRRemoteConfigSourceDefault];
  336. if (result) {
  337. NSString *stringPerNs = @"";
  338. for (NSString *key in result) {
  339. FIRRemoteConfigValue *value = [currentRCInstance defaultValueForKey:key];
  340. stringPerNs = [NSString
  341. stringWithFormat:@"%@%@ : %@ : %@\n", stringPerNs, namespace_p, key, value.stringValue];
  342. }
  343. [output appendString:stringPerNs];
  344. }
  345. [output appendString:@"\n--------Custom Variables--------\n"];
  346. [output appendString:@"\n----------Last fetch time----------------\n"];
  347. NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
  348. [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
  349. [output
  350. appendString:[NSString stringWithFormat:@"%@\n",
  351. [dateFormatter
  352. stringFromDate:currentRCInstance.lastFetchTime]]];
  353. [output appendString:@"\n-----------Last fetch status------------\n"];
  354. [output appendString:[NSString
  355. stringWithFormat:@"%@\n",
  356. [self statusString:currentRCInstance.lastFetchStatus]]];
  357. FIRInstallations *installations = [FIRInstallations installations];
  358. [installations installationIDWithCompletion:^(NSString *_Nullable identifier,
  359. NSError *_Nullable error) {
  360. [output appendString:@"\n-----------Installation ID------------------\n"];
  361. [output appendString:[NSString stringWithFormat:@"%@\n", identifier]];
  362. [output appendString:@"\n-----------Installation ID token------------\n"];
  363. [installations authTokenWithCompletion:^(FIRInstallationsAuthTokenResult *_Nullable tokenResult,
  364. NSError *_Nullable error) {
  365. [output appendString:[NSString stringWithFormat:@"%@\n", tokenResult.authToken]];
  366. [[FRCLog sharedInstance] logToConsole:output];
  367. }];
  368. }];
  369. }
  370. - (BOOL)textFieldShouldReturn:(UITextField *)textField {
  371. [textField resignFirstResponder];
  372. return YES;
  373. }
  374. - (NSString *)statusString:(FIRRemoteConfigFetchStatus)status {
  375. switch (status) {
  376. case FIRRemoteConfigFetchStatusSuccess:
  377. return @"Success";
  378. case FIRRemoteConfigFetchStatusNoFetchYet:
  379. return @"NotFetchYet";
  380. case FIRRemoteConfigFetchStatusFailure:
  381. return @"Failure";
  382. case FIRRemoteConfigFetchStatusThrottled:
  383. return @"Throttled";
  384. default:
  385. return @"Unknown";
  386. }
  387. return @"";
  388. }
  389. - (NSString *)errorString:(FIRRemoteConfigError)error {
  390. switch (error) {
  391. case FIRRemoteConfigErrorInternalError:
  392. return @"Internal Error";
  393. case FIRRemoteConfigErrorUnknown:
  394. return @"Unknown Error";
  395. case FIRRemoteConfigErrorThrottled:
  396. return @"Throttled";
  397. default:
  398. return @"unknown";
  399. }
  400. return @"";
  401. }
  402. - (IBAction)fetchIIDButtonClicked:(id)sender {
  403. FIRInstallations *installations =
  404. [FIRInstallations installationsWithApp:[FIRApp appNamed:self.FIRAppName]];
  405. [installations installationIDWithCompletion:^(NSString *_Nullable identifier,
  406. NSError *_Nullable error) {
  407. if (error) {
  408. [[FRCLog sharedInstance] logToConsole:[NSString stringWithFormat:@"%@", error]];
  409. } else {
  410. [installations authTokenWithCompletion:^(
  411. FIRInstallationsAuthTokenResult *_Nullable tokenResult,
  412. NSError *_Nullable error) {
  413. if (tokenResult.authToken) {
  414. ((FIRRemoteConfig *)self.RCInstances[self.currentNamespace][self.FIRAppName])
  415. .settings.configInstallationsToken = tokenResult.authToken;
  416. [[FRCLog sharedInstance]
  417. logToConsole:[NSString
  418. stringWithFormat:
  419. @"Successfully got installation ID : \n\n%@\n\nToken : \n\n%@\n",
  420. identifier, tokenResult.authToken]];
  421. }
  422. }];
  423. }
  424. }];
  425. }
  426. - (IBAction)searchButtonClicked:(id)sender {
  427. NSString *output = @"-------Active Config------\n";
  428. for (NSString *key in [self.RCInstances[self.currentNamespace][self.FIRAppName]
  429. keysWithPrefix:self.keyLabel.text]) {
  430. FIRRemoteConfigValue *value =
  431. ((FIRRemoteConfig *)(self.RCInstances[self.currentNamespace][self.FIRAppName]))[key];
  432. output = [NSString stringWithFormat:@"%@%@ : %@ : %@\n", output, self.currentNamespace, key,
  433. value.stringValue];
  434. }
  435. [[FRCLog sharedInstance] logToConsole:output];
  436. }
  437. - (IBAction)userPropertyButtonClicked:(id)sender {
  438. [FIRAnalytics setUserPropertyString:self.valueLabel.text forName:self.keyLabel.text];
  439. NSString *output = [NSString
  440. stringWithFormat:@"Set User Property => %@ : %@\n", self.keyLabel.text, self.valueLabel.text];
  441. [[FRCLog sharedInstance] logToConsole:output];
  442. }
  443. #pragma mark - picker
  444. // The number of columns of data
  445. - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
  446. // App and currentNamespace pickers.
  447. return 2;
  448. }
  449. // The number of rows of data
  450. - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
  451. NSInteger rowCount = (component == 0) ? self.namespacePickerData.count : self.appPickerData.count;
  452. return rowCount;
  453. }
  454. // The data to return for the row and component (column) that's being passed in
  455. - (NSString *)pickerView:(UIPickerView *)pickerView
  456. titleForRow:(NSInteger)row
  457. forComponent:(NSInteger)component {
  458. if (component == 0) {
  459. self.currentNamespace = self.namespacePickerData[row];
  460. return self.namespacePickerData[row];
  461. } else {
  462. self.FIRAppName = self.appPickerData[row];
  463. return self.appPickerData[row];
  464. }
  465. }
  466. - (UIView *)pickerView:(UIPickerView *)pickerView
  467. viewForRow:(NSInteger)row
  468. forComponent:(NSInteger)component
  469. reusingView:(UIView *)view {
  470. UILabel *tView = (UILabel *)view;
  471. if (!tView) {
  472. tView = [[UILabel alloc] init];
  473. [tView setFont:[UIFont fontWithName:@"Helvetica" size:15]];
  474. tView.numberOfLines = 3;
  475. }
  476. if (component == 0) {
  477. self.currentNamespace = self.namespacePickerData[row];
  478. tView.text = self.namespacePickerData[row];
  479. } else {
  480. self.FIRAppName = self.appPickerData[row];
  481. tView.text = self.appPickerData[row];
  482. }
  483. return tView;
  484. }
  485. @end