KMP Environment Variables (Part 1)
In this article, I will talk about my experience working with environment variables on Kmm (Kotlin Multiplatform) and how I am currently using it in my project Tv-Maniac
Environment Variables
During the development lifecycle of a mobile app, you may create apps that use API keys or passwords. It is best practice to store such sensitive info in a secure place. In Android, you’d ideally use local.properties
or gradle.properties
to set this up on iOS, configuration files commonly known as xxconfig
The good thing about this is you can configure it to support multiple builds/targets: e.g., Dev
, QA
and Prod
depending on your needs.
Now that we have that in mind, how do we go about this for a KMM project? There are multiple ways you can do this, but I will only talk about the first two since it’s what I have worked with.
- Custom gradle plugin
- BuildKonfig
- Config file reader
- gradle-buildconfig-plugin
1. Custom Gradle Task
I will not go in-depth on this but give an overview. We can use some Gradle utils to generate code from build properties. There are three main concepts that we will need to make this possible.
- Creating a gradle task.
- Defining the generated file.
- Setting the source set
With that in mind, we will need to create a task that produces a file as output. We can use Sync for this. According to Gradle’s documentation, it synchronizes the contents of a destination directory with some source directories and files. It’s more like a copy task.
Once we have that in place, we can dynamically use TestResourceFactory to create files. If you have a custom source set, you will need to define it. Otherwise, gradle won’t recognize it.
You can check out this answer by @aSemy on StackOverflow.
2. BuildKonfig
This is a library that embeds values from a gradle file. If you are an Android dev, this will feel more like home. It’s pretty simple.
I created a small function to help us read from gradle.properties.
Below is how we use the custom function and buildConfig to read from gradle.properties
To generate the files, run ./gradlew generateBuildKonfig
. The generated class will look like so:
3. Config File Reader
We can create a resource reader to help read from yaml
configuration files. The good thing about this is we can easily create multiple environment files for different flavors. Builkonfig supports this, but I have difficulty switching between environments in a different project.
This implementation is from Touchlab’s Droidcon KMM App, which has a neat way of reading files from both iOS and Android. I’d say this is the meat of it. YamlResourceReader
helps us serialize the yaml file into a data class object. readAndDecodeResource
takes in two params:
name
: Name of the yaml file. We have this as a parameter so that you can pass in different files based on the build target you want.strategy
: Serialization strategy. We will be usingkotlinx.serialization
, but you could also use Gson or Jackson.
Android Platform Implementation
We could also use Android AssetManager
to read from the bundled assets context.assets.open(name)
but this example we are using javaClass.classLoader
iOS Platform Implementation
Resources Folder
We then need to add our configuration files. Kmm libraries have a structure folder for resources. You can name them whatever you want. qa.yaml
or release.yaml
depending on your needs. In this case, qa.yaml
.
We need to drag or add the file on iOS, so it’s accessible. For uniformity, I have created a directory called Resources and added the file there.
One extra step was to create a symlink in the root directory so we could easily access it. (This is optional)
Reader Implementation
Tying things up together. We can now use the resource reader and pass the intended file.
Conclusion
There are two things we need to do:
- Remember to add the files on iOS.
- Depending on your application, you might want to ignore the file so you don’t publish sensitive info.
With that, all our resources are in one directory. There might be a better way, but this has worked for me. I’m always up to learning from you, so feel free to poke holes in my implementation. 😅
In part 2, we will look at how to create different build flavors. Until then, happy coding.