使用 resConfig 为 Android 风味强制区域设置

Force locale for Android flavor with resConfig

我正在尝试使用 Android 构建系统中的 resConfig 和 resConfigs。

我在我的项目中遇到了这两个选项的问题,所以我用 android studio 开始了一个新的空白项目。我附上了 build.gradle,我只在

下添加了 resConfigs "en"、"fr"
android { 
   defaultConfig {
        ...
        resConfigs "en", "fr" 
        ...
   }
}

并定义了 2 种基本口味

productFlavors {
        fr {
            resConfig "fr"
        }

        en {
            resConfig "en"
        }
}

然后我创建了 2 个 strings.xml 文件并翻译了 hello_world 默认标签

/src/main/res/values/strings.xml (default)
/src/main/res/values-en/strings.xml
/src/main/res/values-fr/strings.xml

有了这个,我希望在 MyApplication/app/builds/intermediates/res/en/debug 中只看到 3 个值文件夹,因为我在 resConfigs 中定义为仅使用 "en" 和 "fr" 并过滤任何其他内容

/values/
/values-en/
/values-fr/

尽管如此,所有语言值文件夹仍在那里,因此 resConfigs 显然没有过滤任何内容。

我还希望在 运行ning enDebug flavor 变体时看到来自 values-en 的标签 hello_world 因为我指定 flavor en 将使用 resConfig "en" 尽管当我运行 测试应用我看到的标签来自 /values-fr/strings.xml 而不是 /values-en/strings.xml 因为平板电脑上的语言配置为加拿大法语

我是不是误解了 resConfig 背后的目的?如果是这样,我应该如何强制仅使用 运行 语言而不依赖于 OS 语言环境设置?此解决方案也必须与 flavorDimensions 兼容,因为我在我尝试配置的真实应用程序中使用它们。

注意:我还提交了一个错误,因为我认为这个 resConfig 行为确实存在问题 https://code.google.com/p/android/issues/detail?id=180694

谢谢

好吧,几个小时后,对于那些最终遇到同样问题的人,这里是我的问题的解决方案。

原来 resConfig 不是我想的那样。我发现为特定风格强制语言环境的正确且唯一的方法是这样的:

首先,确保您所有的活动都扩展了一个共同的 activity,它将负责强制使用语言环境。 (我必须创建 2,因为我有一些扩展 FragmentActivity 的活动和一些扩展 Activity 的活动。我也不太喜欢在 Activities 构造函数中这样做,但因为我必须在对 getResources 进行任何调用之前调用 applyOverrideConfiguration,我需要在 activity 的 onStart).

之前调用它
public class LocaleMainActivity extends Activity {

    public LocaleMainActivity() {
        ActivityUtils.forceLocale(this);
    }
}

public class LocaleMainFragmentActivity extends FragmentActivity {

    public LocaleMainFragmentActivity() {
        ActivityUtils.forceLocale(this);
    }
}

//Method from ActivityUtils
public static void forceLocale(ContextThemeWrapper contextThemeWrapper) {
    Configuration configuration = new Configuration();
    Locale defaultLocale = new Locale(BuildConfig.LOCALE);
    configuration.locale = defaultLocale;
    contextThemeWrapper.applyOverrideConfiguration(configuration);      
}

接下来,您需要在 build.gradle 风格中定义语言环境

productFlavors {

    myFrenchFlavor {
     buildConfigField "String", "LOCALE", "\"fr\""
    }
    myEnglishFlavor {
      buildConfigField "String", "LOCALE", "\"en\""
    }
}

我在 API 19+ 上测试了解决方案。当您在应用程序中更改语言时也适用。



替代解决方案不适用于Android M+ see android bug report) 这个解决方案在 Whosebug 上广泛传播,但我在 Android M 上实现它时遇到了困难,所以请记住这一点。

在您的 Android应用程序的 onCreate() 中,您可以使用区域设置调用 updateConfiguration。

Locale myLocale = new Locale(BuildConfig.LOCALE);
Resources res = getResources();
Configuration conf = res.getConfiguration();
conf.locale = myLocale;
res.updateConfiguration(conf, res.getDisplayMetrics());

如果您定义了 onConfigurationChanged()

,您还需要重置它
@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);            
        Configuration config = new Configuration(newConfig);
        config.locale = new Locale(BuildConfig.LOCALE);
        getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
    }

编辑: 请注意,此 applyOverrideConfiguration 目前有一个副作用,在此处 Chromium webview does not seems to work with Android applyOverrideConfiguration 进行了解释。 Chromium 团队目前正在努力解决这个问题!

谢谢。

resConfig 不会覆盖 defaultConfig 的指定 resConfigs,而只是组合它们。因此,您最终会得到包含 en fr 资源的所有口味。

因此,为避免这种情况,您不应在 defaultConfig 中指定任何 resConfigs,只需将其设置为特定风格即可。

此外,该应用程序将始终包含默认 values,这意味着如果您那里有英文字符串,fr 风格仍会在设置为任何非英语内容的设备上显示英文内容-法语语言环境。