Appfigurate™️
HomeDocumentation
  • Introducing Appfigurate™️ 3
  • Getting Started
    • Getting Started
    • Examples
    • Upgrade guide
      • v1.4.0 to v2.2.0
      • v2.1.1 to v2.2.0
      • v2.2.1 to v3.0.0
      • v3.2.1 to v4.0.0
    • iOS native app integration
      • iOS app extension integration
    • watchOS app integration
      • watchOS app extension integration
    • Android native app integration
    • Mobile Flutter integration
      • Flutter iOS
      • Flutter Android
    • React Native integration
      • iOS native module integration
      • Android native module integration
      • JavaScript integration
    • Third party remote configuration providers
      • Firebase Remote Config
      • Launch Darkly
      • Other third party remote configuration providers
  • Configuration subclasses
    • Supported property types
      • Boolean
      • Integer
      • Float
      • Double
      • Plain String
      • Encrypted String
    • Custom executable actions
    • Slider icon types
  • Additional reading
    • Info.plist options
    • AndroidManifest.xml options
    • Displaying overridden configuration
    • Security
      • Best practice
      • Encryption
      • Export compliance
      • App Store compliance
      • PrivacyInfo.xcprivacy
      • Rotating your private key
  • Automation testing
    • iOS native app automation testing
    • Android native automation testing
  • API
    • iOS and watchOS API
    • Android API
    • Mobile Flutter API
    • React Native API
  • Appfigurate User Guide
    • Introduction
    • Main menu
    • Select app
    • Add app
    • Import app
    • Install example apps
    • Settings
      • Passcode Lock
      • Restore
      • Backup
      • Delete all apps and Settings
      • Analytics
    • Edit app
    • Configure app
    • Permissions
  • Appfigurate SE user guide
    • Introduction
    • Manual encryption
      • ENCRYPTED_STRING macro/function
      • ENCRYPTED_STRING_IOS_WATCHOS macro/function
    • Setup iOS Simulator app
    • Setup Android Emulator app
    • Xcode source editor extension
      • Troubleshooting
    • Real device cloud testing services
      • BrowserStack
  • LEGAL
    • License Agreement
    • Privacy Policy
    • Release History
    • Third party notices
Powered by GitBook
On this page
  • Add remote properties into your Configuration subclass
  • Provide remote configuration values to Appfigurate Library when requested
  • Apply default values to Firebase
  • Notify Appfigurate Library when Firebase has received remote configuration values
  • Best practice and usage
  1. Getting Started
  2. Third party remote configuration providers

Firebase Remote Config

Tested with Firebase version 10.29.0 (iOS)

PreviousThird party remote configuration providersNextLaunch Darkly

Last updated 4 months ago

Third party remote configuration provider integration is currently in private beta and will be available in the next major release of Appfigurate.

Using Appfigurate remote properties instead of Firebase APIs directly allows for the following:

  • locally change Firebase remote configuration without affecting your entire customer base.

  • compile time type safety - Appfigurate remote properties are typed, Firebase remote configuration is not.

  • avoids hardcoding duplicated flag names throughout your app.

  • deleting a remote configuration property from Firebase Console won't affect existing apps, they'll continue to use the default value provided in the method.

We assume you already have Appfigurate Library and integrated into your app with the following example remote properties created in the :

Add remote properties into your Configuration subclass

Swift Configuration example

import Foundation
import AppfigurateLibrary

@objcMembers class MyConfiguration: APLConfiguration {
...
    @RemoteBoolProperty(remoteKey: "alwaysDarkMode", description: "Force dark mode to be always set")
    var alwaysDarkMode: Bool

    @RemoteStringPropertyEdit(remoteKey: "appTitle", description: "Title of application")
    var appTitle: String

    @RemoteIntPropertyEdit(remoteKey: "bookingDuration", description: "Duration (days) for reservation bookings")
    var bookingDuration: Int

    @RemoteDoublePropertyEdit(remoteKey: "fontSize", description: "Size of font throughout app")
    var fontSize: Double
...
    override func reset() {
        alwaysDarkMode = false
        appTitle = "Holiday finder"
        bookingDuration = 30
        fontSize = 13.0
    }
...
}

