KMM Android端如何从打包为AAR的模块中读取assets目录下的文件列表
KMM Android端AAR内资源目录读取解决方案
问题根因
Android 打包AAR及后续集成到APK的过程中,JVM资源的目录条目不会被保留,仅会保留实际文件的完整路径,因此ClassLoader.getResource(文件夹路径) 天然无法在Android运行时环境生效。单元测试可以正常运行是因为测试运行在本地JVM环境,读取的是本地文件系统的真实目录结构,和Android运行时的资源加载逻辑完全不同。
方案1:构建时生成资源索引(跨端通用,推荐)
就是你已经在使用的方案,可通过Gradle自动生成索引避免手动维护,稳定性最高,兼容AAR分发场景:
- 在共享模块的build.gradle.kts中添加自动生成索引的任务:
task generateAssetIndex { def assetsDir = file("src/commonMain/assets") def outputDir = file("src/commonMain/assets") outputs.file(outputDir.resolve("asset_index.json")) doLast { def index = [] fileTree(assetsDir).visit { file -> if (file.isFile() && !file.name.endsWith("asset_index.json")) { // 存储相对assets根目录的路径 index.add(file.relativePath.toString()) } } outputDir.mkdirs() outputDir.resolve("asset_index.json").text = groovy.json.JsonOutput.toJson(index) } } // 绑定到预编译任务,每次构建自动更新索引 tasks.named("preBuild").configure { dependsOn generateAssetIndex }
- common层读取索引后批量加载文件:
// 读取索引文件 val indexContent = this::class.java.classLoader!!.getResource("asset_index.json")?.readText() val allFilePaths = Json.decodeFromString<List<String>>(indexContent) // 筛选指定目录下的文件 val folder1Files = allFilePaths.filter { it.startsWith("folder1/") } // 逐个读取文件 folder1Files.forEach { path -> val fileContent = this::class.java.classLoader!!.getResource(path)?.readText() // 业务逻辑处理文件内容 }
该方案的所有逻辑都可以放在common层,不需要依赖Android专属API,对上层应用完全无感知,适配AAR作为第三方库分发的场景。
方案2:Android专属AssetManager实现
如果可以接受Android端单独实现逻辑,不需要修改构建流程,代码更简洁:
- 首先修改build.gradle.kts的资源配置,将资源从resources改为assets目录配置:
android { compileSdkVersion(29) sourceSets["main"].assets.srcDirs("src/commonMain/assets") ... }
- 通过expect/actual声明获取上下文的方法,Android端返回ApplicationContext,之后调用AssetManager读取目录:
// Android侧实现 actual fun getAssetFileList(folderPath: String): List<String> { // context为你通过KMM注入的Application上下文 return context.assets.list(folderPath)?.toList() ?: emptyList() }
拿到文件名后拼接完整路径,即可按原有方式读取单个文件内容。
方案选择建议
- 若需要尽可能多的逻辑下沉到common层,优先选择构建索引方案
- 若不介意Android端单独适配,优先选择AssetManager方案,无需额外构建配置
内容的提问来源于stack exchange,提问作者Kevin Bassa
相关产品推荐
相关产品推荐

