feat: add kotlin-example module using android-sdk-framework directly#254
feat: add kotlin-example module using android-sdk-framework directly#254typotter wants to merge 1 commit intosnapshot/typo/apr-17from
Conversation
New :kotlin-example Android app demonstrating direct use of :android-sdk-framework (not :eppo). - KotlinxConfigurationParser implements ConfigurationParser<JsonElement> using kotlinx.serialization for parseJsonValue; delegates parseFlagConfig and parseBanditParams to JacksonConfigurationParser (framework DTOs have hand-rolled Jackson deserializers in sdk-common-jvm) - OkHttpEppoClient from sdk-common-jvm:4.0.0-SNAPSHOT for HTTP (OkHttp 4.x) - BaseAndroidClient.Builder wired in EppoApplication.onCreate() - MainActivity shows flag assignment result via getStringAssignment() - Make CachingConfigurationStore.seedCache() public (was package-private, inaccessible from BaseAndroidClient in a different package)
aarsilv
left a comment
There was a problem hiding this comment.
Nice work proving this out in an example!
| * format. Only [parseJsonValue] uses kotlinx.serialization, since that is the method that | ||
| * returns the user-facing [JsonElement] type. | ||
| */ | ||
| class KotlinxConfigurationParser : ConfigurationParser<JsonElement> { |
There was a problem hiding this comment.
Pull request overview
Adds a new Kotlin sample Android app module (:kotlin-example) that demonstrates using :android-sdk-framework directly (w/ kotlinx.serialization for JSON flag values and OkHttp 4.x for HTTP), and adjusts framework visibility to support this usage.
Changes:
- Add new
:kotlin-exampleAndroid application module (Kotlin + kotlinx.serialization + OkHttp). - Wire
BaseAndroidClient.BuilderusingKotlinxConfigurationParserandOkHttpEppoClient. - Make
CachingConfigurationStore.seedCache()public to allow cross-package use fromBaseAndroidClient.
Reviewed changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
settings.gradle |
Includes the new :kotlin-example module in the build. |
build.gradle |
Adds Kotlin Android + Kotlin serialization plugins at the root. |
android-sdk-framework/src/main/java/cloud/eppo/android/framework/storage/CachingConfigurationStore.java |
Makes seedCache() public for use outside the storage package. |
kotlin-example/build.gradle |
Defines the new app module, dependencies (OkHttp, kotlinx.serialization), and BuildConfig API key wiring. |
kotlin-example/src/main/AndroidManifest.xml |
Declares the sample app, EppoApplication, and launcher activity. |
kotlin-example/src/main/kotlin/cloud/eppo/kotlinexample/EppoApplication.kt |
Initializes BaseAndroidClient asynchronously using the framework + OkHttp client. |
kotlin-example/src/main/kotlin/cloud/eppo/kotlinexample/MainActivity.kt |
Displays a sample string assignment result. |
kotlin-example/src/main/kotlin/cloud/eppo/kotlinexample/KotlinxConfigurationParser.kt |
Implements ConfigurationParser<JsonElement> using kotlinx.serialization for JSON values. |
kotlin-example/src/main/res/layout/activity_main.xml |
Basic UI for status + assignment display. |
kotlin-example/src/main/res/values/colors.xml |
Sample theme colors. |
kotlin-example/src/main/res/values/strings.xml |
App strings for UI text. |
kotlin-example/src/main/res/values/themes.xml |
MaterialComponents theme for the sample app. |
kotlin-example/proguard-rules.pro |
Placeholder ProGuard config for the module. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def localProperties = new Properties() | ||
| def localPropertiesFile = rootProject.file('local.properties') | ||
| if (localPropertiesFile.exists()) { | ||
| localProperties.load(new FileInputStream(localPropertiesFile)) |
There was a problem hiding this comment.
The Gradle script loads local.properties via new FileInputStream(...) but never closes the stream. In long-lived Gradle daemons this can leak file descriptors. Use localPropertiesFile.withInputStream { localProperties.load(it) } (or a try-with-resources equivalent) to ensure the stream is closed.
| localProperties.load(new FileInputStream(localPropertiesFile)) | |
| localPropertiesFile.withInputStream { localProperties.load(it) } |
| try { | ||
| json.parseToJsonElement(jsonValue) | ||
| } catch (e: Exception) { | ||
| throw ConfigurationParseException("Failed to parse JSON value: $jsonValue", e) |
There was a problem hiding this comment.
The thrown ConfigurationParseException message includes the full jsonValue string. This can unintentionally leak sensitive flag payloads into logs/crash reports and can also be very large. Prefer omitting the raw value (or logging a truncated/length-only version) and rely on the cause exception for debugging details.
| throw ConfigurationParseException("Failed to parse JSON value: $jsonValue", e) | |
| throw ConfigurationParseException( | |
| "Failed to parse JSON value (length=${jsonValue.length})", | |
| e, | |
| ) |
Summary
New
:kotlin-exampleAndroid application module demonstrating how to use:android-sdk-frameworkdirectly (without going through:eppo). Written in Kotlin, uses kotlinx.serialization for JSON flag values and OkHttp 4.x for HTTP.Stacked on
snapshot/typo/apr-17.What's in this PR
New module:
:kotlin-exampleKotlinxConfigurationParserConfigurationParser<JsonElement>—parseJsonValueuses kotlinx.serialization;parseFlagConfig/parseBanditParamsdelegated toJacksonConfigurationParser(framework DTOs have hand-rolled Jackson deserializers)EppoApplicationBaseAndroidClient.BuilderwithKotlinxConfigurationParser+OkHttpEppoClientinApplication.onCreate()MainActivitygetStringAssignment()Changed:
CachingConfigurationStore.seedCache()visibilityMade
public(was package-private).BaseAndroidClientandCachingConfigurationStoreare in different packages so package-private was inaccessible.Dependency note
Uses
sdk-common-jvm:4.0.0-SNAPSHOTnot3.13.1. The old3.13.1monolithic jar bundleseppo-sdk-frameworkclasses and produces duplicate class errors when combined witheppo-sdk-framework:0.1.0-SNAPSHOTfrom:android-sdk-framework.Resolves #253