KMM中使用OKIO访问commonMain资源文件的路径配置问题
解决KMP中Android端读取commonMain资源文件的问题
问题根源
Android平台打包后,src/commonMain/resources下的文件会被放到APK的assets目录中,而非保留原本地路径。你直接用FileSystem.SYSTEM读取src/resources/initialdata.json这种本地路径,自然会找不到文件。
正确实现方案
1. 修正expect/actual定义(支持协程)
在commonMain中定义带协程的接口:
expect class FileResourceParser { suspend fun parseInitialFile(): String }
2. Android端实际实现
通过Context访问Assets目录读取文件,支持原生流或OKIO两种方式:
actual class FileResourceParser(private val context: Context) { actual suspend fun parseInitialFile(): String { // 原生流方式 return context.assets.open("initialdata.json").use { inputStream -> inputStream.readBytes().decodeToString() } // 或用OKIO方式 // return Okio.buffer(Okio.source(context.assets.open("initialdata.json"))).readUtf8() } }
3. iOS端实际实现
通过App Bundle获取资源路径,再用OKIO读取:
actual class FileResourceParser { actual suspend fun parseInitialFile(): String { val filePath = NSBundle.mainBundle.pathForResource("initialdata.json", null) ?: error("initialdata.json 未在Bundle中找到") return FileSystem.SYSTEM.read(filePath.toPath()) { readUtf8() } } }
4. 修正Realm初始化代码
Realm的initialData是同步执行的,需要用runBlocking包裹协程调用,同时区分平台传入Context(Android):
val config = RealmConfiguration.Builder(schema = schema) .name("boardDb-local") .initialData { val jsonString = runBlocking { val parser = if (Platform.isAndroid) { // 替换为你的ApplicationContext FileResourceParser(applicationContext) } else { FileResourceParser() } parser.parseInitialFile() } val exerciseList: List<Exercise> = Json.decodeFromString(jsonString) // 直接循环写入Realm,无需转RealmList exerciseList.forEach { copyToRealm(it, UpdatePolicy.ALL) } } .log(LogLevel.ALL) .schemaVersion(1) .build()
额外注意事项
- 确保
initialdata.json确实放在src/commonMain/resources目录下,文件名大小写完全匹配(Android对文件名大小写敏感) - Android端获取
ApplicationContext时,避免内存泄漏,建议用Application级别的Context - 若不需要协程,也可以将读取逻辑改为同步,但IO操作尽量放在后台线程执行
内容的提问来源于stack exchange,提问作者Igro182
相关产品推荐
相关产品推荐

