Android / Kotlin
This OpenFeature provider has a Kotlin implementation for Android to communicate with the GO Feature Flag Server.
In conjuction with the OpenFeature SDK you will be able to evaluate your feature flags in your Android applications.
For documentation related to flags management in GO Feature Flag, refer to the GO Feature Flag documentation website.
Functionalities:
- Manage the integration of the OpenFeature Android SDK and GO Feature Flag relay-proxy.
- Prefetch and cache flag evaluations in order to give the flag value in an efficient way.
- Automatic configuration changes polling, to be informed as soon as a flag configuration has changed.
- Automatic data collection about which flags have been accessed by the application
Dependency Setup
api("dev.openfeature:android-sdk:0.3.0")
api("org.gofeatureflag.openfeature:gofeatureflag-kotlin-provider0.1.0")
Getting started
Initialize the provider
GO Feature Flag provider needs to be created and then set in the global OpenFeatureAPI.
The only required option to create a GoFeatureFlagProvider
is the URL to your GO Feature Flag relay-proxy instance.
import org.gofeatureflag.openfeature.bean.GoFeatureFlagOptions
import org.gofeatureflag.openfeature.GoFeatureFlagProvider
// ...
val evaluationContext: EvaluationContext = ImmutableContext(
targetingKey = UUID.randomUUID().toString(),
attributes = mapOf( "age" to Value.Integer(22), "email" to Value.String("contact@gofeatureflag.org"))
)
OpenFeatureAPI.setProvider(
GoFeatureFlagProvider(
options = GoFeatureFlagOptions( endpoint = "http://localhost:1031")
),
evaluationContext
)
The evaluation context is the way for the client to specify contextual data that GO Feature Flag uses to evaluate the feature flags, it allows defining rules on the flag.
The targetingKey
is mandatory for GO Feature Flag in order to evaluate the feature flag, it could be the id of a user, a session ID or anything you find relevent to use as identifier during the evaluation.
The setProvider()
function is synchronous and returns immediately however, this does not mean that the provider is ready to be used.
An asynchronous network request to the GO Feature Flag backend to fetch all the flags configured for your application must be completed by the provider first. The provider will then emit a READY
event indicating you can start resolving flags.
If you prefer to wait until the fetch is done you can use the suspend
compatible API available for waiting the Provider to become ready:
runBlocking{
OpenFeatureAPI.shared.setProviderAndWait(
provider = provider,
dispatcher = Dispatchers.IO,
initialContext = evaluationContext
)
}
Available options
When initializing the provider, you can pass some options to configure the provider and how it behaves with GO Feature Flag.
Option name | Type | Default | Description |
---|---|---|---|
endpoint | String | endpoint is the URL where your GO Feature Flag server is located. | |
timeout | Long | 10000 | (optional) timeout is the time in millisecond we wait for an answer from the server. |
maxIdleConnections | Int | 1000 | (optional) maxIdleConnections is the maximum number of connexions in the connexion pool. |
keepAliveDuration | Long | 7200000 | (optional) keepAliveDuration is the time in millisecond we keep the connexion open. |
apiKey | String | (optional) If GO Feature Flag is configured to authenticate the requests, you should provide an API Key to the provider. Please ask the administrator of the relay proxy to provide an API Key. | |
pollingIntervalInMillis | Long | 300000 | (optional) Polling interval in millisecond to check with GO Feature Flag relay proxy if there is a flag configuration change. |
flushIntervalMs | Long | 1000 | (optional) Time to wait before calling GO Feature Flag to store all the data about the evaluation in the relay proxy. |
Update the Evaluation Context
During the usage of your application it may appear that the EvaluationContext
should be updated. For example, if a not logged-in user authentify himself, you will probably have to update the evaluation context.
val newContext: EvaluationContext = ImmutableContext(
targetingKey = userId,
attributes = mapOf( "age" to Value.Integer(32), "email" to Value.String("batman@gofeatureflag.org"))
)
OpenFeatureAPI.setEvaluationContext(newEvalCtx)
setEvaluationContext()
is a synchronous function similar to setProvider()
and will fetch the new version of the feature flags based on this new EvaluationContext
.
Limit the flags to evaluate
By default, the provider will fetch all the flags configured in the GO Feature Flag server to be ready to evaluate them. If you know in advance, what are the flags you will evaluate in your application, you can specify the list of flags to evaluate in the context.
You need to add in the evaluation context the restricted key gofeatureflag.flagList
with the list of flags you want to evaluate.
val newContext: EvaluationContext = ImmutableContext(
targetingKey = "userId",
attributes = mapOf(
"gofeatureflag" to Value.Structure(
mapOf(
"flagList" to Value.List(
listOf(
// list of flags to evaluate
Value.String("flag1"),
Value.String("flag2"),
Value.String("flag3")
)
),
)
),
)
)
OpenFeatureAPI.setEvaluationContext(newEvalCtx)
By setting the gofeatureflag.flagList
key in the context, the provider will only fetch the flags specified in the list.
When limiting the flags to evaluate, if you try to evaluate a flag not in the list, the provider will return the default value with the error FLAG_NOT_FOUND
.
Evaluate a feature flag
The client is used to retrieve values for the current EvaluationContext
. For example, retrieving a boolean value for the flag "my-flag":
val client = OpenFeatureAPI.getClient()
val result = client.getBooleanValue("my-flag", false)
GO Feature Flag supports different all OpenFeature supported types of feature flags, it means that you can use all the accessor directly
// Bool
client.getBooleanValue("my-flag", false)
// String
client.getStringValue("my-flag", "default")
// Integer
client.getIntegerValue("my-flag", 1)
// Double
client.getDoubleValue("my-flag", 1.1)
// Object
client.getObjectValue("my-flag", Value.structure(mapOf("email" to Value.String("contact@gofeatureflag.org"))))
[!NOTE] If you add a new flag in GO Feature Flag, expect some delay before having it available for the provider. Refreshing the cache from remote happens when setting a new provider and/or evaluation context in the global OpenFeatureAPI, but also when a configuration change is detected during the polling.
Handling Provider Events
When setting the provider or the context (via setEvaluationContext()
or setProvider()
) some events can be triggered to know the state of the provider.
To listen to them, you can add an event handler via the OpenFeatureAPI
shared instance:
val coroutineScope = CoroutineScope(Dispatchers.IO)
coroutineScope.launch {
provider.observe<OpenFeatureEvents.ProviderStale>().collect {
providerStaleEventReceived = true
}
}
Existing type of events are:
ProviderReady
: Provider is ready.ProviderError
: Provider in error.ProviderStale
: Provider has not the latest version of the feature flags.ProviderNotReady
: Provider is not ready to evaluate the feature flags.
Features status
Status | Feature | Description |
---|---|---|
✅ | Flag evaluation | It is possible to evaluate all the type of flags |
✅ | Cache invalidation | Websocket mechanism is in place to refresh the cache in case of configuration change |
❌ | Logging | Not supported by the SDK |
❌ | Flag Metadata | Not supported by the SDK |
✅ | Event Streaming | Not implemented |
✅ | Unit test | Not implemented |