Objective-C Configuration header example

@import Foundation;
@import AppfigurateLibrary;

@interface MyConfiguration : APLConfiguration
...
@property(nonatomic, assign) BOOL alwaysDarkMode;
@property(nonatomic, strong) NSString* appTitle;
@property(nonatomic, assign) NSInteger bookingDuration;
@property(nonatomic, assign) double fontSize;
...
@end

Objective-C Configuration implementation example

#import "MyConfiguration.h"

@implementation MyConfiguration
...
REMOTE_BOOL_PROPERTY(alwaysDarkMode, @"alwaysDarkMode", @"Force dark mode to be always set");
REMOTE_STRING_PROPERTY_EDIT(appTitle, @"appTitle", @"Title of application");
REMOTE_INT_PROPERTY_EDIT(bookingDuration, @"bookingDuration", @"Duration (days) for reservation bookings");
REMOTE_DOUBLE_PROPERTY_EDIT(fontSize, @"fontSize", @"Size of font throughout app");
...
- (void) reset {
    self.alwaysDarkMode = NO;
    self.appTitle = @"Holiday finder";
    self.bookingDuration = 30;
    self.fontSize = 13.0;
}
...
@end

Kotlin Configuration example

package com.yourcompany.yourapp

import nz.co.electricbolt.appfiguratelibrary.annotations.RemoteBooleanProperty
import nz.co.electricbolt.appfiguratelibrary.annotations.RemoteDoublePropertyEdit
import nz.co.electricbolt.appfiguratelibrary.annotations.RemoteIntPropertyEdit
import nz.co.electricbolt.appfiguratelibrary.annotations.RemoteStringPropertyEdit

class MyConfiguration : nz.co.electricbolt.appfiguratelibrary.Configuration() {
...
    @RemoteBooleanProperty(remoteKey = "alwaysDarkMode", description = "Force dark mode to be always set")
    var alwaysDarkMode: Boolean = false

    @RemoteStringPropertyEdit(remoteKey = "appTitle", description = "Title of application")
    var appTitle: String? = null

    @RemoteDoublePropertyEdit(remoteKey = "fontSize", description = "Size of font throughout app")
    var fontSize: Double = 0.0

    @RemoteIntPropertyEdit(remoteKey = "bookingDuration", description = "Duration (days) for reservation bookings")
    var bookingDuration: Int = 0
...
    override fun reset() {
        alwaysDarkMode = false
        appTitle = "Holiday finder"
        bookingDuration = 30  
        fontSize = 13.0
    }
}

Java Configuration example

package com.yourcompany.yourapp;

import nz.co.electricbolt.appfiguratelibrary.annotations.RemoteBooleanProperty;
import nz.co.electricbolt.appfiguratelibrary.annotations.RemoteDoublePropertyEdit;
import nz.co.electricbolt.appfiguratelibrary.annotations.RemoteIntPropertyEdit;
import nz.co.electricbolt.appfiguratelibrary.annotations.RemoteStringPropertyEdit;

public class MyConfiguration extends nz.co.electricbolt.appfiguratelibrary.Configuration {
...
    @RemoteBooleanProperty(remoteKey = "alwaysDarkMode", description = "Force dark mode to be always set")
    public boolean alwaysDarkMode;

    @RemoteStringPropertyEdit(remoteKey = "appTitle", description = "Title of application")
    public String appTitle;

    @RemoteDoublePropertyEdit(remoteKey = "fontSize", description = "Size of font throughout app")
    public double fontSize;

    @RemoteIntPropertyEdit(remoteKey = "bookingDuration", description = "Duration (days) for reservation bookings")
    public int bookingDuration;
...
    @Override
    public void reset() {
        alwaysDarkMode = false;
        appTitle = "Holiday finder";
        bookingDuration = 30;        
        fontSize = 13.0;
    }
...
}

Provide remote configuration values to Appfigurate Library when requested

Appfigurate Library needs to be able to read the current remote configuration values from Firebase. Copy and paste the following code into your app.

Swift example

