# Other third party remote configuration providers

## Check your third party remote configuration provider APIs for compatibility

The third party remote configuration providers' read-property function(s) must return a value synchronously  (cached or default value):

> ✓ Pseudocode examples -  ok

```swift
// ok - returns value immediately
var value = thirdPartyRemoteProvider.getBooleanValue("alwaysDarkMode");

// ok - returns value immediately
var value = thirdPartyRemoteProvider.getBooleanValue("alwaysDarkMode", false);
```

If your third party remote configuration provider's read-property function(s) are marked async, or take a callback/lambda/delegate, then it is incompatible with Appfigurate Library:

> ✗ Pseudocode examples - incompatible third party remote provider

```swift
// not compatible - asynchronous
var value = await thirdPartyRemoteProvider.getBooleanValue("alwaysDarkMode");

// not compatible - callback
thirdPartyRemoteProvider.getBooleanValue("alwaysDarkMode") { value in
    ...
};
```

Also check if your third party remote configuration provider has \`snapshot\` APIs, which should allow synchronous access to a 'snapshot in time' of remote properties (e.g. ConfigCat).

{% hint style="success" %}
Once you've confirmed your third party remote provider has the required synchronous read-property function(s),  you can start integration.&#x20;
{% endhint %}

## Integration of third party remote configuration providers

{% hint style="success" %}
Using Appfigurate remote properties instead of your third party remote configuration provider APIs directly allows for the following:

* locally change third party remote configuration provider properties without affecting your entire customer base.
* compile time type safety - Appfigurate remote properties are typed, third party remote configuration provider properties are not.
* avoids hardcoding duplicated property names throughout your app.
* avoids hardcoding duplicated default values throughout your app.
* deleting a property from your third party remote configuration provider Console won't affect existing apps, they'll continue to use the default value provided in the [`reset`](https://www.electricbolt.co.nz/api/Classes/APLConfiguration.html#/c:objc\(cs\)APLConfiguration\(im\)reset) method.
  {% endhint %}

We assume you already have Appfigurate Library and your third party remote provider integrated into your app with the following example remote properties created in the third party remote provider's Console:

| Remote property key | Remote property type |
| ------------------- | -------------------- |
| alwaysDarkMode      | boolean              |
| appTitle            | string               |
| bookingDuration     | integer              |
| fontSize            | double               |

### Add remote properties into your Configuration subclass

Update your configuration subclass to include your remote configuration properties. Provide default values for the properties in the overridden [`reset`](https://www.electricbolt.co.nz/api/Classes/APLConfiguration.html#/c:objc\(cs\)APLConfiguration\(im\)reset) method.  See also [Supported property types](/configuration-subclasses/supported-property-types.md#remote-properties).

{% tabs %}
{% tab title="Swift" %}

> Swift Configuration example

```swift
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
    }
...
}
```

{% endtab %}

{% tab title="Objective-C" %}

> Objective-C Configuration header example

```objectivec
@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

```objectivec
#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
```

{% endtab %}
{% endtabs %}

## Provide remote configuration values to Appfigurate Library when requested

Appfigurate Library needs to be able to read the current remote configuration values from your third party remote configuration provider.

{% tabs %}
{% tab title="With default value parameter" %}
If your third party remote configuration provider's read-property function(s) have a default value parameter, then Appfigurate Library passes across the correct default value of the remote property to the callback:

> Pseudocode example

```swift
// add the following function call before initializing the third party remote provider.
APLFetchRemoteConfiguration { propertyKey, propertyType, defaultValue in
    if (propertyType == RemotePropertyTypeBool) {
        return this.thirdPartyRemoteProvider.getBooleanValue(propertyKey, defaultValue as Boolean);
    } else if (propertyType == RemotePropertyTypeInt) {
        return this.thirdPartyRemoteProvider.getIntegerValue(propertyKey, defaultValue as Int);
    } else if (propertyType == RemotePropertyTypeDouble {
        return this.thirdPartyRemoteProvider.getDoubleValue(propertyKey, defaultValue as Double);
    } else // RemotePropertyTypeString {
        return this.thirdPartyRemoteProvider.getStringValue(propertyKey, defaultValue as String);
    }
};
...
// initialize the third party remote provider
this.thirdPartyRemoteProvider = ThirdPartyRemoteProvider.initAndConfigure("1fa0b704-8e22-4314");
```

{% endtab %}

{% tab title="Without default value parameter" %}
If your third party remote configuration provider's read-property function(s) doesn't have a default value parameter, then it will likely require default values to be set at the start of your app. (e.g. Firebase does, Launch Darkly doesn't).&#x20;

We recommend you use the default values set in the [`reset`](https://www.electricbolt.co.nz/api/Classes/APLConfiguration.html#/c:objc\(cs\)APLConfiguration\(im\)reset) method of your configuration subclass. You can get the default values using the `remoteDefaults` method, which returns a `Dictionary` of property key/value pairs:

> Pseudocode example

```swift
// add the following function call before initializing the third party remote provider.
APLFetchRemoteConfiguration { propertyKey, propertyType, defaultValue in
    if (propertyType == RemotePropertyTypeBool) {
        return this.thirdPartyRemoteProvider.getBooleanValue(propertyKey);
    } else if (propertyType == RemotePropertyTypeInt) {
        return this.thirdPartyRemoteProvider.getIntegerValue(propertyKey);
    } else if (propertyType == RemotePropertyTypeDouble) {
        return this.thirdPartyRemoteProvider.getDoubleValue(propertyKey);
    } else { // RemotePropertyTypeString
        return this.thirdPartyRemoteProvider.getStringValue(propertyKey);
    }
};
...
// initialize third party remote provider
this.thirdPartyRemoteProvider = ThirdPartyRemoteProvider.initAndConfigure("1fa0b704-8e22-4314");
...
// initialize third party remote provider default values
var defaults = APLConfiguration.shared().remoteDefaults();
this.thirdPartyRemoteProvider.setDefaultBooleanValue(forKey: "alwaysDarkMode", value: defaults["alwaysDarkMode"]);
this.thirdPartyRemoteProvider.setDefaultIntegerValue(forKey: "bookingDuration", value: defaults["bookingDuration"]);
...
```

{% endtab %}
{% endtabs %}

## Notify Appfigurate Library when the third party remote configuration provider has received remote config

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

> Pseudocode example

```swift
remoteProvider.setOnFetchCallback { status, error in
    if (status == .receivedConfiguration) {
        ...
        APLFlushRemoteConfiguration(); // add this line
    }
}
```

## Best practice and usage

Replace all calls to your third party remote configuration providers read-property function(s):

> Pseudocode example

```swift
if (remoteProvider.getBooleanValue("alwaysDarkMode", defaultValue: false) {
    ...
```

with the following:

> Pseudocode example

```swift
if (APLConfiguration.shared().alwaysDarkMode) {
    ...
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.electricbolt.co.nz/getting-started/third-party-remote-configuration-providers/other-third-party-remote-configuration-providers.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
