Android中能否编程创建string.xml并保存到项目资源目录?
核心前提说明
Android 应用编译打包后,res/ 目录属于只读的内置资源分区,运行时无法写入或修改文件,因此你无法在已安装的APP运行阶段,直接把生成的strings.xml保存到项目的资源文件夹中,需要根据你的使用场景选择对应的实现方案。
方案1:构建阶段自动生成strings.xml(适合发版前批量同步多语言资源)
如果你的需求是开发阶段把API返回的多语言数据批量生成本地资源文件,打包进APK使用,可以通过Gradle自定义任务实现:
- 在module级别的
build.gradle(一般是app目录下的build.gradle)中添加如下任务,支持自动解析JSON并生成对应语言的strings.xml到指定资源目录:
task generateDynamicStrings(type: DefaultTask) { doLast { // 可替换为请求API拉取最新多语言数据的逻辑 def langJson = new groovy.json.JsonSlurper().parse(new File("本地存储多语言JSON的文件路径")) // 示例为泰米尔语,对应资源目录为values-ta,其他语言替换为对应目录名即可 def stringsDir = new File("app/src/main/res/values-ta/") stringsDir.mkdirs() def stringsFile = new File(stringsDir, "strings.xml") def xmlContent = new StringBuilder() xmlContent.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n") langJson.languageKeys.each { item -> // 转义XML特殊字符,避免格式错误 def escapedValue = item.value .replace("&", "&") .replace("<", "<") .replace(">", ">") .replace("\"", """) .replace("'", "\\'") xmlContent.append(" <string name=\"${item.key}\">${escapedValue}</string>\n") } xmlContent.append("</resources>") stringsFile.text = xmlContent.toString() } } // 绑定到构建流程,每次编译前自动执行任务更新资源 preBuild.dependsOn generateDynamicStrings
- 生成的资源文件和普通手动创建的strings.xml没有区别,可以直接通过
R.string.xxx引用。
方案2:运行时动态加载多语言字符串(适合上线后动态更新多语言内容)
如果你的需求是APP上线后,运行时拉取API的多语言数据动态更新文案,可以采用动态缓存+自定义工具类的方案实现,不需要生成物理XML文件:
- 第一步:API拉取到多语言键值对后,持久化存储到APP可读写的私有目录,比如SharedPreferences、Room数据库、本地JSON文件,同时加载到内存缓存
- 第二步:实现自定义字符串获取工具类,替代系统原生的
getString方法,优先读取动态拉取的文案,兜底读取本地内置的strings.xml资源,示例代码如下:
object DynamicStringProvider { // 内存缓存动态多语言键值对 private val dynamicStringMap = mutableMapOf<String, String>() // 拉取到API数据后调用该方法更新缓存和本地存储 fun updateStrings(newMap: Map<String, String>) { dynamicStringMap.clear() dynamicStringMap.putAll(newMap) // 此处可添加逻辑将newMap写入本地持久化存储,下次启动直接读取无需重复请求 } fun get(context: Context, key: String, vararg formatArgs: Any): String { // 优先取动态拉取的文案 val dynamicValue = dynamicStringMap[key] if (dynamicValue != null) { return if (formatArgs.isNotEmpty()) String.format(dynamicValue, *formatArgs) else dynamicValue } // 兜底读取本地内置资源 val resId = context.resources.getIdentifier(key, "string", context.packageName) return if (resId != 0) { if (formatArgs.isNotEmpty()) context.getString(resId, *formatArgs) else context.getString(resId) } else { key // 极端情况兜底返回key本身,避免崩溃 } } }
- 使用时直接调用
DynamicStringProvider.get(context, "welcome_screen_title")即可获取对应文案。
注意事项
- 动态加载方案无法直接在布局XML中使用
@string/xxx引用动态文案,需要在代码中调用工具类设置文本,也可以通过自定义View扩展布局层面的动态文案支持 - 处理多语言内容时必须做好XML特殊字符转义,避免格式错误或文案显示异常
- 如果需要支持APP内切换语言,需要将不同语言的动态键值对分开存储,切换语言时切换对应的缓存内容
内容的提问来源于stack exchange,提问作者Suman Radhakrishnan
相关产品推荐
相关产品推荐