APLFetchRemoteConfiguration { remoteKey, propertyType, defaultValue in
    if propertyType == .string {
        return self.remoteConfig.configValue(forKey: remoteKey).stringValue as NSObject
    } else if propertyType == .bool {
        return self.remoteConfig.configValue(forKey: remoteKey).boolValue as NSObject
    } else { // .int || .double
        return self.remoteConfig.configValue(forKey: remoteKey).numberValue as NSObject
    }
}

Objective-C example

APLFetchRemoteConfiguration(^NSObject* (NSString* remoteKey, APLRemotePropertyType propertyType, NSObject* defaultValue) {
    if (propertyType == APLRemotePropertyTypeString) {
        return [self.remoteConfig configValueForKey: remoteKey].stringValue;
    } else if (propertyType == APLRemotePropertyTypeBool) {
        return [NSNumber numberWithBool: [self.remoteConfig configValueForKey: remoteKey].boolValue];
    } else { // APLRemotePropertyTypeInt || APLRemotePropertyTypeDouble
        return [self.remoteConfig configValueForKey: remoteKey].numberValue;
    }
});

Kotlin example

Appfigurate.fetchRemoteConfiguration { remoteKey: String, propertyType: RemotePropertyType, defaultValue: Any? ->
    when (propertyType) {
        RemotePropertyTypeString -> this.remoteConfig.getString(remoteKey)
        RemotePropertyTypeBoolean -> this.remoteConfig.getBoolean(remoteKey)
        RemotePropertyTypeInt -> this.remoteConfig.getLong(remoteKey)
        RemotePropertyTypeDouble -> this.remoteConfig.getDouble(remoteKey)
    }
}

Java example

Appfigurate.fetchRemoteConfiguration((remoteKey, propertyType, defaultValue) -> {
    return switch (propertyType) {
        case RemotePropertyTypeString -> this.remoteConfig.getString(remoteKey);
        case RemotePropertyTypeBoolean -> this.remoteConfig.getBoolean(remoteKey);
        case RemotePropertyTypeInt -> this.remoteConfig.getLong(remoteKey);
        case RemotePropertyTypeDouble -> this.remoteConfig.getDouble(remoteKey);
    };
});

Apply default values to Firebase

Swift example

FirebaseApp.configure()
self.remoteConfig = RemoteConfig.remoteConfig()
...
// add the following line
self.remoteConfig.setDefaults(APLConfiguration.shared().remoteDefaults())

Objective-C example

[FIRApp configure];    
self.remoteConfig = [FIRRemoteConfig remoteConfig];
...
// add the following line
[self.remoteConfig setDefaults: [[APLConfiguration sharedConfiguration] remoteDefaults]];

Kotlin example

FirebaseApp.initializeApp(this)
this.remoteConfig = FirebaseRemoteConfig.getInstance()
...
// add the following line
this.remoteConfig.setDefaultsAsync(Configuration.sharedConfiguration().remoteDefaults())

Java example

FirebaseApp.initializeApp(this)
this.remoteConfig = FirebaseRemoteConfig.getInstance()
...
// add the following line
this.remoteConfig.setDefaultsAsync(Configuration.sharedConfiguration().remoteDefaults());

Notify Appfigurate Library when Firebase has received remote configuration values

We need to tell Appfigurate Library that Firebase has received remote configuration, so that it can keep your Configuration subclass remote properties in sync.

