Ted Hopp's answer managed to solve the problem, but he didn't address the question of why this occurs.
The reason is the changes made to the WebView
class and its support package in Android 7.0.
Background:
Android's WebView
is built using WebKit. While it was originally a part of AOSP, from KitKat onwards a decision was made to spin off WebView
into a separate component called Android System WebView. It is essentially an Android system app that comes pre-installed with Android devices. It is periodically updated, just like other system apps such as Google Play Services and the Play Store app. You can see it in your list of installed system apps:
Android 7.0 changes:
Starting with Android N, the Chrome app will be used to render any/all WebView
s in third-party Android apps. In phones that have Android N out-of-the-box, the Android WebView System app is not present at all. In devices that have received an OTA update to Android N, the Android System WebView is disabled:
and
Moreover, multi-locale support has been introduced, with devices having more than one default language:
This has an important consequence for apps that have multiple languages. If your app has WebView
s, then those are rendered using the Chrome app. Because Chrome is an Android app in itself, running in its own sandboxed process, it will not be bound to the locale set by your app. Instead, Chrome will revert to the primary device locale. For example, say your app locale is set to ar-AE
, while the primary locale of the device is en-US
. In this case, the locale of the Activity
containing a WebView
will change from ar-AE
to en-US
, and strings and resources from the corresponding locale folders will be displayed. You may see a mish-mash of LTR and RTL strings/resources on those Activity
s that have WebView
s.
The Solution:
The complete solution to this problem consists of two steps:
STEP 1:
First, reset the default locale manually in every Activity
, or at least every Activity
that has a WebView
.
public static void setLocale(Locale locale){
Context context = MyApplication.getInstance();
Resources resources = context.getResources();
Configuration configuration = resources.getConfiguration();
Locale.setDefault(locale);
configuration.setLocale(locale);
if (Build.VERSION.SDK_INT >= 25) {
context = context.getApplicationContext().createConfigurationContext(configuration);
context = context.createConfigurationContext(configuration);
}
context.getResources().updateConfiguration(configuration,
resources.getDisplayMetrics());
}
Call the above method before calling setContentView(...)
in the onCreate()
method of all your Activities. The locale
parameter should be the default Locale
that you wish to set. For example, if you wish to set Arabic/UAE as the default locale, you should pass new Locale("ar", "AE")
. Or if you wish to set the default locale (i.e. the Locale
that is automatically set by the operating system), you should pass Locale.US
.
STEP 2:
Additionally, you need to add the following line of code:
new WebView(this).destroy();
in the onCreate()
of your Application
class (if you have one), and wherever else the user may be changing the language. This will take care of all kinds of edge cases that may occur on app restart after changing the language (you may have noticed strings in other languages or with the opposite alignment after changing the language on Activities
that have WebView
s on Android 7.0++).
As an addendum, Chrome custom tabs are now the preferred way of rendering in-app web pages.
References:
1. Android 7.0 - changes for WebView
.
2. Understanding WebView and Android security patches.
3. WebView for Android.
4. WebView: From "Powered by Chrome" to straight up Chrome.
5. Nougat WebView.
6. Android 7.0 Nougat.
7. Android N Mysteries, Part 1: Android System WebView is just "Chrome" Now?.