Merge pull request #121 from pocketgems/master
[ios][remoteconfig] Implement Firebase Remote Config for iOS
This commit is contained in:
commit
07a7f863f6
|
@ -15,6 +15,7 @@
|
|||
D96290851D6D28B80099A3EC /* RNFirebaseDatabase.m in Sources */ = {isa = PBXBuildFile; fileRef = D96290841D6D28B80099A3EC /* RNFirebaseDatabase.m */; };
|
||||
D9D62E7C1D6D86FD003D826D /* RNFirebaseStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9D62E7B1D6D86FD003D826D /* RNFirebaseStorage.m */; };
|
||||
D9D62E801D6D8717003D826D /* RNFirebaseAuth.m in Sources */ = {isa = PBXBuildFile; fileRef = D9D62E7F1D6D8717003D826D /* RNFirebaseAuth.m */; };
|
||||
EC841F001ECE79D6001AD3D9 /* RNFirebaseRemoteConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = EC841EFF1ECE79D6001AD3D9 /* RNFirebaseRemoteConfig.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
|
@ -48,6 +49,8 @@
|
|||
D9D62E7B1D6D86FD003D826D /* RNFirebaseStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNFirebaseStorage.m; path = RNFirebase/RNFirebaseStorage.m; sourceTree = "<group>"; };
|
||||
D9D62E7E1D6D8717003D826D /* RNFirebaseAuth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNFirebaseAuth.h; path = RNFirebase/RNFirebaseAuth.h; sourceTree = "<group>"; };
|
||||
D9D62E7F1D6D8717003D826D /* RNFirebaseAuth.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNFirebaseAuth.m; path = RNFirebase/RNFirebaseAuth.m; sourceTree = "<group>"; };
|
||||
EC841EFE1ECE79D6001AD3D9 /* RNFirebaseRemoteConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNFirebaseRemoteConfig.h; path = RNFirebase/RNFirebaseRemoteConfig.h; sourceTree = "<group>"; };
|
||||
EC841EFF1ECE79D6001AD3D9 /* RNFirebaseRemoteConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNFirebaseRemoteConfig.m; path = RNFirebase/RNFirebaseRemoteConfig.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -82,6 +85,8 @@
|
|||
D96290351D6D145F0099A3EC /* Modules */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EC841EFE1ECE79D6001AD3D9 /* RNFirebaseRemoteConfig.h */,
|
||||
EC841EFF1ECE79D6001AD3D9 /* RNFirebaseRemoteConfig.m */,
|
||||
D90882D41D89C18C00FB6742 /* RNFirebaseMessaging.h */,
|
||||
D90882D51D89C18C00FB6742 /* RNFirebaseMessaging.m */,
|
||||
D9D62E7E1D6D8717003D826D /* RNFirebaseAuth.h */,
|
||||
|
@ -163,6 +168,7 @@
|
|||
D962903F1D6D15B00099A3EC /* RNFirebaseErrors.m in Sources */,
|
||||
D950369E1D19C77400F7094D /* RNFirebase.m in Sources */,
|
||||
D90882D61D89C18C00FB6742 /* RNFirebaseMessaging.m in Sources */,
|
||||
EC841F001ECE79D6001AD3D9 /* RNFirebaseRemoteConfig.m in Sources */,
|
||||
29C199451EA7A851007B6BF8 /* RNFirebaseCrash.m in Sources */,
|
||||
D96290851D6D28B80099A3EC /* RNFirebaseDatabase.m in Sources */,
|
||||
);
|
||||
|
|
|
@ -243,82 +243,10 @@ RCT_EXPORT_METHOD(configure:(RCTResponseSenderBlock)callback)
|
|||
callback:callback];
|
||||
}
|
||||
|
||||
#pragma mark - Storage
|
||||
|
||||
#pragma mark Storage
|
||||
|
||||
#pragma mark RemoteConfig
|
||||
|
||||
// RCT_EXPORT_METHOD(setDefaultRemoteConfig:(NSDictionary *)props
|
||||
// callback:(RCTResponseSenderBlock) callback)
|
||||
// {
|
||||
// if (!self.remoteConfigInstance) {
|
||||
// // Create remote Config instance
|
||||
// self.remoteConfigInstance = [FIRRemoteConfig remoteConfig];
|
||||
// }
|
||||
|
||||
// [self.remoteConfigInstance setDefaults:props];
|
||||
// callback(@[[NSNull null], props]);
|
||||
// }
|
||||
|
||||
// RCT_EXPORT_METHOD(setDev:(RCTResponseSenderBlock) callback)
|
||||
// {
|
||||
// FIRRemoteConfigSettings *remoteConfigSettings = [[FIRRemoteConfigSettings alloc] initWithDeveloperModeEnabled:YES];
|
||||
// self.remoteConfigInstance.configSettings = remoteConfigSettings;
|
||||
// callback(@[[NSNull null], @"ok"]);
|
||||
// }
|
||||
|
||||
// RCT_EXPORT_METHOD(configValueForKey:(NSString *)name
|
||||
// callback:(RCTResponseSenderBlock) callback)
|
||||
// {
|
||||
// if (!self.remoteConfigInstance) {
|
||||
// NSDictionary *err = @{
|
||||
// @"error": @"No configuration instance",
|
||||
// @"msg": @"No configuration instance set. Please call setDefaultRemoteConfig before using this feature"
|
||||
// };
|
||||
// callback(@[err]);
|
||||
// }
|
||||
|
||||
|
||||
// FIRRemoteConfigValue *value = [self.remoteConfigInstance configValueForKey:name];
|
||||
// NSString *valueStr = value.stringValue;
|
||||
|
||||
// if (valueStr == nil) {
|
||||
// valueStr = @"";
|
||||
// }
|
||||
// callback(@[[NSNull null], valueStr]);
|
||||
// }
|
||||
|
||||
// RCT_EXPORT_METHOD(fetchWithExpiration:(NSNumber*)expirationSeconds
|
||||
// callback:(RCTResponseSenderBlock) callback)
|
||||
// {
|
||||
// if (!self.remoteConfigInstance) {
|
||||
// NSDictionary *err = @{
|
||||
// @"error": @"No configuration instance",
|
||||
// @"msg": @"No configuration instance set. Please call setDefaultRemoteConfig before using this feature"
|
||||
// };
|
||||
// callback(@[err]);
|
||||
// }
|
||||
|
||||
// NSTimeInterval expirationDuration = [expirationSeconds doubleValue];
|
||||
|
||||
// [self.remoteConfigInstance fetchWithExpirationDuration:expirationDuration completionHandler:^(FIRRemoteConfigFetchStatus status, NSError *error) {
|
||||
// if (status == FIRRemoteConfigFetchStatusSuccess) {
|
||||
// NSLog(@"Config fetched!");
|
||||
// [self.remoteConfigInstance activateFetched];
|
||||
// callback(@[[NSNull null], @(YES)]);
|
||||
// } else {
|
||||
// NSLog(@"Error %@", error.localizedDescription);
|
||||
|
||||
// NSDictionary *err = @{
|
||||
// @"error": @"No configuration instance",
|
||||
// @"msg": [error localizedDescription]
|
||||
// };
|
||||
|
||||
// callback(@[err]);
|
||||
// }
|
||||
// }];
|
||||
// }
|
||||
|
||||
#pragma mark Database
|
||||
|
||||
#pragma mark Messaging
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef RNFirebaseRemoteConfig_h
|
||||
#define RNFirebaseRemoteConfig_h
|
||||
|
||||
#if __has_include(<React/RCTBridgeModule.h>)
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#else // Compatibility for RN version < 0.40
|
||||
#import "RCTBridgeModule.h"
|
||||
#endif
|
||||
|
||||
@interface RNFirebaseRemoteConfig : NSObject <RCTBridgeModule>
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
|
@ -0,0 +1,161 @@
|
|||
#import "RNFirebaseRemoteConfig.h"
|
||||
|
||||
#if __has_include(<React/RCTConvert.h>)
|
||||
#import <React/RCTConvert.h>
|
||||
#else // Compatibility for RN version < 0.40
|
||||
#import "RCTConvert.h"
|
||||
#endif
|
||||
#if __has_include(<React/RCTUtils.h>)
|
||||
#import <React/RCTUtils.h>
|
||||
#else // Compatibility for RN version < 0.40
|
||||
#import "RCTUtils.h"
|
||||
#endif
|
||||
|
||||
#import "FirebaseRemoteConfig/FirebaseRemoteConfig.h"
|
||||
|
||||
NSString *convertFIRRemoteConfigFetchStatusToNSString(FIRRemoteConfigFetchStatus value)
|
||||
{
|
||||
switch(value){
|
||||
case FIRRemoteConfigFetchStatusNoFetchYet:
|
||||
return @"remoteConfitFetchStatusNoFetchYet";
|
||||
case FIRRemoteConfigFetchStatusSuccess:
|
||||
return @"remoteConfitFetchStatusSuccess";
|
||||
case FIRRemoteConfigFetchStatusFailure:
|
||||
return @"remoteConfitFetchStatusFailure";
|
||||
case FIRRemoteConfigFetchStatusThrottled:
|
||||
return @"remoteConfitFetchStatusThrottled";
|
||||
default:
|
||||
return @"remoteConfitFetchStatusFailure";
|
||||
}
|
||||
}
|
||||
|
||||
NSString *convertFIRRemoteConfigSourceToNSString(FIRRemoteConfigSource value)
|
||||
{
|
||||
switch(value) {
|
||||
case FIRRemoteConfigSourceRemote:
|
||||
return @"remoteConfigSourceRemote";
|
||||
case FIRRemoteConfigSourceDefault:
|
||||
return @"remoteConfigSourceDefault";
|
||||
case FIRRemoteConfigSourceStatic:
|
||||
return @"remoteConfigSourceStatic";
|
||||
default:
|
||||
return @"remoteConfigSourceStatic";
|
||||
}
|
||||
}
|
||||
|
||||
NSDictionary *convertFIRRemoteConfigValueToNSDictionary(FIRRemoteConfigValue *value)
|
||||
{
|
||||
return @{
|
||||
@"stringValue" : value.stringValue ?: [NSNull null],
|
||||
@"numberValue" : value.numberValue ?: [NSNull null],
|
||||
@"dataValue" : value.dataValue ? [value.dataValue base64EncodedStringWithOptions:0] : [NSNull null],
|
||||
@"boolValue" : @(value.boolValue),
|
||||
@"source" : convertFIRRemoteConfigSourceToNSString(value.source)
|
||||
};
|
||||
}
|
||||
|
||||
@interface RNFirebaseRemoteConfig ()
|
||||
|
||||
@property (nonatomic, readwrite, weak) FIRRemoteConfig *remoteConfig;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RNFirebaseRemoteConfig
|
||||
|
||||
RCT_EXPORT_MODULE(RNFirebaseRemoteConfig);
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_remoteConfig = [FIRRemoteConfig remoteConfig];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(enableDeveloperMode)
|
||||
{
|
||||
FIRRemoteConfigSettings *remoteConfigSettings = [[FIRRemoteConfigSettings alloc] initWithDeveloperModeEnabled:YES];
|
||||
self.remoteConfig.configSettings = remoteConfigSettings;
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(fetch:(RCTPromiseResolveBlock)resolve
|
||||
rejecter:(RCTPromiseRejectBlock)reject)
|
||||
{
|
||||
[self.remoteConfig fetchWithCompletionHandler:^(FIRRemoteConfigFetchStatus status, NSError *__nullable error) {
|
||||
if (error) {
|
||||
RCTLogError(@"\nError: %@", RCTJSErrorFromNSError(error));
|
||||
reject(convertFIRRemoteConfigFetchStatusToNSString(status), error.localizedDescription, error);
|
||||
} else {
|
||||
resolve(convertFIRRemoteConfigFetchStatusToNSString(status));
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(fetchWithExpirationDuration:(nonnull NSNumber *)expirationDuration
|
||||
resolver:(RCTPromiseResolveBlock)resolve
|
||||
rejecter:(RCTPromiseRejectBlock)reject)
|
||||
{
|
||||
[self.remoteConfig fetchWithExpirationDuration:expirationDuration.doubleValue completionHandler:^(FIRRemoteConfigFetchStatus status, NSError *__nullable error) {
|
||||
if (error) {
|
||||
RCTLogError(@"\nError: %@", RCTJSErrorFromNSError(error));
|
||||
reject(convertFIRRemoteConfigFetchStatusToNSString(status), error.localizedDescription, error);
|
||||
} else {
|
||||
resolve(convertFIRRemoteConfigFetchStatusToNSString(status));
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(activateFetched:(RCTPromiseResolveBlock)resolve
|
||||
rejecter:(RCTPromiseRejectBlock)reject)
|
||||
{
|
||||
BOOL status = [self.remoteConfig activateFetched];
|
||||
if (status) {
|
||||
resolve(@(status));
|
||||
} else {
|
||||
reject(@"activate_failed", @"Did not activate remote config", nil);
|
||||
}
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(configValueForKey:(NSString *)key
|
||||
resolver:(RCTPromiseResolveBlock)resolve
|
||||
rejecter:(RCTPromiseRejectBlock)reject)
|
||||
{
|
||||
FIRRemoteConfigValue *value = [self.remoteConfig configValueForKey:key];
|
||||
resolve(convertFIRRemoteConfigValueToNSDictionary(value));
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(configValuesForKeys:(NSArray *)keys
|
||||
resolver:(RCTPromiseResolveBlock)resolve
|
||||
rejecter:(RCTPromiseRejectBlock)reject)
|
||||
{
|
||||
NSMutableDictionary *res = [[NSMutableDictionary alloc] init];
|
||||
for (NSString *key in keys) {
|
||||
FIRRemoteConfigValue *value = [self.remoteConfig configValueForKey:key];
|
||||
res[key] = convertFIRRemoteConfigValueToNSDictionary(value);
|
||||
}
|
||||
resolve(res);
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(keysWithPrefix:(NSString *)prefix
|
||||
resolver:(RCTPromiseResolveBlock)resolve
|
||||
rejecter:(RCTPromiseRejectBlock)reject)
|
||||
{
|
||||
NSSet *keys = [self.remoteConfig keysWithPrefix:prefix];
|
||||
if (keys.count) {
|
||||
resolve(keys);
|
||||
} else {
|
||||
reject(@"no_keys_matching_prefix", @"There are no keys that match that prefix", nil);
|
||||
}
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(setDefaults:(NSDictionary *)defaults)
|
||||
{
|
||||
[self.remoteConfig setDefaults:defaults];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(setDefaultsFromPlistFileName:(NSString *)fileName)
|
||||
{
|
||||
[self.remoteConfig setDefaultsFromPlistFileName:fileName];
|
||||
}
|
||||
|
||||
@end
|
|
@ -14,6 +14,7 @@ import Database, { statics as DatabaseStatics } from './modules/database';
|
|||
import Messaging, { statics as MessagingStatics } from './modules/messaging';
|
||||
import Analytics from './modules/analytics';
|
||||
import Crash from './modules/crash';
|
||||
import RemoteConfig from './modules/remoteConfig';
|
||||
|
||||
const instances: Object = { default: null };
|
||||
const FirebaseModule = NativeModules.RNFirebase;
|
||||
|
@ -40,6 +41,7 @@ export default class Firebase {
|
|||
database: Function;
|
||||
analytics: Function;
|
||||
messaging: Function;
|
||||
remoteConfig: Function;
|
||||
|
||||
eventHandlers: Object;
|
||||
debug: boolean;
|
||||
|
@ -83,6 +85,7 @@ export default class Firebase {
|
|||
this.messaging = this._staticsOrInstance('messaging', MessagingStatics, Messaging);
|
||||
this.analytics = this._staticsOrInstance('analytics', {}, Analytics);
|
||||
this.crash = this._staticsOrInstance('crash', {}, Crash);
|
||||
this.remoteConfig = this._staticsOrInstance('remoteConfig', {}, RemoteConfig);
|
||||
|
||||
// init auth to start listeners
|
||||
this.auth();
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
/**
|
||||
* @flow
|
||||
*/
|
||||
import { NativeModules } from 'react-native';
|
||||
|
||||
import { Base } from './../base';
|
||||
|
||||
const FirebaseRemoteConfig = NativeModules.RNFirebaseRemoteConfig;
|
||||
|
||||
type RemoteConfigOptions = {}
|
||||
|
||||
/**
|
||||
* @class Config
|
||||
*/
|
||||
export default class RemoteConfig extends Base {
|
||||
constructor(firebase: Object, options: RemoteConfigOptions = {}) {
|
||||
super(firebase, options);
|
||||
this.namespace = 'firebase:config';
|
||||
this.developerModeEnabled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable Remote Config developer mode to allow for frequent refreshes of the cache
|
||||
*/
|
||||
enableDeveloperMode() {
|
||||
if (!this.developerModeEnabled) {
|
||||
this.log.debug('Enabled developer mode');
|
||||
FirebaseRemoteConfig.enableDeveloperMode();
|
||||
this.developerModeEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches Remote Config data
|
||||
* Call activateFetched to make fetched data available in app
|
||||
* @returns {*|Promise.<String>}:
|
||||
* One of
|
||||
* - remoteConfitFetchStatusSuccess
|
||||
* - remoteConfitFetchStatusFailure
|
||||
* - remoteConfitFetchStatusThrottled
|
||||
* rejects on remoteConfitFetchStatusFailure and remoteConfitFetchStatusThrottled
|
||||
* resolves on remoteConfitFetchStatusSuccess
|
||||
*/
|
||||
fetch() {
|
||||
this.log.debug('Fetching remote config data');
|
||||
return FirebaseRemoteConfig.fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches Remote Config data and sets a duration that specifies how long config data lasts.
|
||||
* Call activateFetched to make fetched data available
|
||||
* @param expiration: Duration that defines how long fetched config data is available, in
|
||||
* seconds. When the config data expires, a new fetch is required.
|
||||
* @returns {*|Promise.<Bool>}
|
||||
* One of
|
||||
* - remoteConfitFetchStatusSuccess
|
||||
* - remoteConfitFetchStatusFailure
|
||||
* - remoteConfitFetchStatusThrottled
|
||||
* rejects on remoteConfitFetchStatusFailure and remoteConfitFetchStatusThrottled
|
||||
* resolves on remoteConfitFetchStatusSuccess
|
||||
*/
|
||||
fetchWithExpirationDuration(expiration: Number) {
|
||||
this.log.debug(`Fetching remote config data with expiration ${expiration.toString()}`);
|
||||
return FirebaseRemoteConfig.fetchWithExpirationDuration(expiration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies Fetched Config data to the Active Config
|
||||
* @returns {*|Promise.<Bool>}
|
||||
* resolves if there was a Fetched Config, and it was activated,
|
||||
* rejects if no Fetched Config was found, or the Fetched Config was already activated.
|
||||
*/
|
||||
activateFetched() {
|
||||
this.log.debug('Activating remote config');
|
||||
return FirebaseRemoteConfig.activateFetched();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the config value of the default namespace.
|
||||
* @param key: Config key
|
||||
* @returns {*|Promise.<Object>}, will always resolve
|
||||
* Object looks like
|
||||
* {
|
||||
* "stringValue" : stringValue,
|
||||
* "numberValue" : numberValue,
|
||||
* "dataValue" : dataValue,
|
||||
* "boolValue" : boolValue,
|
||||
* "source" : OneOf<String>(remoteConfigSourceRemote|remoteConfigSourceDefault|remoteConfigSourceStatic)
|
||||
* }
|
||||
*/
|
||||
configValueForKey(key: String) {
|
||||
return FirebaseRemoteConfig.configValueForKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the config value of the default namespace.
|
||||
* @param key: Config key
|
||||
* @returns {*|Promise.<Object>}, will always resolve.
|
||||
* Result will be a dictionary of key and config objects
|
||||
* Object looks like
|
||||
* {
|
||||
* "stringValue" : stringValue,
|
||||
* "numberValue" : numberValue,
|
||||
* "dataValue" : dataValue,
|
||||
* "boolValue" : boolValue,
|
||||
* "source" : OneOf<String>(remoteConfigSourceRemote|remoteConfigSourceDefault|remoteConfigSourceStatic)
|
||||
* }
|
||||
*/
|
||||
configValuesForKeys(keys: Array<String>) {
|
||||
return FirebaseRemoteConfig.configValuesForKeys(keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the set of parameter keys that start with the given prefix, from the default namespace
|
||||
* @param prefix: The key prefix to look for. If prefix is nil or empty, returns all the keys.
|
||||
* @returns {*|Promise.<Array<String>>}
|
||||
*/
|
||||
keysWithPrefix(prefix: String) {
|
||||
return FirebaseRemoteConfig.keysWithPrefix(prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets config defaults for parameter keys and values in the default namespace config.
|
||||
* @param defaults: A dictionary mapping a String key to a Object values.
|
||||
*/
|
||||
setDefaults(defaults: Object) {
|
||||
FirebaseRemoteConfig.setDefaults(defaults);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets default configs from plist for default namespace;
|
||||
* @param filename: The plist file name, with no file name extension
|
||||
*/
|
||||
setDefaultsFromPlistFileName(filename: String) {
|
||||
FirebaseRemoteConfig.setDefaultsFromPlistFileName(filename);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue