Skip to content

feat: add kotlin-example module using android-sdk-framework directly#254

Draft
typotter wants to merge 1 commit into
snapshot/typo/apr-17from
muse/kotlin-framework-example-app
Draft

feat: add kotlin-example module using android-sdk-framework directly#254
typotter wants to merge 1 commit into
snapshot/typo/apr-17from
muse/kotlin-framework-example-app

Conversation

@typotter

Copy link
Copy Markdown
Collaborator

Summary

New :kotlin-example Android application module demonstrating how to use :android-sdk-framework directly (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-example

File Purpose
KotlinxConfigurationParser ConfigurationParser<JsonElement>parseJsonValue uses kotlinx.serialization; parseFlagConfig/parseBanditParams delegated to JacksonConfigurationParser (framework DTOs have hand-rolled Jackson deserializers)
EppoApplication Wires BaseAndroidClient.Builder with KotlinxConfigurationParser + OkHttpEppoClient in Application.onCreate()
MainActivity Shows flag assignment result via getStringAssignment()

Changed: CachingConfigurationStore.seedCache() visibility

Made public (was package-private). BaseAndroidClient and CachingConfigurationStore are in different packages so package-private was inaccessible.

Dependency note

Uses sdk-common-jvm:4.0.0-SNAPSHOT not 3.13.1. The old 3.13.1 monolithic jar bundles eppo-sdk-framework classes and produces duplicate class errors when combined with eppo-sdk-framework:0.1.0-SNAPSHOT from :android-sdk-framework.

Resolves #253

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 aarsilv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔥

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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-example Android application module (Kotlin + kotlinx.serialization + OkHttp).
  • Wire BaseAndroidClient.Builder using KotlinxConfigurationParser and OkHttpEppoClient.
  • Make CachingConfigurationStore.seedCache() public to allow cross-package use from BaseAndroidClient.

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))

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
localProperties.load(new FileInputStream(localPropertiesFile))
localPropertiesFile.withInputStream { localProperties.load(it) }

Copilot uses AI. Check for mistakes.
try {
json.parseToJsonElement(jsonValue)
} catch (e: Exception) {
throw ConfigurationParseException("Failed to parse JSON value: $jsonValue", e)

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
throw ConfigurationParseException("Failed to parse JSON value: $jsonValue", e)
throw ConfigurationParseException(
"Failed to parse JSON value (length=${jsonValue.length})",
e,
)

Copilot uses AI. Check for mistakes.
@aarsilv

aarsilv commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@aarsilv, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 59 minutes and 38 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3311cbde-5729-4030-90b1-82f37c703160

📥 Commits

Reviewing files that changed from the base of the PR and between 2099f50 and ed5cb99.

📒 Files selected for processing (13)
  • android-sdk-framework/src/main/java/cloud/eppo/android/framework/storage/CachingConfigurationStore.java
  • build.gradle
  • kotlin-example/build.gradle
  • kotlin-example/proguard-rules.pro
  • kotlin-example/src/main/AndroidManifest.xml
  • kotlin-example/src/main/kotlin/cloud/eppo/kotlinexample/EppoApplication.kt
  • kotlin-example/src/main/kotlin/cloud/eppo/kotlinexample/KotlinxConfigurationParser.kt
  • kotlin-example/src/main/kotlin/cloud/eppo/kotlinexample/MainActivity.kt
  • kotlin-example/src/main/res/layout/activity_main.xml
  • kotlin-example/src/main/res/values/colors.xml
  • kotlin-example/src/main/res/values/strings.xml
  • kotlin-example/src/main/res/values/themes.xml
  • settings.gradle

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants