Nice programing

Android-WebView 언어가 Android 7.0 이상에서 갑자기 변경됨

nicepro 2020. 12. 30. 20:25
반응형

Android-WebView 언어가 Android 7.0 이상에서 갑자기 변경됨


기본 언어 영어와 보조 언어 아랍어를 사용하는 다국어 앱이 있습니다.

에서 설명한 것처럼 문서 ,

  • android:supportsRtl="true"매니페스트에 추가 했습니다.
  • leftright속성을 사용 하여 모든 xml 속성을 startend각각 변경했습니다.
  • 에서 아랍어 문자열을 추가했습니다 strings-ar(다른 리소스에서도 유사하게).

위의 설정이 제대로 작동합니다. 을 변경 한 후 Localear-AE아랍어 텍스트 및 자원을 제대로 내 활동에 표시됩니다.

그러나 Activitya WebView및 / 또는 a로 이동할 때마다 WebViewClient로캘, 텍스트 및 레이아웃 방향이 갑자기 장치 기본값으로 되돌아갑니다.

추가 힌트 :

  • 이는 Android 7.0이 설치된 Nexus 6P 에서만 발생 합니다 . Android 6.0.1 이하에서는 모든 것이 제대로 작동합니다.
  • 로케일의 갑작스러운 변화 는 a 및 / 또는 a 가있는로 이동할 때만 발생 합니다 (그리고 여러 개가 있습니다). 다른 활동에서는 발생하지 않습니다.ActivityWebViewWebViewClient

Android 7.0은 다중 로케일을 지원하므로 사용자가 둘 이상의 기본 로케일을 설정할 수 있습니다. 따라서 기본 로케일을 Locale.UK다음과 같이 설정하면

여기에 이미지 설명 입력

그런 다음로 이동 WebView하면 로케일이에서 ar-AE변경 됩니다 en-GB.

Android 7.0 API 변경 :

API 변경 사항 목록에 표시된대로 로케일과 관련된 새 메소드가 API 24의 다음 클래스에 추가되었습니다.

Locale:

Configuration:

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

전에이 문제가 발생한 적이 있습니까? 그 이유는 무엇이며 어떻게 해결합니까?

참조 :

1. Android 4.2에서 기본 RTL 지원 .

2. 다국어 지원-언어 및 로케일 .

3. 기본 로케일에주의하십시오 .


Ted Hopp의 대답 은 문제를 해결하는 데 성공했지만 이런 일이 발생 하는지에 대한 질문은 다루지 않았습니다 .

그 이유는 WebViewAndroid 7.0에서 클래스와 지원 패키지가 변경 되었기 때문입니다 .

배경:

Android WebViewWebKit을 사용하여 구축되었습니다 . 원래 AOSP의 일부 였지만 KitKat부터 Android System WebViewWebView 라는 별도의 구성 요소로 분리 하기로 결정했습니다 . 기본적으로 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 비활성화

또한 장치에 둘 이상의 기본 언어가있는 다중 로케일 지원이 도입되었습니다.

여기에 이미지 설명 입력

이는 여러 언어를 사용하는 앱에 중요한 결과를 가져옵니다. 앱에 WebViews 가 있으면 Chrome 앱을 사용하여 렌더링됩니다. Chrome은 자체적으로 샌드 박스 처리 된 프로세스에서 실행 되는 Android 앱이므로 앱 에서 설정 한 로케일에 바인딩되지 않습니다. 대신 Chrome이 기본 기기 로케일로 되돌아갑니다. 예를 들어 앱 언어는로 설정되어 ar-AE있고 기기의 기본 언어 는로 설정되어 있다고 가정 해 보겠습니다 en-US. 이 경우 Activity포함 된 의 로캘이 WebView에서 ar-AE변경되고 en-US해당 로캘 폴더의 문자열 및 리소스가 표시됩니다. Activitys가있는 WebViews 에서 LTR 및 RTL 문자열 / 리소스가 섞여있는 것을 볼 수 있습니다 .

해결책:

이 문제에 대한 완전한 솔루션은 다음 두 단계로 구성됩니다.

1 단계:

첫째, 모든 수동으로 기본 로케일을 재설정 Activity하거나 적어도 모든 ActivityA가 들어 그 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설정하려는 것이다. 예를 들어 아랍어 / UAE를 기본 로케일로 설정하려면을 전달해야합니다 new Locale("ar", "AE"). 또는 기본 로케일 (예 : Locale운영 체제에서 자동으로 설정하는 로케일)을 설정 하려면을 전달해야합니다 Locale.US.

2 단계:

또한 다음 코드 줄을 추가해야합니다.

new WebView(this).destroy();

에서 onCreate()당신의 Application클래스 (있는 경우), 사용자는 언어를 변경 할 수있다 어디든지 다른. 이렇게하면 언어를 변경 한 후 앱을 다시 시작할 때 발생할 수있는 모든 종류의 엣지 케이스를 처리합니다 (다른 언어로 된 문자열 또는 Android 7.0 ++에서 s Activities있는 언어를 변경 한 후 반대 정렬로 표시 될 수 있음 WebView).

부록으로 Chrome 맞춤 탭 은 이제 인앱 웹 페이지를 렌더링하는 데 선호되는 방법입니다.

참조 :

1. Android 7.0-WebView .

2. WebView 및 Android 보안 패치 이해 .

3. Android 용 WebView .

