ktembed
0.1.6indexedEmbed static resources into binaries via compile-time Base64 encoding with generated ResourceDirectory, lazy decoding, smart in-memory/disk caching, integrity validation, and configurable optimization strategies.
Embed static resources into binaries via compile-time Base64 encoding with generated ResourceDirectory, lazy decoding, smart in-memory/disk caching, integrity validation, and configurable optimization strategies.
Embed static resources directly into your Kotlin binaries
KtEmbed is a Kotlin Multiplatform library and Gradle plugin that lets you embed static resources (text, JSON, HTML, images, etc.) directly into your compiled applications. Resources are encoded as Z85 strings at compile time and can be accessed efficiently at runtime with automatic caching and optimization strategies.
Add the KtEmbed plugin to your build.gradle.kts:
plugins {
id("dev.ktool.ktembed") version "0.0.1"
}
ktembed {
packageName = "com.example.resources"
resourceDirectories = listOf("src/main/resources")
}
import com.example.resources.ResourceDirectory
// Initialize the Resources instance
val resources = ResourceDirectory.toResources()
config = resources.asString()
image = resources.asBytes()
(resources.exists()) {
println(resources.asString())
}
FileOutputStream().use { ->
resources.write(, )
}
filePath = resources.asPath()
// In settings.gradle.kts
pluginManagement {
repositories {
gradlePluginPortal()
}
}
// In build.gradle.kts
plugins {
id("dev.ktool.ktembed") version "0.1.1"
}
dependencies {
implementation("dev.ktool:ktembed-runtime:0.1.1")
}
The ktembed extension provides the following configuration options:
ktembed {
// Package for generated code
packageName = "com.myapp.assets"
// Multiple resource directories
resourceDirectories = listOf(
"src/main/resources",
"assets",
"static"
)
// Filter function to exclude files
exclude = { path ->
path.endsWith(".tmp") || // Ignore temp files
path.contains(".git") || // Ignore git files
path.startsWith("private/") // Ignore private directory
}
}
The main API for accessing embedded resources.
exists(path: String): BooleanCheck if a resource exists at the given path.
if (resources.exists("config.json")) {
// Resource exists
}
asString(path: String): StringRead resource as UTF-8 string. Result is cached in memory.
val json = resources.asString("data.json")
asByteArray(path: String): ByteArrayRead resource as bytes. Result is cached in memory.
val imageData = resources.asByteArray("image.png")
asPath(path: String): Path?Get a file system path to the resource. The resource is extracted to a cache directory and validated.
val configFile = resources.asPath("config.properties")
// Use with libraries that need file paths
write(path: String, output: Sink)Write resource to an Okio Sink. Automatically chooses optimization strategy based on inMemoryCutoff.
FileSystem.SYSTEM.sink(outputPath).use { sink ->
resources.write("large-file.bin", sink)
}
write(path: String, output: Sink, strategy: OptimizationStrategy)Write resource with explicit optimization strategy.
resources.write("data.bin", sink, OptimizationStrategy.Memory)
write(path: String, out: OutputStream) (JVM only)Write resource to a Java OutputStream.
FileOutputStream("output.txt").use { out ->
resources.write("input.txt", out)
}
Choose between speed and memory efficiency:
enum class OptimizationStrategy {
Speed, // Load entire resource into memory (faster)
Memory // Stream from disk cache (uses less memory)
}
When to use:
Speed: Small resources, frequent access, plenty of memoryMemory: Large resources (>6MB), infrequent access, memory-constrained environmentsResources class and are lazily decoded and cached as neededByteArray and String values are cached per Resource instanceResources extracted to disk are automatically validated:
val filePath = resources.asPath("important.dat")
// File is validated by comparing hashes
// If validation fails, the file is regenerated
write() for large files instead of asBytes() to avoid loading into memoryEnsure the generateKtEmbedResources task runs before compilation:
tasks.named("compileKotlin") {
dependsOn("generateKtEmbedResources")
}
This is handled automatically by the plugin, but can be added explicitly if needed.
Reduce the inMemoryCutoff value:
val resources = Resources(ResourceDirectory(), inMemoryCutoff = 1_000_000) // 1MB
Or use OptimizationStrategy.Memory for large resources:
resources.write("large-file.bin", output, OptimizationStrategy.Memory)
The filter function returns true for paths to ignore:
// Correct: ignore .tmp files
filter = { path -> path.endsWith(".tmp") }
// Incorrect: this would ignore everything EXCEPT .tmp files
filter = { path -> !path.endsWith(".tmp") }
| Property | Type | Required | Description |
|---|
packageName | String | Yes | Package name for the generated ResourceDirectory class |
resourceDirectories | StringList | Yes | Directories to scan for resources |
exclude | (String) -> Boolean | No | Function to exclude paths (returns true to ignore) |
inMemoryCutoff based on your application's memory constraintsOptimizationStrategy.Memory for resources >4MBResources instance - don't create multiple instances of the same ResourceDirectorySurfaced from shared tags and platforms — no rankings paid for.