为了账号安全,请及时绑定邮箱和手机立即绑定

Android-WebView语言在Android 7.0及更高版本上突然改变

Android-WebView语言在Android 7.0及更高版本上突然改变

呼唤远方 2019-12-27 11:02:31
我有使用主要语言英语和次要语言阿拉伯语的多语言应用程序。如文档中所述,我已经添加android:supportsRtl="true"了清单。我已将所有xml属性分别与left和right属性分别更改为start和end。我在中添加了阿拉伯语言字符串strings-ar(其他资源也是如此)。上面的设置可以正常工作。将更Locale改为后ar-AE,阿拉伯文和资源会正确显示在我的活动中。但是,每次我Activity使用WebView 和和/或导航到时WebViewClient,语言环境,文本和布局方向都会突然恢复为设备默认值。更多提示:这仅在具有Android 7.0的Nexus 6P上发生。一切在Android 6.0.1及更低版本上均可正常运行。仅当我导航到Activity具有WebView和(或)WebViewClient(并且我有多个)的时,才会发生语言环境的突然变化。在任何其他活动上都不会发生。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构建我的应用程序,并且没有使用任何这些新方法。此外...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());}有人遇到过这个问题吗?原因是什么,我该如何解决?
查看完整描述

3 回答

?
慕慕森

TA贡献1856条经验 获得超17个赞

背景:


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


Android系统WebView


Android 7.0的变化:


从Android N开始,Chrome应用将用于渲染WebView第三方Android应用中的任何/全部。在开箱即用的Android N手机中,根本没有Android WebView System应用程序。在已收到Android N的OTA更新的设备中,Android系统WebView被禁用:


WebView已禁用



WebView已禁用


此外,已引入多语言环境支持,并且设备具有多种默认语言:


在此处输入图片说明


对于具有多种语言的应用程序,这具有重要的意义。如果您的应用包含WebView,则这些内容将使用Chrome应用呈现。由于Chrome 本身就是一个Android应用,因此以其自己的沙盒流程运行,因此不会绑定到您的应用设置的语言环境。取而代之的是,Chrome将还原为主要设备的语言环境。例如,假设您的应用语言环境设置为ar-AE,而设备的主要语言环境设置为en-US。在这种情况下,Activity包含的语言环境WebView将从ar-AE变为en-US,并且将显示来自相应语言环境文件夹的字符串和资源。您可能会在Activity具有WebViews的那些s 上看到大量的LTR和RTL字符串/资源。


解决方案:


完整的解决方案包括两个步骤:


步骤1:


首先,在每个Activity(或至少每个Activity具有的)中手动重置默认语言环境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());

}

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


第2步:


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


new WebView(this).destroy();

在onCreate()您的Application类(如果有的话),和任何其他地方的用户可以更改语言。这将处理在更改语言后重新启动应用程序时可能发生的各种极端情况(您可能已经注意到其他语言的字符串,或者在更改语言后在Android 7.0 ++ 上Activities具有相反的对齐方式WebView)。


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


查看完整回答
反对 回复 2019-12-27
?
炎炎设计

TA贡献1808条经验 获得超4个赞

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


我采用的方法是子类化AppCompatActivity(或者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;

        }

    }

}

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


查看完整回答
反对 回复 2019-12-27
  • 3 回答
  • 0 关注
  • 1209 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信