【问题标题】:Android Nougat 7.1 resets Locale after launching WebViewAndroid Nougat 7.1 在启动 WebView 后重置区域设置
【发布时间】:2017-03-22 01:56:01
【问题描述】:

我们在 Android N 7.1 (API-25) 中遇到了一个奇怪的行为,即在启动 WebView 后,系统强制将区域设置重置为设备区域设置。这会覆盖应用程序上使用的语言环境(用于本地化)。重现这一点的简单方法是在应用程序上进行本地化。并启动一个 WebView。然后,在您再次重新启动应用程序之前,您将不会再看到本地化内容。这只发生在 Android-7.1 (API-25) 上

以下是我如何切换适用于所有 API 的语言环境:

 public void switchToCzLocale() {
        Locale mLocale = new Locale("cs","CZ");// it can be any other Locale
        Configuration config = getBaseContext().getResources()
                .getConfiguration();
        Locale.setDefault(mLocale);
        config.setLocale(mLocale);
        getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
    }

我已经上传了一个示例来重现该问题,并提供了更多详细信息:

https://github.com/mabuthraa/WebView-android7-issue

请知道这种行为是否是错误或可能是更改语言环境的错误植入。

Android群开票链接:Issue 218310: [developer preview] Creating a WebView resets Locale to user defaults

【问题讨论】:

    标签: android webview android-7.1-nougat


    【解决方案1】:

    这是我的解决方法。

    我们通过在初始化 webView 和加载内容之前再次强制设置区域设置解决了这个问题:

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
      MyApp.getApplication().switchToCzLocale();
    }
    

    例如在WebActivity中:

     @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_web);
            mWebView = (WebView) findViewById(R.id.webview);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
              MyApp.getApplication().switchToCzLocale();
            }
            mWebView.loadData(getString(R.string.web_content), "text/html", "charset=UTF-8");
        }
    

    我的应用程序:

    import android.app.Application;
    import android.content.res.Configuration;
    
    import java.util.Locale;
    
    
    public class MyApp extends Application {
        private static MyApp sApplication;
    
        @Override
        public void onCreate() {
            super.onCreate();
            switchToCzLocale();
            sApplication = this;
        }
    
        public static MyApp getApplication() {
            return sApplication;
        }
    
        public void switchToCzLocale() {
            Locale mLocale = new Locale("cs","CZ");
            Configuration config = getBaseContext().getResources()
                    .getConfiguration();
            Locale.setDefault(mLocale);
            config.setLocale(mLocale);
            getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
        }
    }
    

    我希望这可能会有所帮助,'。

    我仍在寻找更好的解决方案。

    【讨论】:

    • 目前这是唯一的解决方案:|
    • @Maher 你有没有找到更好的解决方案?几个月以来,我一直在使用您上面提到的解决方法,但最近我又收到了关于同样问题的投诉。这个问题在谷歌跟踪器中也没有解决,我真的找不到更好的解决方案。
    【解决方案2】:

    这个问题也让我有些头疼,尤其是因为 Google 认为这不是他们这边的错误。但是,这绝对不是应用程序中所期望的行为,即仅在打开 WebView 时语言就会改变。

    我们的解决方案不依赖硬编码语言,适用于 Android 7+。首先,将此代码添加到您的应用 build.gradle 文件中:

    android {
        defaultConfig {
            ...
            resConfigs rootProject.ext.available_languages
            buildConfigField "String[]", "AVAILABLE_LANGUAGES", "{\"${rootProject.ext.available_languages.join("\",\"")}\"}"
        }
    }
    

    并将以下代码添加到您的根 build.gradle:

    ext {
        available_languages = ["en", "de"]
    }
    

    这两个代码块定义了可用的strings.xml 文件列表并将该列表放在BuildConfig.AVAILABLE_LANGUAGES 字段中。

    现在,我们可以定义一个BaseActivity,所有活动都应从该BaseActivity扩展,使用以下代码:

    abstract class BaseActivity : AppCompatActivity() {
    
        override fun attachBaseContext(newBase: Context) {
            val locale = getFirstAvailableLocale(newBase)
            val context = createContextWithLocale(locale, newBase)
            super.attachBaseContext(context)
        }
    
        private fun getFirstAvailableLocale(context: Context): Locale {
            val availableLanguages = BuildConfig.AVAILABLE_LANGUAGES // Gets list of available languages defined in the build.gradle file
            val locales = context.resources.configuration.locales
            for (i in 0..locales.size()) {
                if (locales[i].language in availableLanguages) {
                    return locales[i]
                }
            }
            return locales[0]
        }
    
        @Suppress("DEPRECATION")
        private fun createContextWithLocale(locale: Locale, baseContext: Context): Context {
            val resources = baseContext.resources
            val configuration = resources.configuration
            val localeList = LocaleList(locale)
            LocaleList.setDefault(localeList)
            configuration.setLocales(localeList)
            return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
                baseContext.createConfigurationContext(configuration)
            } else {
                resources.updateConfiguration(configuration, resources.displayMetrics)
                baseContext
            }
        }
    }
    

    您甚至可以扩展此解决方案以支持不同的区域,但是您必须将字符串从 resConfigs 拆分为语言和区域,因为 Locale 类无法正确识别语言标签(例如 de-rDE 需要在 resConfigs 中定义,但 Locale 将是 de_DE)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-03
      • 2016-03-19
      • 1970-01-01
      • 2021-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多