web-dev-qa-db-ja.com

AndroidフレーバーをresConfigで強制する

AndroidビルドシステムからresConfigとresConfigsを使用しようとしています。

  • AndroidStudioバージョン1.2.2
  • Gradleビルドバージョン1.2.3
  • OSX 10.10.3

プロジェクトでこれら2つのオプションに問題があったので、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(デフォルト)
/src/main/res/values-en/strings.xml
/src/main/res/values-fr/strings.xml

これにより、resConfigsで「en」と「fr」のみを使用して他のものをフィルタリングするように定義したため、MyApplication/app/builds/Intermediates/res/en/debugに3つの値フォルダーのみが表示されると予想されます。

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

ただし、すべての言語の値フォルダーはまだそこにあるため、resConfigsは明らかに何もフィルタリングしていません。

また、enDebugフレーバーバリアントを実行すると、values-enからラベルhello_worldが表示されると予想されます。これは、フレーバーenがresConfig "en"を使用するように指定したためですが、テストアプリを実行すると、/ values-fr/stringsからラベルが表示されます。タブレットの言語はFrenchCanadaとして構成されているため、/ values-en /strings.xmlではなくxml

ResConfigの背後にある目的を誤解していますか?もしそうなら、どうすればフレーバーを言語のみで実行し、OSロケール設定に依存しないように強制する必要がありますか?このソリューションは、構成しようとしている実際のアプリで使用するため、flavorDimensionsとも互換性がある必要があります。

[〜#〜] note [〜#〜]:このresConfigの動作に本当に問題があると思うので、バグも報告しました https://code.google.com/p/Android/issues/detail?id=180694

ありがとう

13
Eric Labelle

さて、何時間も経った後、同じ問題が発生した場合の私の問題の解決策は次のとおりです。

ResConfigは私が思っていたものには向いていないことがわかりました。特定のフレーバーのロケールを強制するために私が見つけた適切で唯一の方法は次のとおりです。

まず、すべてのアクティビティが、ロケールを強制する責任がある共通のアクティビティを拡張していることを確認します。 (FragmentActivityを拡張するアクティビティとActivityを拡張するアクティビティがあるため、2を作成する必要がありました。Activitiesコンストラクターでこれを行うのもあまり好きではありませんが、呼び出しを行う前にapplyOverrideConfigurationを呼び出す必要があるためです。 getResourcesでは、アクティビティの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\""
    }
}

API19以降でソリューションをテストしました。アプリ内で言語を変更した場合にも機能します。



代替ソリューションは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());

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());
    }

EDIT:このapplyOverrideConfigurationには現在、ここで説明されている副作用があることに注意してください ChromiumwebviewはAndroid applyOverrideConfiguration 。 Chromiumチームは現在それに取り組んでいます!

ありがとう。

10
Eric Labelle

resConfigは、resConfigsの指定されたdefaultConfigをオーバーライドしませんが、代わりにそれらを組み合わせるだけです。したがって、enおよびfrリソースを含むすべてのフレーバーになります。

したがって、これを回避するには、resConfigsdefaultConfigを指定せず、特定のフレーバーに設定するだけです。

さらに、アプリには常にデフォルトのvaluesが含まれます。つまり、英語の文字列がある場合でも、フランス語以外のロケールに設定されたデバイスでは、frフレーバーが英語のコンテンツとともに表示されます。 。

2
Floern