4. WebView : "Powered by Chrome"에서 곧바로 Chrome까지 .

5. 누가 WebView .

6. Android 7.0 Nougat .

7. Android N 미스터리, Part 1 : Android 시스템 WebView는 이제 "Chrome"일 뿐입니 까? .


코드가 앱 자체의 구성에서 로케일을 설정하는 것 같습니다 ( 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().


모든 답변을 읽은 후 각 답변에 빠진 것이 있음을 알았으므로 지금까지 나를 위해 일한 솔루션이 있습니다. WebView는 활동 컨텍스트 및 애플리케이션 컨텍스트의 언어 구성을 재정의하므로 이러한 상황이 발생할 때마다 해당 변경 사항을 다시 재설정하는 메서드를 호출해야합니다. 내 경우에는이 문제를 나타내는 내 활동이 확장되는 다음 클래스를 작성했습니다 (WebView를 보여주는 것).

public class WebViewFixAppCompatActivity extends AppCompatActivity {

private Locale mBackedUpLocale = null;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        mBackedUpLocale = getApplicationContext().getResources().getConfiguration().getLocales().get(0);
    }
}

@Override
protected void onStop() {
    super.onStop();
    fixLocale();
}

@Override
public void onBackPressed() {
    fixLocale();
    super.onBackPressed();
}

/**
 * The locale configuration of the activity context and the global application context gets overridden with the first language the app supports.
 */
public void fixLocale() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        Resources resources = getResources();
        final Configuration config = resources.getConfiguration();

        if (null != mBackedUpLocale && !config.getLocales().get(0).equals(mBackedUpLocale)) {
            Locale.setDefault(mBackedUpLocale);
            final Configuration newConfig = new Configuration(config);
            newConfig.setLocale(new Locale(mBackedUpLocale.getLanguage(), mBackedUpLocale.getCountry()));
            resources.updateConfiguration(newConfig, null);
        }

        // Also this must be overridden, otherwise for example when opening a dialog the title could have one language and the content other, because
        // different contexts are used to get the resources.
        Resources appResources = getApplicationContext().getResources();
        final Configuration appConfig = appResources.getConfiguration();
        if (null != mBackedUpLocale && !appConfig.getLocales().get(0).equals(mBackedUpLocale)) {
            Locale.setDefault(mBackedUpLocale);
            final Configuration newConfig = new Configuration(appConfig);
            newConfig.setLocale(new Locale(mBackedUpLocale.getLanguage(), mBackedUpLocale.getCountry()));
            appResources.updateConfiguration(newConfig, null);
        }

    }
}
}

The idea posted by @Tobliug to save the initial configuration before the WebView overrides it worked for me, in my particular case I found this to be more easy to implement than other solutions posted. Important is that the fix method gets called after exiting the WebView, e.g. when pressing back and in onStop. If the webView is shown in a dialog you must take care the fix method is called after dismissing the dialog, mostly in onResume and/or onCreate. And if the webView is directly loaded in onCreate of the Activity and not afterwards in a new fragment the fix must also be called directly after setContentView before the activity's title is set, etc. If the WebView is loaded inside a fragment in the activity, call the activity in onViewCreated of the fragment and the activity should call the fix method. Not all activities need to extend the class above as noted in an aswer, that's an overkill and not necessary. This issue also does not get solved replacing the WebView by Google Chrome Tabs or opening an external browser.

If you really need your ressources configuratoin to have the whole list of languages set and not only one, then you would need to merge this solution with the one at https://gist.github.com/amake/0ac7724681ac1c178c6f95a5b09f03ce In my case it was not necessary.

I also did not find necessary to call new WebView(this).destroy(); as noted in an answer here.


Same issue here. I have a dirty, but simple, solution.

Because I observe that the locale is still good in the Activity.onCreate(...) function and no more valid in the Activity.onPostCreate(...) function, I just save the Locale and force it at the end of the onPostCreate(...) function.

Here we go :

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

Bonus - the change locale 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);
    }
}

Hopes it will help.


None of the answers above helped me, I managed to reset app locale again inside onStop() method of the activity containing the Webview


If you are using the WebView only to display rich text (Text with some paragraphs or bold and italic text in different font sizes), then you can use TextView and Html.fromHtml() instead. TextViews have no issue with locale settings ;-)


I want to add one more use-case here:

When pressing back from webview activity(i.e. Showing payment screen and user press back button), onCreate() of previous activity does not execute, So that language got reset again. To keep it bug free, We must reset app locale in onResume() of base Activity.

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

Call above method in onResume() of base activity or atleast in webview activity.

편집 : 프래그먼트를 다루는 경우 사용자가 웹보기를 종료 할 때이 메서드가 호출되는지 확인하십시오.


BaseContext를 "this"로 전달하는 SEt 로컬 메소드의 매개 변수를 변경하거나 특히 android 7.0 및 이전 버전에서 정확한 활동


Android N에서는을 수행 하면 리소스 경로에 new WebView()추가 /system/app/WebViewGoogle/WebViewGoogle.apk되고 경로에 추가되지 않은 경우 리소스가 다시 생성됩니다.

따라서 문제를 해결 new WebView(application)하려면 로컬을 변경하기 전에 응용 프로그램에서 수행 하십시오.

중국어를 아는 분 은이 블로그를 읽을 수 있습니다 .

참조 URL : https://stackoverflow.com/questions/40398528/android-webview-language-changes-abruptly-on-android-7-0-and-above

반응형