Форсировать локаль для Android-вкуса с помощью resConfig

Я пытаюсь использовать resConfig и resConfigs из системы Android Build.

  • Android Studio версии 1.2.2
  • Gradle версия для сборки 1.2.3
  • OSX 10.10.3

У меня возникла проблема с этими двумя вариантами с моим проектом, поэтому я начал новый пустой проект с помощью студии Android. Я прикрепил свой 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(по умолчанию)
/src/main/res/values-en/strings.xml
/src/main/res/values-fr/strings.xml

С этим я бы ожидал увидеть только 3 папки значений в MyApplication/app/builds/intermediates/res/en/debug, так как я определил в resConfigs только для использования "en" и "fr" и фильтрации чего-либо еще

/values ​​/
/values-en/
/Значения-пт/

Хотя все папки значений языков все еще находятся там, поэтому resConfigs ничего не фильтрует.

Я также ожидал увидеть ярлык hello_world от значений-en при запуске варианта вкуса enDebug, так как я указал, что аромат en будет использовать resConfig "en" , хотя, когда я запускаю тестовое приложение, я вижу метку от /values -fr/strings.xml вместо/values-en/strings.xml, так как язык на планшете настроен как французский Канада

Неужели я неправильно понимаю цель resConfig? Если да, то как я могу заставить аромат работать только на языке и не зависит от настройки локали ОС? Это решение должно быть совместимо с flavorDimensions, так как я использую их в реальном приложении, которое я пытаюсь настроить.

ПРИМЕЧАНИЕ. Я также зарегистрировал ошибку, так как я думаю, что действительно существует проблема с этим поведением resConfig https://code.google.com/p/android/issues/detail?id=180694

Спасибо

Ответ 1

Ну, через много часов, вот решение моей проблемы для тех, кто заканчивается той же проблемой.

Оказывается, что resConfig не для чего я. Правильный и единственный способ, которым я нашел, чтобы заставить локаль для конкретного аромата, выглядит следующим образом:

Во-первых, убедитесь, что все ваши действия расширяют общую деятельность, которая будет нести ответственность за создание локали. (Мне пришлось создать 2, так как у меня есть некоторые действия, расширяющие FragmentActivity и некоторые расширяющие Activity. Мне также не нравится делать это в конструкторе Activities, но поскольку мне нужно вызвать applyOverrideConfiguration, прежде чем любой вызов будет выполнен на getResources, мне нужно позвонить это перед активностью в начале).

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 + см. отчет об ошибке в Android) Это решение широко распространяется на stackOverflow, но я столкнулся с стеной, реализуя это на Android M, поэтому имейте это в виду.

В onCreate() вашего AndroidApplication вы можете вызвать updateConfiguration с набором локалей.

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

Вам также понадобится reset его, если вы определили 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, похоже, не работает с Android applyOverrideConfiguration, Команда Chromium в настоящее время работает над этим!

Спасибо.

Ответ 2

resConfig не переопределяет указанный resConfigs defaultConfig, а просто объединяет их. Таким образом, вы получите все вкусы, содержащие ресурсы en и fr.

Итак, чтобы этого избежать, вы не должны указывать в defaultConfig resConfigs и просто устанавливать его в определенном вкусе.

Кроме того, приложение всегда будет включать в себя значение по умолчанию values, что означает, что если у вас есть английские строки, аромат fr все равно будет отображаться с английским контентом на устройстве, установленном для любого не французского языка.