使用resConfig强制Android风格的区域设置

Eri*_*lle 10 android locale localization gradle android-productflavors

我正在尝试使用Android Build系统中的resConfig和resConfigs.

  • Android Studio版本1.2.2
  • Gradle构建版本1.2.3
  • OSX 10.10.3

我的项目有这两个选项的问题,所以我用android studio开始了一个新的空白项目.我附上了我的build.gradle,我只在其中添加了resConfigs"en","fr"

android { 
   defaultConfig {
        ...
        resConfigs "en", "fr" 
        ...
   }
}
Run Code Online (Sandbox Code Playgroud)

并定义了2种基本口味

productFlavors {
        fr {
            resConfig "fr"
        }

        en {
            resConfig "en"
        }
}
Run Code Online (Sandbox Code Playgroud)

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

/src/main/res/values/strings.xml(默认)
/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没有明显过滤任何东西.

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

我是否误解了resConfig背后的目的?如果是这样,我应该如何强制只使用语言运行并且不依赖于操作系统区域设置?此解决方案必须与flavorDimensions兼容,因为我在我正在尝试配置的真实应用程序中使用它们.

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

谢谢

Eri*_*lle 9

好吧,经过几个小时,这里是解决我遇到同样问题的问题的解决方案.

事实证明resConfig并不适合我.我发现强制特定风格的语言环境的正确和唯一方法是这样的:

首先,确保您的所有活动都扩展了一个共同的活动,该活动将负责强制使用区域设置.(我必须创建2,因为我有一些活动扩展FragmentActivity和一些扩展Activity.我也不喜欢在Activities构造函数中这样做但是因为我必须在getResources上完成任何调用之前调用applyOverrideConfiguration,我需要调用它在活动的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);      
}
Run Code Online (Sandbox Code Playgroud)

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

productFlavors {

    myFrenchFlavor {
     buildConfigField "String", "LOCALE", "\"fr\""
    }
    myEnglishFlavor {
      buildConfigField "String", "LOCALE", "\"en\""
    }
}
Run Code Online (Sandbox Code Playgroud)

我在API 19+上测试了该解决方案.在应用程序中更改语言时也可以使用.



替代解决方案(不适用于Android M + 请参阅android错误报告)此解决方案在stackOverflow上广泛传播,但我在Android M上实现此问题时遇到了问题,请记住这一点.

在AndroidApplication的onCreate()中,您可以使用区域设置调用updateConfiguration.

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

如果你定义了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());
    }
Run Code Online (Sandbox Code Playgroud)

编辑:请注意,此applyOverrideConfiguration目前有副作用,此处解释Chromium webview似乎不适用于Android applyOverrideConfiguration.Chromium团队目前正致力于此!

谢谢.

  • 作为一个旁边(因为我是提交你上面链接的bug报告的人),如果使用的`context`来自`Activity`而不是来自`Application`,上面提到的替代解决方案对M有效. (2认同)

Flo*_*ern 6

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

因此,为了避免这种情况,您不应该resConfigs在 中指定任何内容defaultConfig,而只需将其设置为特定的风格。

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