You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何动态更新或替换Android应用对应语言的strings.xml文件

Android 动态更新strings.xml实现方案

原生Android的strings.xml是编译时打包进APK的,没法直接替换原文件,所以得换个思路——绕过系统原生资源加载,自定义一套字符串读取逻辑,优先用服务器下载的语言资源, fallback到系统默认资源。下面是具体实现步骤:

一、定义服务器返回的资源格式

建议用JSON格式(比XML解析更简单高效),比如对应中文的资源:

{
  "app_name": "我的新应用",
  "welcome_msg": "欢迎使用动态更新版",
  "btn_submit": "提交"
}

如果坚持用XML,也可以让服务器返回标准的<resources>结构的XML文件。

二、下载并存储资源

  1. 发起网络请求下载对应语言的资源文件(根据当前系统Locale判断要下载的语言包,比如zh-CN、en-US)
  2. 把下载的文件存在应用内部存储的私有目录(比如context.getFilesDir()),避免外部存储权限问题,同时可以按语言+版本号命名,比如strings_zh-CN_v2.json,方便版本管理和更新判断。

示例代码(用OkHttp做下载):

OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
        .url("https://your-server.com/langs/strings_zh-CN.json")
        .build();

client.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        // 下载失败,继续用默认资源
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        if (response.isSuccessful() && response.body() != null) {
            String jsonContent = response.body().string();
            // 保存到内部存储
            File file = new File(context.getFilesDir(), "strings_zh-CN.json");
            FileWriter writer = new FileWriter(file);
            writer.write(jsonContent);
            writer.close();
            // 通知界面刷新字符串
            LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("REFRESH_STRINGS"));
        }
    }
});

三、实现自定义字符串加载工具类

写一个单例工具类,优先读取本地存储的资源,没有的话调用系统getString():

public class DynamicStringManager {
    private static DynamicStringManager instance;
    private Context context;
    private Map<String, String> dynamicStrings = new HashMap<>();
    private String currentLang;

    private DynamicStringManager(Context context) {
        this.context = context.getApplicationContext();
        loadCurrentLangStrings();
    }

    public static synchronized DynamicStringManager getInstance(Context context) {
        if (instance == null) {
            instance = new DynamicStringManager(context);
        }
        return instance;
    }

    // 加载当前语言的动态字符串
    private void loadCurrentLangStrings() {
        currentLang = Locale.getDefault().getLanguage() + "-" + Locale.getDefault().getCountry();
        File file = new File(context.getFilesDir(), "strings_" + currentLang + ".json");
        if (file.exists()) {
            try {
                String jsonContent = new String(Files.readAllBytes(file.toPath()));
                JSONObject jsonObject = new JSONObject(jsonContent);
                Iterator<String> keys = jsonObject.keys();
                while (keys.hasNext()) {
                    String key = keys.next();
                    dynamicStrings.put(key, jsonObject.getString(key));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    // 获取字符串:优先动态资源,否则用系统默认
    public String getString(String key) {
        if (dynamicStrings.containsKey(key)) {
            return dynamicStrings.get(key);
        }
        int resId = context.getResources().getIdentifier(key, "string", context.getPackageName());
        return resId != 0 ? context.getString(resId) : key;
    }

    // 资源更新后重新加载
    public void reloadStrings() {
        dynamicStrings.clear();
        loadCurrentLangStrings();
    }
}

四、替换应用中的字符串调用

把所有getString(R.string.xxx)替换成DynamicStringManager.getInstance(this).getString("xxx"),比如:

// 原来的写法
textView.setText(getString(R.string.welcome_msg));
// 替换后的写法
textView.setText(DynamicStringManager.getInstance(this).getString("welcome_msg"));

五、更新后的界面刷新

当资源下载完成后,通过广播或者ViewModel通知所有界面重新加载字符串,比如在Activity中注册广播:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    LocalBroadcastManager.getInstance(this).registerReceiver(refreshReceiver, new IntentFilter("REFRESH_STRINGS"));
}

private BroadcastReceiver refreshReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        DynamicStringManager.getInstance(context).reloadStrings();
        // 刷新当前界面的所有文本
        refreshUI();
    }
};

private void refreshUI() {
    TextView welcomeTv = findViewById(R.id.welcome_tv);
    welcomeTv.setText(DynamicStringManager.getInstance(this).getString("welcome_msg"));
    // 其他控件同理
}

@Override
protected void onDestroy() {
    super.onDestroy();
    LocalBroadcastManager.getInstance(this).unregisterReceiver(refreshReceiver);
}

注意事项

  • 要处理语言切换的情况:当用户切换系统语言时,需要重新加载对应语言的动态资源
  • 加入版本校验:给每个语言包加版本号,下载前先比对服务器版本和本地版本,避免重复下载
  • 异常处理:解析资源文件失败时,确保能 fallback到系统默认字符串,避免崩溃

内容的提问来源于stack exchange,提问作者Ayush Sharma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 21:38:35