Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
/*
2
 * Copyright 2019 Google
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
 
17
#import "FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h"
18
 
19
#import "FirebaseABTesting/Sources/Private/FirebaseABTestingInternal.h"
20
#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
21
#import "FirebaseRemoteConfig/Sources/FIRRemoteConfigComponent.h"
22
#import "FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h"
23
#import "FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h"
24
#import "FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h"
25
#import "FirebaseRemoteConfig/Sources/RCNConfigConstants.h"
26
#import "FirebaseRemoteConfig/Sources/RCNConfigContent.h"
27
#import "FirebaseRemoteConfig/Sources/RCNConfigDBManager.h"
28
#import "FirebaseRemoteConfig/Sources/RCNConfigExperiment.h"
29
#import "FirebaseRemoteConfig/Sources/RCNConfigValue_Internal.h"
30
#import "FirebaseRemoteConfig/Sources/RCNDevice.h"
31
#import "FirebaseRemoteConfig/Sources/RCNPersonalization.h"
32
 
33
/// Remote Config Error Domain.
34
/// TODO: Rename according to obj-c style for constants.
35
NSString *const FIRRemoteConfigErrorDomain = @"com.google.remoteconfig.ErrorDomain";
36
/// Remote Config Error Info End Time Seconds;
37
NSString *const FIRRemoteConfigThrottledEndTimeInSecondsKey = @"error_throttled_end_time_seconds";
38
/// Minimum required time interval between fetch requests made to the backend.
39
static NSString *const kRemoteConfigMinimumFetchIntervalKey = @"_rcn_minimum_fetch_interval";
40
/// Timeout value for waiting on a fetch response.
41
static NSString *const kRemoteConfigFetchTimeoutKey = @"_rcn_fetch_timeout";
42
 
43
/// Listener for the get methods.
44
typedef void (^FIRRemoteConfigListener)(NSString *_Nonnull, NSDictionary *_Nonnull);
45
 
46
@implementation FIRRemoteConfigSettings
47
 
48
- (instancetype)init {
49
  self = [super init];
50
  if (self) {
51
    _minimumFetchInterval = RCNDefaultMinimumFetchInterval;
52
    _fetchTimeout = RCNHTTPDefaultConnectionTimeout;
53
  }
54
  return self;
55
}
56
 
57
@end
58
 
59
@implementation FIRRemoteConfig {
60
  /// All the config content.
61
  RCNConfigContent *_configContent;
62
  RCNConfigDBManager *_DBManager;
63
  RCNConfigSettings *_settings;
64
  RCNConfigFetch *_configFetch;
65
  RCNConfigExperiment *_configExperiment;
66
  dispatch_queue_t _queue;
67
  NSString *_appName;
68
  NSMutableArray *_listeners;
69
}
70
 
71
static NSMutableDictionary<NSString *, NSMutableDictionary<NSString *, FIRRemoteConfig *> *>
72
    *RCInstances;
73
 
74
+ (nonnull FIRRemoteConfig *)remoteConfigWithApp:(FIRApp *_Nonnull)firebaseApp {
75
  return [FIRRemoteConfig remoteConfigWithFIRNamespace:FIRNamespaceGoogleMobilePlatform
76
                                                   app:firebaseApp];
77
}
78
 
79
+ (nonnull FIRRemoteConfig *)remoteConfigWithFIRNamespace:(NSString *_Nonnull)firebaseNamespace {
80
  if (![FIRApp isDefaultAppConfigured]) {
81
    FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000047",
82
                @"FIRApp not configured. Please make sure you have called [FIRApp configure]");
83
    // TODO: Maybe throw an exception here? That'd be a breaking change though, but at this point
84
    // RC can't work as expected.
85
  }
86
 
87
  return [FIRRemoteConfig remoteConfigWithFIRNamespace:firebaseNamespace app:[FIRApp defaultApp]];
88
}
89
 
90
+ (nonnull FIRRemoteConfig *)remoteConfigWithFIRNamespace:(NSString *_Nonnull)firebaseNamespace
91
                                                      app:(FIRApp *_Nonnull)firebaseApp {
92
  // Use the provider to generate and return instances of FIRRemoteConfig for this specific app and
93
  // namespace. This will ensure the app is configured before Remote Config can return an instance.
94
  id<FIRRemoteConfigProvider> provider =
95
      FIR_COMPONENT(FIRRemoteConfigProvider, firebaseApp.container);
96
  return [provider remoteConfigForNamespace:firebaseNamespace];
97
}
98
 
99
+ (FIRRemoteConfig *)remoteConfig {
100
  // If the default app is not configured at this point, warn the developer.
101
  if (![FIRApp isDefaultAppConfigured]) {
102
    FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000047",
103
                @"FIRApp not configured. Please make sure you have called [FIRApp configure]");
104
    // TODO: Maybe throw an exception here? That'd be a breaking change though, but at this point
105
    // RC can't work as expected.
106
  }
107
 
108
  return [FIRRemoteConfig remoteConfigWithFIRNamespace:FIRNamespaceGoogleMobilePlatform
109
                                                   app:[FIRApp defaultApp]];
110
}
111
 
112
/// Singleton instance of serial queue for queuing all incoming RC calls.
113
+ (dispatch_queue_t)sharedRemoteConfigSerialQueue {
114
  static dispatch_once_t onceToken;
115
  static dispatch_queue_t sharedRemoteConfigQueue;
116
  dispatch_once(&onceToken, ^{
117
    sharedRemoteConfigQueue =
118
        dispatch_queue_create(RCNRemoteConfigQueueLabel, DISPATCH_QUEUE_SERIAL);
119
  });
120
  return sharedRemoteConfigQueue;
121
}
122
 
123
/// Designated initializer
124
- (instancetype)initWithAppName:(NSString *)appName
125
                     FIROptions:(FIROptions *)options
126
                      namespace:(NSString *)FIRNamespace
127
                      DBManager:(RCNConfigDBManager *)DBManager
128
                  configContent:(RCNConfigContent *)configContent
129
                      analytics:(nullable id<FIRAnalyticsInterop>)analytics {
130
  self = [super init];
131
  if (self) {
132
    _appName = appName;
133
    _DBManager = DBManager;
134
    // The fully qualified Firebase namespace is namespace:firappname.
135
    _FIRNamespace = [NSString stringWithFormat:@"%@:%@", FIRNamespace, appName];
136
 
137
    // Initialize RCConfigContent if not already.
138
    _configContent = configContent;
139
    _settings = [[RCNConfigSettings alloc] initWithDatabaseManager:_DBManager
140
                                                         namespace:_FIRNamespace
141
                                                   firebaseAppName:appName
142
                                                       googleAppID:options.googleAppID];
143
 
144
    FIRExperimentController *experimentController = [FIRExperimentController sharedInstance];
145
    _configExperiment = [[RCNConfigExperiment alloc] initWithDBManager:_DBManager
146
                                                  experimentController:experimentController];
147
    /// Serial queue for read and write lock.
148
    _queue = [FIRRemoteConfig sharedRemoteConfigSerialQueue];
149
 
150
    // Initialize with default config settings.
151
    [self setDefaultConfigSettings];
152
    _configFetch = [[RCNConfigFetch alloc] initWithContent:_configContent
153
                                                 DBManager:_DBManager
154
                                                  settings:_settings
155
                                                 analytics:analytics
156
                                                experiment:_configExperiment
157
                                                     queue:_queue
158
                                                 namespace:_FIRNamespace
159
                                                   options:options];
160
 
161
    [_settings loadConfigFromMetadataTable];
162
 
163
    if (analytics) {
164
      _listeners = [[NSMutableArray alloc] init];
165
      RCNPersonalization *personalization =
166
          [[RCNPersonalization alloc] initWithAnalytics:analytics];
167
      [self addListener:^(NSString *key, NSDictionary *config) {
168
        [personalization logArmActive:key config:config];
169
      }];
170
    }
171
  }
172
  return self;
173
}
174
 
175
// Initialize with default config settings.
176
- (void)setDefaultConfigSettings {
177
  // Set the default config settings.
178
  self->_settings.fetchTimeout = RCNHTTPDefaultConnectionTimeout;
179
  self->_settings.minimumFetchInterval = RCNDefaultMinimumFetchInterval;
180
}
181
 
182
- (void)ensureInitializedWithCompletionHandler:
183
    (nonnull FIRRemoteConfigInitializationCompletion)completionHandler {
184
  __weak FIRRemoteConfig *weakSelf = self;
185
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
186
    FIRRemoteConfig *strongSelf = weakSelf;
187
    if (!strongSelf) {
188
      return;
189
    }
190
    BOOL initializationSuccess = [self->_configContent initializationSuccessful];
191
    NSError *error = nil;
192
    if (!initializationSuccess) {
193
      error = [[NSError alloc]
194
          initWithDomain:FIRRemoteConfigErrorDomain
195
                    code:FIRRemoteConfigErrorInternalError
196
                userInfo:@{NSLocalizedDescriptionKey : @"Timed out waiting for database load."}];
197
    }
198
    completionHandler(error);
199
  });
200
}
201
 
202
/// Adds a listener that will be called whenever one of the get methods is called.
203
/// @param listener Function that takes in the parameter key and the config.
204
- (void)addListener:(nonnull FIRRemoteConfigListener)listener {
205
  @synchronized(_listeners) {
206
    [_listeners addObject:listener];
207
  }
208
}
209
 
210
- (void)callListeners:(NSString *)key config:(NSDictionary *)config {
211
  @synchronized(_listeners) {
212
    for (FIRRemoteConfigListener listener in _listeners) {
213
      dispatch_async(_queue, ^{
214
        listener(key, config);
215
      });
216
    }
217
  }
218
}
219
 
220
#pragma mark - fetch
221
 
222
- (void)fetchWithCompletionHandler:(FIRRemoteConfigFetchCompletion)completionHandler {
223
  dispatch_async(_queue, ^{
224
    [self fetchWithExpirationDuration:self->_settings.minimumFetchInterval
225
                    completionHandler:completionHandler];
226
  });
227
}
228
 
229
- (void)fetchWithExpirationDuration:(NSTimeInterval)expirationDuration
230
                  completionHandler:(FIRRemoteConfigFetchCompletion)completionHandler {
231
  FIRRemoteConfigFetchCompletion completionHandlerCopy = nil;
232
  if (completionHandler) {
233
    completionHandlerCopy = [completionHandler copy];
234
  }
235
  [_configFetch fetchConfigWithExpirationDuration:expirationDuration
236
                                completionHandler:completionHandlerCopy];
237
}
238
 
239
#pragma mark - fetchAndActivate
240
 
241
- (void)fetchAndActivateWithCompletionHandler:
242
    (FIRRemoteConfigFetchAndActivateCompletion)completionHandler {
243
  __weak FIRRemoteConfig *weakSelf = self;
244
  FIRRemoteConfigFetchCompletion fetchCompletion =
245
      ^(FIRRemoteConfigFetchStatus fetchStatus, NSError *fetchError) {
246
        FIRRemoteConfig *strongSelf = weakSelf;
247
        if (!strongSelf) {
248
          return;
249
        }
250
        // Fetch completed. We are being called on the main queue.
251
        // If fetch is successful, try to activate the fetched config
252
        if (fetchStatus == FIRRemoteConfigFetchStatusSuccess && !fetchError) {
253
          [strongSelf activateWithCompletion:^(BOOL changed, NSError *_Nullable activateError) {
254
            if (completionHandler) {
255
              FIRRemoteConfigFetchAndActivateStatus status =
256
                  activateError ? FIRRemoteConfigFetchAndActivateStatusSuccessUsingPreFetchedData
257
                                : FIRRemoteConfigFetchAndActivateStatusSuccessFetchedFromRemote;
258
              dispatch_async(dispatch_get_main_queue(), ^{
259
                completionHandler(status, nil);
260
              });
261
            }
262
          }];
263
        } else if (completionHandler) {
264
          FIRRemoteConfigFetchAndActivateStatus status =
265
              fetchStatus == FIRRemoteConfigFetchStatusSuccess
266
                  ? FIRRemoteConfigFetchAndActivateStatusSuccessUsingPreFetchedData
267
                  : FIRRemoteConfigFetchAndActivateStatusError;
268
          dispatch_async(dispatch_get_main_queue(), ^{
269
            completionHandler(status, fetchError);
270
          });
271
        }
272
      };
273
  [self fetchWithCompletionHandler:fetchCompletion];
274
}
275
 
276
#pragma mark - apply
277
 
278
typedef void (^FIRRemoteConfigActivateChangeCompletion)(BOOL changed, NSError *_Nullable error);
279
 
280
- (void)activateWithCompletion:(FIRRemoteConfigActivateChangeCompletion)completion {
281
  __weak FIRRemoteConfig *weakSelf = self;
282
  void (^applyBlock)(void) = ^(void) {
283
    FIRRemoteConfig *strongSelf = weakSelf;
284
    if (!strongSelf) {
285
      NSError *error = [NSError errorWithDomain:FIRRemoteConfigErrorDomain
286
                                           code:FIRRemoteConfigErrorInternalError
287
                                       userInfo:@{@"ActivationFailureReason" : @"Internal Error."}];
288
      if (completion) {
289
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
290
          completion(NO, error);
291
        });
292
      }
293
      FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000068", @"Internal error activating config.");
294
      return;
295
    }
296
    // Check if the last fetched config has already been activated. Fetches with no data change are
297
    // ignored.
298
    if (strongSelf->_settings.lastETagUpdateTime == 0 ||
299
        strongSelf->_settings.lastETagUpdateTime <= strongSelf->_settings.lastApplyTimeInterval) {
300
      FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000069",
301
                  @"Most recently fetched config is already activated.");
302
      if (completion) {
303
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
304
          completion(NO, nil);
305
        });
306
      }
307
      return;
308
    }
309
    [strongSelf->_configContent copyFromDictionary:self->_configContent.fetchedConfig
310
                                          toSource:RCNDBSourceActive
311
                                      forNamespace:self->_FIRNamespace];
312
    strongSelf->_settings.lastApplyTimeInterval = [[NSDate date] timeIntervalSince1970];
313
    FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000069", @"Config activated.");
314
    [strongSelf->_configContent activatePersonalization];
315
    [strongSelf->_configExperiment updateExperimentsWithHandler:^(NSError *_Nullable error) {
316
      if (completion) {
317
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
318
          completion(YES, nil);
319
        });
320
      }
321
    }];
322
  };
323
  dispatch_async(_queue, applyBlock);
324
}
325
 
326
#pragma mark - helpers
327
- (NSString *)fullyQualifiedNamespace:(NSString *)namespace {
328
  // If this is already a fully qualified namespace, return.
329
  if ([namespace rangeOfString:@":"].location != NSNotFound) {
330
    return namespace;
331
  }
332
  NSString *fullyQualifiedNamespace = [NSString stringWithFormat:@"%@:%@", namespace, _appName];
333
  return fullyQualifiedNamespace;
334
}
335
 
336
#pragma mark - Get Config Result
337
 
338
- (FIRRemoteConfigValue *)objectForKeyedSubscript:(NSString *)key {
339
  return [self configValueForKey:key];
340
}
341
 
342
- (FIRRemoteConfigValue *)configValueForKey:(NSString *)key {
343
  if (!key) {
344
    return [[FIRRemoteConfigValue alloc] initWithData:[NSData data]
345
                                               source:FIRRemoteConfigSourceStatic];
346
  }
347
  NSString *FQNamespace = [self fullyQualifiedNamespace:_FIRNamespace];
348
  __block FIRRemoteConfigValue *value;
349
  dispatch_sync(_queue, ^{
350
    value = self->_configContent.activeConfig[FQNamespace][key];
351
    if (value) {
352
      if (value.source != FIRRemoteConfigSourceRemote) {
353
        FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000001",
354
                    @"Key %@ should come from source:%zd instead coming from source: %zd.", key,
355
                    (long)FIRRemoteConfigSourceRemote, (long)value.source);
356
      }
357
      [self callListeners:key
358
                   config:[self->_configContent getConfigAndMetadataForNamespace:FQNamespace]];
359
      return;
360
    }
361
    value = self->_configContent.defaultConfig[FQNamespace][key];
362
    if (value) {
363
      return;
364
    }
365
 
366
    value = [[FIRRemoteConfigValue alloc] initWithData:[NSData data]
367
                                                source:FIRRemoteConfigSourceStatic];
368
  });
369
  return value;
370
}
371
 
372
- (FIRRemoteConfigValue *)configValueForKey:(NSString *)key source:(FIRRemoteConfigSource)source {
373
  if (!key) {
374
    return [[FIRRemoteConfigValue alloc] initWithData:[NSData data]
375
                                               source:FIRRemoteConfigSourceStatic];
376
  }
377
  NSString *FQNamespace = [self fullyQualifiedNamespace:_FIRNamespace];
378
 
379
  __block FIRRemoteConfigValue *value;
380
  dispatch_sync(_queue, ^{
381
    if (source == FIRRemoteConfigSourceRemote) {
382
      value = self->_configContent.activeConfig[FQNamespace][key];
383
    } else if (source == FIRRemoteConfigSourceDefault) {
384
      value = self->_configContent.defaultConfig[FQNamespace][key];
385
    } else {
386
      value = [[FIRRemoteConfigValue alloc] initWithData:[NSData data]
387
                                                  source:FIRRemoteConfigSourceStatic];
388
    }
389
  });
390
  return value;
391
}
392
 
393
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
394
                                  objects:(id __unsafe_unretained[])stackbuf
395
                                    count:(NSUInteger)len {
396
  __block NSUInteger localValue;
397
  dispatch_sync(_queue, ^{
398
    localValue =
399
        [self->_configContent.activeConfig[self->_FIRNamespace] countByEnumeratingWithState:state
400
                                                                                    objects:stackbuf
401
                                                                                      count:len];
402
  });
403
  return localValue;
404
}
405
 
406
#pragma mark - Properties
407
 
408
/// Last fetch completion time.
409
- (NSDate *)lastFetchTime {
410
  __block NSDate *fetchTime;
411
  dispatch_sync(_queue, ^{
412
    NSTimeInterval lastFetchTime = self->_settings.lastFetchTimeInterval;
413
    fetchTime = [NSDate dateWithTimeIntervalSince1970:lastFetchTime];
414
  });
415
  return fetchTime;
416
}
417
 
418
- (FIRRemoteConfigFetchStatus)lastFetchStatus {
419
  __block FIRRemoteConfigFetchStatus currentStatus;
420
  dispatch_sync(_queue, ^{
421
    currentStatus = self->_settings.lastFetchStatus;
422
  });
423
  return currentStatus;
424
}
425
 
426
- (NSArray *)allKeysFromSource:(FIRRemoteConfigSource)source {
427
  __block NSArray *keys = [[NSArray alloc] init];
428
  dispatch_sync(_queue, ^{
429
    NSString *FQNamespace = [self fullyQualifiedNamespace:self->_FIRNamespace];
430
    switch (source) {
431
      case FIRRemoteConfigSourceDefault:
432
        if (self->_configContent.defaultConfig[FQNamespace]) {
433
          keys = [[self->_configContent.defaultConfig[FQNamespace] allKeys] copy];
434
        }
435
        break;
436
      case FIRRemoteConfigSourceRemote:
437
        if (self->_configContent.activeConfig[FQNamespace]) {
438
          keys = [[self->_configContent.activeConfig[FQNamespace] allKeys] copy];
439
        }
440
        break;
441
      default:
442
        break;
443
    }
444
  });
445
  return keys;
446
}
447
 
448
- (nonnull NSSet *)keysWithPrefix:(nullable NSString *)prefix {
449
  __block NSMutableSet *keys = [[NSMutableSet alloc] init];
450
  dispatch_sync(_queue, ^{
451
    NSString *FQNamespace = [self fullyQualifiedNamespace:self->_FIRNamespace];
452
    if (self->_configContent.activeConfig[FQNamespace]) {
453
      NSArray *allKeys = [self->_configContent.activeConfig[FQNamespace] allKeys];
454
      if (!prefix.length) {
455
        keys = [NSMutableSet setWithArray:allKeys];
456
      } else {
457
        for (NSString *key in allKeys) {
458
          if ([key hasPrefix:prefix]) {
459
            [keys addObject:key];
460
          }
461
        }
462
      }
463
    }
464
  });
465
  return [keys copy];
466
}
467
 
468
#pragma mark - Defaults
469
 
470
- (void)setDefaults:(NSDictionary<NSString *, NSObject *> *)defaultConfig {
471
  NSString *FQNamespace = [self fullyQualifiedNamespace:_FIRNamespace];
472
  NSDictionary *defaultConfigCopy = [[NSDictionary alloc] init];
473
  if (defaultConfig) {
474
    defaultConfigCopy = [defaultConfig copy];
475
  }
476
  void (^setDefaultsBlock)(void) = ^(void) {
477
    NSDictionary *namespaceToDefaults = @{FQNamespace : defaultConfigCopy};
478
    [self->_configContent copyFromDictionary:namespaceToDefaults
479
                                    toSource:RCNDBSourceDefault
480
                                forNamespace:FQNamespace];
481
    self->_settings.lastSetDefaultsTimeInterval = [[NSDate date] timeIntervalSince1970];
482
  };
483
  dispatch_async(_queue, setDefaultsBlock);
484
}
485
 
486
- (FIRRemoteConfigValue *)defaultValueForKey:(NSString *)key {
487
  NSString *FQNamespace = [self fullyQualifiedNamespace:_FIRNamespace];
488
  __block FIRRemoteConfigValue *value;
489
  dispatch_sync(_queue, ^{
490
    NSDictionary *defaultConfig = self->_configContent.defaultConfig;
491
    value = defaultConfig[FQNamespace][key];
492
    if (value) {
493
      if (value.source != FIRRemoteConfigSourceDefault) {
494
        FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000002",
495
                    @"Key %@ should come from source:%zd instead coming from source: %zd", key,
496
                    (long)FIRRemoteConfigSourceDefault, (long)value.source);
497
      }
498
    }
499
  });
500
  return value;
501
}
502
 
503
- (void)setDefaultsFromPlistFileName:(nullable NSString *)fileName {
504
  if (!fileName || fileName.length == 0) {
505
    FIRLogWarning(kFIRLoggerRemoteConfig, @"I-RCN000037",
506
                  @"The plist file '%@' could not be found by Remote Config.", fileName);
507
    return;
508
  }
509
  NSArray *bundles = @[ [NSBundle mainBundle], [NSBundle bundleForClass:[self class]] ];
510
 
511
  for (NSBundle *bundle in bundles) {
512
    NSString *plistFile = [bundle pathForResource:fileName ofType:@"plist"];
513
    // Use the first one we find.
514
    if (plistFile) {
515
      NSDictionary *defaultConfig = [[NSDictionary alloc] initWithContentsOfFile:plistFile];
516
      if (defaultConfig) {
517
        [self setDefaults:defaultConfig];
518
      }
519
      return;
520
    }
521
  }
522
  FIRLogWarning(kFIRLoggerRemoteConfig, @"I-RCN000037",
523
                @"The plist file '%@' could not be found by Remote Config.", fileName);
524
}
525
 
526
#pragma mark - custom variables
527
 
528
- (FIRRemoteConfigSettings *)configSettings {
529
  __block NSTimeInterval minimumFetchInterval = RCNDefaultMinimumFetchInterval;
530
  __block NSTimeInterval fetchTimeout = RCNHTTPDefaultConnectionTimeout;
531
  dispatch_sync(_queue, ^{
532
    minimumFetchInterval = self->_settings.minimumFetchInterval;
533
    fetchTimeout = self->_settings.fetchTimeout;
534
  });
535
  FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000066",
536
              @"Successfully read configSettings. Minimum Fetch Interval:%f, "
537
              @"Fetch timeout: %f",
538
              minimumFetchInterval, fetchTimeout);
539
  FIRRemoteConfigSettings *settings = [[FIRRemoteConfigSettings alloc] init];
540
  settings.minimumFetchInterval = minimumFetchInterval;
541
  settings.fetchTimeout = fetchTimeout;
542
  /// The NSURLSession needs to be recreated whenever the fetch timeout may be updated.
543
  [_configFetch recreateNetworkSession];
544
  return settings;
545
}
546
 
547
- (void)setConfigSettings:(FIRRemoteConfigSettings *)configSettings {
548
  void (^setConfigSettingsBlock)(void) = ^(void) {
549
    if (!configSettings) {
550
      return;
551
    }
552
 
553
    self->_settings.minimumFetchInterval = configSettings.minimumFetchInterval;
554
    self->_settings.fetchTimeout = configSettings.fetchTimeout;
555
    /// The NSURLSession needs to be recreated whenever the fetch timeout may be updated.
556
    [self->_configFetch recreateNetworkSession];
557
    FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000067",
558
                @"Successfully set configSettings. Minimum Fetch Interval:%f, "
559
                @"Fetch timeout:%f",
560
                configSettings.minimumFetchInterval, configSettings.fetchTimeout);
561
  };
562
  dispatch_async(_queue, setConfigSettingsBlock);
563
}
564
 
565
@end