Add a call to APLFlushRemoteConfiguration in any existing Firebase Remote Config activate(completion:) blocks (inside fetch(completionHandler:) and optionally addOnConfigUpdateListener(remoteConfigUpdateCompletion:).

Swift example

self.remoteConfig.fetch { status, error in
    if status == .success {
        self.remoteConfig.activate { changed, error in
            ...
            APLFlushRemoteConfiguration() // add this line
        }
    }
}

Add a call to APLFlushRemoteConfiguration in any existing Firebase Remote Config activateWithCompletion: blocks (inside fetchWithCompletionHandler: and optionally addOnConfigUpdateListener:).

Objective-C example

__weak __typeof__(self) weakSelf = self;
[self.remoteConfig fetchWithCompletionHandler: ^(FIRRemoteConfigFetchStatus status, NSError* error) {
    if (status == FIRRemoteConfigFetchStatusSuccess) {
        __typeof__(self) strongSelf = weakSelf;
        [strongSelf.remoteConfig activateWithCompletion: ^(BOOL changed, NSError* error) {
             ...
             APLFlushRemoteConfiguration(); // add this line
        }];
}];

Add a call to Appfigurate.flushRemoteConfiguration in your existing Firebase Remote Config fetchAndActivate block:

Kotlin fetch and activate example

this.remoteConfig.fetchAndActivate().addOnCompleteListener(this) { task ->
    if (task.isSuccessful()) {
        ...
        Appfigurate.flushRemoteConfiguration() // add this line
    }
}

If you are optionally using Firebase Remote Config real time updates add a call to Appfigurate.flushRemoteConfiguration in your existing addOnConfigUpdateListener block:

Kotlin real time update example

this.remoteConfig.addOnConfigUpdateListener(object : ConfigUpdateListener {
    override fun onUpdate(configUpdate: ConfigUpdate) {
        FirebaseRemoteConfig.getInstance().activate().addOnCompleteListener {
            ...
            Appfigurate.flushRemoteConfiguration() // add this line
        }
    }
    ...
})

Add a call to Appfigurate.flushRemoteConfiguration in your existing Firebase Remote Config fetchAndActivate block:

Java fetch and activate example

this.remoteConfig.fetchAndActivate().addOnCompleteListener(this, task -> {
    if (task.isSuccessful()) {
        ...
        Appfigurate.flushRemoteConfiguration(); // add this line
    }
});

If you are optionally using Firebase Remote Config real time updates add a call to Appfigurate.flushRemoteConfiguration in your existing addOnConfigUpdateListener block:

Java real time update example

this.remoteConfig.addOnConfigUpdateListener(new ConfigUpdateListener() {
    @Override public void onUpdate(ConfigUpdate configUpdate) {
        this.remoteConfig.activate().addOnCompleteListener(task -> {
            if (task.isSuccessful()) {
                ...
                Appfigurate.flushRemoteConfiguration(); // add this line
            }
        });
    }
    ...
});

Best practice and usage

Replace all calls to Firebase Remote Config configValue(forKey:):

if remoteConfig.configValue(forKey: "alwaysDarkMode").boolValue {
   ...

with the following:

if (APLConfiguration.shared() as! MyConfiguration).alwaysDarkMode {
   ...

Replace all calls to Firebase Remote Config configValueForKey:

if ([remoteConfig configValueForKey: @"alwaysDarkMode"].boolValue]) {
   ...

with the following:

if (((MyConfiguration*) [APLConfiguration sharedConfiguration]).alwaysDarkMode) {
   ...

Replace all calls to Firebase Remote Config getBoolean(), getLong(), getDouble(), getString()

if (this.remoteConfig.getBoolean("alwaysDarkMode")) {
   ...

with the following:

if (((MyConfiguration) Configuration.sharedConfiguration()).alwaysDarkMode) {
   ...

Update your configuration subclass to include your remote configuration properties. Provide default values for the properties in the overridden method. See also .

The defaultValue parameter in the callback is not used with Firebase. See the section below.

Apply default values to Firebase using the values you set in the method of your configuration subclass. The default values are used by Firebase when the remote configuration has not yet been received.

The class has a method remoteDefaults which provides a Dictionary of all the remote configuration property default values that were set in your overridden method.

The class has a method remoteDefaults which provides a NSDictionary* of all the remote configuration property default values that were set in your overridden method.

The class has a method remoteDefaults which provides a HashMap<String,Object> of all the remote configuration property default values that were set in your overridden method.

The class has a method remoteDefaults which provides a HashMap<String,Object> of all the remote configuration property default values that were set in your overridden method.

reset
APLConfiguration
reset
APLConfiguration
reset
nz.co.electricbolt.appfiguratelibrary.Configuration
reset
nz.co.electricbolt.appfiguratelibrary.Configuration
reset
Apply default values for Firebase
reset
Firebase
Firebase Console
reset
Supported property types