Thomas Skovsgaard
06/28/2023, 9:31 AMThomas Skovsgaard
06/28/2023, 9:36 AMAdam S
06/28/2023, 9:46 AMJeff Lockhart
06/28/2023, 9:48 AMThomas Skovsgaard
06/28/2023, 9:49 AMAdam S
06/28/2023, 9:55 AMloadResource()
function, so long as you know how to load a resource for each specific target?Thomas Skovsgaard
06/28/2023, 9:57 AMJeff Lockhart
06/28/2023, 9:58 AMcommonMain/resources
are bundled with your app package. Second, you can create a common interface that both platforms can implement to then read the resource from the app bundle.Jeff Lockhart
06/28/2023, 10:10 AMexpect fun getAsset(asset: String): Source?
and then implement that API in a platform-specific way for each of your supported platforms. E.g. in androidMain:
actual fun getAsset(asset: String): Source = context.assets.open(asset).source()
and in iosMain:
actual fun getAsset(asset: String): Source? {
val dotIndex = asset.lastIndexOf('.')
val name = asset.substring(0, dotIndex)
val type = asset.substring(dotIndex + 1)
val path = NSBundle.mainBundle
.pathForResource(name, type)
?: return null
return FileSystem.SYSTEM.source(path.toPath())
}
These are implementations in my project using Okio's Source as an input stream return type.Jeff Lockhart
06/28/2023, 10:12 AMContext
in your implementation. Alternatively, you don't even need to use `expect`/`actual`. You can just define an interface and then inject a platform-specific implementation to use.Jeff Lockhart
06/28/2023, 10:26 AMcommonMain/resources
in your application bundles, for Android I've just symlinked androidMain/resources/assets
to commonMain/resources
.
iOS is the most complicated, as you need to hook into the gradle task that builds the framework to copy the resources into it. It depends how you're building the framework, which task this will be (CocoaPods plugin, XCFramework, fat framework, etc.). Here's some code I wrote to do this.
Instead of creating a separate Gradle task, it's actually better practice to hook into the existing task with doFirst
or doLast
and perform the file copy there, so you don't have multiple tasks with the same output directory. I should update that code.Jeff Lockhart
06/28/2023, 10:49 AMPaul Woitaschek
06/28/2023, 11:41 AMconst val
to your commonMain source setephemient
06/28/2023, 12:05 PMephemient
06/28/2023, 12:10 PMephemient
06/28/2023, 12:11 PMMichael Paus
06/28/2023, 1:16 PMcoroutineScope.launch {
try {
val configString = resource("config.json").readBytes().decodeToString()
_masterModelState.update { s -> s.copy(config = format.decodeFromString(configString)) }
} catch (e: Exception) {
log.error(e) { "Could not read configuration resource file." }
}
}
config.json
in commonMain/resources/
resource
from package org.jetbrains.compose.resources
json
from Json
in package kotlinx.serialization.json
This should work out of the box on Desktop, Android and iOS. I haven’t tried other platforms though.Christian Gaisl
06/28/2023, 1:44 PMPaul Woitaschek
06/28/2023, 3:03 PMRobert Munro
06/28/2023, 5:13 PMJeff Lockhart
06/28/2023, 5:34 PMNSBundle.mainBundle
, use NSBundle.bundleWithIdentifier("shared.framework.bundle.ID")
. The shared framework bundle ID should be the {module.group}.{framework.name}
.Charles Prado
11/05/2023, 1:59 PMSivaraj
12/08/2023, 10:26 AM<key>CFBundleIdentifier</key>
<string>com.example.abc.shared</string>
And i was using the below code to list all the files.
NSBundle.bundleWithIdentifier("com.example.abc.shared.framework")?.pathsForResourcesOfType(
inDirectory = rootFolder,
ext = null
) as List<String>
}
Jeff Lockhart
12/08/2023, 6:42 PM.framework
suffix. The CFBundleIdentifier
string itself should work.Sivaraj
12/08/2023, 11:53 PM