Android – WebView语言在Android N上突然更改

我有一个多语言的应用程序与主要语言英语和阿拉伯语中学语言。

如文件所述 ,

  • 我已经在清单中添加了android:supportsRtl="true"
  • 我已经改变了所有具有right属性的XML属性分别startend
  • 我在strings-ar添加了阿拉伯语语言string(对于其他资源也类似)。

上述设置正常工作。 将Locale更改为ar-AE ,阿拉伯文文本和资源正确显示在我的活动中。

但是,每次使用WebView和/或WebViewClient导航到Activity时,语言环境,文本和布局方向都会突然恢复为设备默认设置。

更多提示:

  • 在使用Android 7.0的Nexus 6P上发生。 一切正常在Android 6.0.1及以下。
  • 只有在导航到具有WebView和/或WebViewClientActivity (我有几个)时, 才会发生语言环境的突变。 它不会发生在其他任何活动上。

Android 7.0具有多语言环境支持,允许用户设置多个默认语言环境。 所以,如果我将主要语言环境设置为Locale.UK

在这里输入图像描述

然后在导航到WebView ,语言环境从ar-AE更改为en-GB

Android 7.0 API更改:

如API更改列表中所示,有关语言环境的新方法已添加到API 24中的以下类中:

Locale

  • Locale.getDefault(...)
  • Locale.setDefault(...)

Configuration

  • getLocales()
  • setLocales(...)

不过,我正在用API 23构build我的应用程序,并没有使用任何这些新的方法。

再说…

  • Nexus 6P仿真器上也会出现该问题。

  • 要获取默认语言环境,我使用了Locale.getDefault()

  • 要设置默认语言环境,我使用下面的代码:

     public static void setLocale(Locale locale){ Locale.setDefault(locale); Configuration config = new Configuration(); config.setLocale(locale); Context context = MyApplication.getInstance(); context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics()); } 

有没有人遇到过这个问题? 这是什么原因,我该如何解决呢?

参考文献:

1. Android 4.2中的原生RTL支持

2. 多语言支持 – 语言和地区

3. 谨慎默认的语言环境

泰德·霍普的答案设法解决了这个问题,但是他没有解决为什么会出现这个问题。

原因是在Android 7.0中对Webview类及其支持包所做的更改。

背景:

Android的WebView是使用webkit构build的。 虽然它最初是AOSP的一部分,但从KitKat开始,决定将WebView分解成一个名为Android System WebView的单独组件。 它基本上是一个Android系统应用程序,预装了Android设备。 它会像其他系统应用程序(如Google Play服务和Play商店应用程序)一样定期更新。 您可以在已安装的系统应用列表中看到它:

Android系统WebView

Android 7.0更改

从Android N开始,Chrome应用将用于在第三方Android应用中呈现任何/所有WebView 。 在具有Android N开箱即用的手机中,Android WebView系统应用根本不存在。 在已收到Android N的OTA更新的设备中,Android系统WebView被禁用:

禁用WebView

禁用WebView

此外,引入了多语言支持,设备具有多种默认语言:

在这里输入图像描述

这对于具有多种语言的应用程序具有重要的意义。 如果您的应用程序具有WebView ,那么使用Chrome应用程序呈现这些内容。 由于Chrome 本身就是一个Android应用程序,运行在自己的沙盒过程中,因此它不会被绑定到您的应用程序设置的区域设置。 相反,Chrome将恢复到主设备区域设置。 例如,假设您的应用程序语言环境设置为ar-AE ,而设备的主要语言环境为en-US 。 在这种情况下,包含WebViewActivity的语言环境将从ar-AE更改为en-US ,并显示相应语言环境文件夹中的string和资源。 您可能会在具有WebViewActivity上看到LTR和RTLstring/资源的混搭。

解决scheme:

这个问题的完整解决scheme由两个步骤组成:

步骤1:

首先,在每个Activity或至less每个具有WebView Activity中手动重置默认语言环境。

 public static void setLocale(Locale locale){ Locale.setDefault(locale); Context context = MusafirApplication.getInstance(); final Resources resources = context.getResources(); final Configuration config = resources.getConfiguration(); config.setLocale(locale); context.getResources().updateConfiguration(config, resources.getDisplayMetrics()); } 

在所有活动的onCreate()方法中调用setContentView(...)之前调用上述方法。 locale参数应该是您希望设置的默认Locale 。 例如,如果您希望将阿拉伯语/阿拉伯联合酋长国设置为默认语言环境,则应传递new Locale("ar", "AE") 。 或者,如果您希望设置默认语言环境(即由操作系统自动设置的Locale ),则应该通过Locale.US

