Android编译期动态添加assets

背景

开发过程中会有这样一种需求:app需要从远程获取部分前置资源(比如接口配置信息)。通常做法是打包前手动内置到assets中,但这种方式比较低效,今天我们就来讨论一种自动化的过程

自定义Gradle插件获取远程资源并配置到sourceSets中

class PreloadAssetsPlugin : Plugin {
    override fun apply(target: Project) {
        // 判断是否为主工程
        if (target.plugins.hasPlugin("com.android.application")) {
            val pathSeparator = File.separator
            // 自定义asset目录
            val tmpAssetDir = "${target.rootDir}${pathSeparator}tmpasset${pathSeparator}PreloadPlugin${pathSeparator}assets"
            val assetDir = File(tmpAssetDir)
            println(tmpAssetDir)
            // 执行网络请求,获取预加载信息
            if (!assetDir.exists()) {
                assetDir.mkdirs()
            }

            // 缓存文件
            val cacheFile = File(tmpAssetDir, "app_service_api.json")

            // 执行网络请求
            val okHttpClient = OkHttpClient()
            val request = Request.Builder().url("https://api.uomg.com/api/rand.qinghua?format=json")
                .get().build()

            val response = okHttpClient.newCall(request).execute().body?.string()

            // 写入缓存文件
            FileUtils.writeStringToFile(cacheFile, response, "utf-8")

            target.afterEvaluate { project ->
                val android = project.extensions.getByName("android") as AppExtension
                val mainSourceSet = android.sourceSets.getByName("main")
                // 动态添加asset目录
                mainSourceSet.assets.srcDirs(tmpAssetDir)
                println("source assets = ${mainSourceSet.assets.srcDirs}")
            }
        } else {
            throw IllegalStateException("只能在主工程模块中使用资源预加载插件!")
        }
    }
}

使用

应用了该插件build之后,会在项目跟目录生成我们指定的assets目录以及文件


9D9EF183-29A7-4860-A7D4-8AA04EFDF775.png

最终也会打包到app里


2EF39414-FE1A-440d-888A-0B2E976CE8EC.png

最后

上面的demo只是一个思路,最终形态还有需要完善的地方:

  • 临时目录需要配置ignore,避免污染项目代码
  • 文件缓存的策略?每次都需要下载?

你可能感兴趣的:(Android编译期动态添加assets)