第2步:

另外,您需要添加以下代码行:

 new WebView(this).destroy(); 

在你的Application类的onCreate() (如果有的话)以及用户可能正在改变语言的地方。 这将处理更改语言后应用程序重新启动时可能出现的各种边缘情况(您可能已经注意到其他语言中的string,或者在更改具有Android 7.0 ++上的WebViewActivities的语言之后,相反的alignment方式) 。

作为附录, Chrome自定义标签现在是呈现应用内网页的首选方式。

参考文献:

1. Android 7.0 – 更改WebView

2. 了解WebView和Android安全补丁

3. 用于Android的WebView

4. WebView:从“Powered by Chrome”直接浏览Chrome

5. 牛轧糖WebView

6. Android 7.0牛轧糖

7. Android N Mysteries,第1部分:Android系统WebView现在只是“Chrome”?

您的代码似乎是在应用程序本身( MyApplication.getInstance() )的configuration中设置语言环境。 但是,在扩充活动的内容视图之前,需要更新活动上下文的configuration。 我发现,修改应用程序的上下文是不够的(事实certificate,甚至没有必要)。 如果我不更新每个活动上下文,那么这个行为在各个活动之间是不一致的。

我采取的方法是inheritanceAppCompatActivity (或Activity ,如果不使用兼容性库),然后从该子类派生所有我的活动类。 这里是我的代码的简化版本:

 public class LocaleSensitiveActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { Locale locale = ... // the locale to use for this activity fixupLocale(this, locale); super.onCreate(savedInstanceState); ... } static void fixupLocale(Context ctx, Locale newLocale) { final Resources res = ctx.getResources(); final Configuration config = res.getConfiguration(); final Locale curLocale = getLocale(config); if (!curLocale.equals(newLocale)) { Locale.setDefault(newLocale); final Configuration conf = new Configuration(config); conf.setLocale(newLocale); res.updateConfiguration(conf, res.getDisplayMetrics()); } } private static Locale getLocale(Configuration config) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { return config.getLocales().get(0); } else { //noinspection deprecation return config.locale; } } } 

然后调用任何使用上下文的方法(比如setContentView()之前,确保在每个子类的onCreate()方法中调用super.onCreate(savedInstanceState)

上面的答案都没有帮助我,我设法重新设置在包含Webview的活动onStop()方法内的应用程序语言环境

我想在这里添加一个用例

当从webview活动中按下(即显示付款屏幕和用户按下后退button)时,先前活动的onCreate()不会执行,以便语言重新被复位。 为了保持它的bug,我们必须重置基本Activity的onResume() app locale

 private static void updateResources(Context context, String language) { Locale locale = new Locale(language); Locale.setDefault(locale); Configuration config = new Configuration(); config.setLocale(locale); config.setLayoutDirection(locale); context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics()); } 

在基本活动的onResume()或至less在webview活动中调用以上方法。

这里同样的问题。 我有一个肮脏的,但简单的解决scheme。

因为我注意到Activity.onCreate(…)函数中的语言环境仍然不错,在Activity.onPostCreate(…)函数中没有更多的有效内容,我只保存Locale并强制在onPostCreate (…)function。

开始了 :

 private Locale backedUpLocale = null; @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); backedUpLocale = getApplicationContext().getResources().getConfiguration().locale; } @Override protected void onPostCreate(@Nullable Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); changeLocale(backedUpLocale); } 

奖金 – 更改区域设置function:

 public void changeLocale(final Locale locale) { final Configuration config = res.getConfiguration(); if(null != locale && !config.locale.equals(locale)) { Locale.setDefault(locale); final Configuration newConfig = new Configuration(config); if(PlatformVersion.isAtLeastJellyBeanMR1()) { newConfig.setLocale(new Locale(locale.getLanguage())); } else { newConfig.locale = new Locale(locale.getLanguage()); } res.updateConfiguration(newConfig, null); } } 

希望它会有所帮助。

如果仅使用WebView来显示富文本(带有一些段落的文本或不同字体的粗体和斜体文本),则可以使用TextView和Html.fromHtml() 。 TextViews与语言环境设置没有任何问题;-)

在Android N中,当您new WebView() ,它会将/system/app/WebViewGoogle/WebViewGoogle.apk添加到资源path中,如果未添加到path中,则会导致Resource重新创build。

所以,如果你想解决这个问题,只需在应用程序中执行new WebView(application) ,然后再更改本地。

如果你懂中文, 你可以阅读这个博客 。