studio permisos nougat errores descargar android android-webview locale android-7.0-nougat nexus-6p

nougat - permisos android 7.0 android studio



Android: el idioma de WebView cambia abruptamente en Android N (8)

Tengo una aplicación multilingüe con el idioma principal inglés y el idioma secundario árabe.

Como se describe en la documentation ,

  • He agregado android:supportsRtl="true" en el manifiesto.
  • He cambiado todas las propiedades xml con atributos left y right para start y end respectivamente.
  • He agregado cadenas de idioma árabe en strings-ar (y de manera similar para otros recursos).

La configuración anterior funciona correctamente. Después de cambiar la Locale a ar-AE , el texto y los recursos en árabe se muestran correctamente en mis actividades.

Sin embargo, cada vez que navego a una Activity con un WebView y / o un WebViewClient , la configuración regional, el texto y la dirección del diseño vuelven abruptamente al valor predeterminado del dispositivo.

Consejos adicionales:

  • Esto ocurre solo en un Nexus 6P con Android 7.0 . Todo funciona correctamente en Android 6.0.1 y versiones posteriores.
  • El cambio abrupto en la configuración regional ocurre solo cuando navego a una Activity que tiene un WebView y / o un WebViewClient (y tengo varios). No ocurre en ninguna de las otras actividades.

Android 7.0 tiene soporte para múltiples configuraciones regionales, lo que permite al usuario establecer más de una configuración regional predeterminada. Entonces, si configuro la configuración regional primaria en Locale.UK :

Luego, al navegar a WebView , la configuración regional cambia de ar-AE a en-GB .

Cambios de la API de Android 7.0:

Como se indica en la lista de cambios de API , se han agregado nuevos métodos relacionados con la configuración regional a las siguientes clases en API 24:

Locale :

Configuration :

Sin embargo, estoy creando mi aplicación con API 23, y no estoy usando ninguno de estos nuevos métodos.

Además ...

  • El problema también ocurre en el emulador Nexus 6P.

  • Para obtener la configuración regional predeterminada, estoy usando Locale.getDefault() .

  • Para establecer la configuración regional predeterminada, estoy usando el siguiente código:

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

¿Alguien ha encontrado este problema antes? ¿Cuál es la razón y cómo resuelvo esto?

Referencias

1. Soporte RTL nativo en Android 4.2 .

2. Soporte multilingüe: idioma y configuración regional .

3. Tenga cuidado con la configuración regional predeterminada .


Después de leer todas las respuestas, descubrí que falta algo en cada una, así que aquí está la solución que me funcionó hasta ahora. Dado que WebView anula la configuración de idioma del contexto de la actividad y el contexto de la aplicación, debe asegurarse de que cada vez que esto suceda llame a un método que restablezca esos cambios. En mi caso, escribí en la siguiente clase que mis actividades que presentan este problema se extienden (aquellas que muestran un 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); } } } }

La idea publicada por @Tobliug para guardar la configuración inicial antes de que WebView anulara funcionó para mí, en mi caso particular, encontré que esto era más fácil de implementar que otras soluciones publicadas. Es importante que se llame al método de reparación después de salir de WebView, por ejemplo, al presionar hacia atrás y en onStop. Si webView se muestra en un cuadro de diálogo, debe asegurarse de que se llame al método de reparación después de cerrar el cuadro de diálogo, principalmente en onResume y / o onCreate. Y si el webView se carga directamente en onCreate of the Activity y no después en un nuevo fragmento, también se debe llamar al arreglo directamente después de setContentView antes de establecer el título de la actividad, etc. Si el WebView se carga dentro de un fragmento de la actividad, llame al la actividad en onViewCreated del fragmento y la actividad debe llamar al método de reparación. No todas las actividades necesitan extender la clase anterior como se indica en una respuesta, eso es una exageración y no es necesario. Este problema tampoco se resuelve reemplazando WebView por Google Chrome Tabs o abriendo un navegador externo.

Si realmente necesita su configuración de recursos para tener configurada la lista completa de idiomas y no solo uno, entonces necesitaría fusionar esta solución con la que se encuentra en https://gist.github.com/amake/0ac7724681ac1c178c6f95a5b09f03ce En mi caso fue no es necesario.

Tampoco encontré necesario llamar a nuevo WebView (this) .destroy (); como se señala en una respuesta aquí.


En Android N, cuando haces un new WebView() , agregará /system/app/WebViewGoogle/WebViewGoogle.apk a la ruta del recurso, y si no se ha agregado a la ruta, hará que Resource se vuelva a crear.

Entonces, si desea resolver la pregunta, simplemente haga una new WebView(application) en la aplicación antes de cambiar el local.

Si sabes chino, puedes leer este blog .


Mismo problema aquí. Tengo una solución sucia, pero simple.

Como observo que la configuración regional sigue siendo buena en la función Activity.onCreate (...) y no es más válida en la función Activity.onPostCreate (...), simplemente guardo la configuración regional y la fuerzo al final de onPostCreate (...) función.

Aquí vamos :

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

Bonificación: la función de cambio de configuración regional:

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

Espera que ayude.


Ninguna de las respuestas anteriores me ayudó, logré restablecer la configuración regional de la aplicación nuevamente dentro del método onStop () de la actividad que contiene la vista web


Parece que su código establece la configuración regional en la configuración de la aplicación en sí ( MyApplication.getInstance() ). Sin embargo, debe actualizar la configuración para el contexto de la actividad antes de inflar la vista de contenido de la actividad. Descubrí que modificar el contexto de la aplicación no es suficiente (y resulta que ni siquiera es necesario). Si no actualizo cada contexto de actividad, entonces el comportamiento es inconsistente en todas las actividades.

La forma en que AppCompatActivity esto es subclasificar AppCompatActivity (o Activity , si no usa la biblioteca de compatibilidad) y luego derivar todas mis clases de actividad de esa subclase. Aquí hay una versión simplificada de mi código:

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

Luego me aseguro de llamar a super.onCreate(savedInstanceState) en el método super.onCreate(savedInstanceState) de cada subclase antes de llamar a cualquier método (como setContentView() ) que use el contexto.


Quiero agregar un caso de uso más aquí:

Al presionar hacia atrás desde la actividad de vista web (es decir, mostrar la pantalla de pago y el usuario presionar el botón Atrás), onCreate () de la actividad anterior no se ejecuta, por lo que el idioma se restableció nuevamente. Para mantenerlo libre de errores, debemos restablecer la configuración regional de la aplicación en onResume() de la Actividad base.

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

Llame al método anterior en onResume () de la actividad base o al menos en la actividad de vista web.

Editar: si está tratando con Fragmentos, asegúrese de que este método llame cuando el usuario salga de la vista web.


Si está utilizando WebView solo para mostrar texto enriquecido (Texto con algunos párrafos o texto en negrita y cursiva en diferentes tamaños de fuente), puede usar TextView y Html.fromHtml() lugar. TextViews no tiene problemas con la configuración regional ;-)


La respuesta de Ted Hopp logró resolver el problema, pero no abordó la pregunta de por qué ocurre esto.

La razón son los cambios realizados en la clase WebView y su paquete de soporte en Android 7.0.

Fondo:

WebView de Android está construido con WebKit . Si bien originalmente era parte de AOSP, desde KitKat en adelante se tomó la decisión de WebView en un componente separado llamado Android System WebView . Es esencialmente una aplicación de sistema Android que viene preinstalada con dispositivos Android. Se actualiza periódicamente, al igual que otras aplicaciones del sistema, como los servicios de Google Play y la aplicación Play Store. Puede verlo en su lista de aplicaciones de sistema instaladas:

Android 7.0 cambios :

A partir de Android N, la aplicación de Chrome se usará para representar cualquiera / todos los WebView en aplicaciones de Android de terceros. En los teléfonos que tienen Android N listo para usar, la aplicación Android WebView System no está presente en absoluto. En los dispositivos que han recibido una actualización OTA para Android N, la vista web del sistema Android está desactivada:

y

Además, se ha introducido la compatibilidad con múltiples ubicaciones, con dispositivos que tienen más de un idioma predeterminado:

Esto tiene una consecuencia importante para las aplicaciones que tienen varios idiomas. Si su aplicación tiene WebView s, estos se representan con la aplicación Chrome. Debido a que Chrome es una aplicación de Android en sí misma , que se ejecuta en su propio proceso de espacio aislado, no estará vinculada a la configuración regional establecida por su aplicación. En cambio, Chrome volverá a la configuración regional del dispositivo principal. Por ejemplo, supongamos que la configuración regional de su aplicación está configurada en ar-AE , mientras que la configuración regional principal del dispositivo es en-US . en-US . En este caso, la configuración regional de la Activity contiene un WebView cambiará de ar-AE a en-US , y se mostrarán cadenas y recursos de las carpetas locales correspondientes. Es posible que vea una mezcla de cadenas / recursos LTR y RTL en las Activity que tienen WebView .

La solución:

La solución completa a este problema consta de dos pasos:

PASO 1:

Primero, restablezca la configuración regional predeterminada manualmente en cada Activity , o al menos en cada Activity que tenga un 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()); }

Llame al método anterior antes de llamar a setContentView(...) en el método onCreate() de todas sus Actividades. El parámetro de locale debe ser la configuración Locale predeterminada que desea establecer. Por ejemplo, si desea establecer árabe / Emiratos Árabes Unidos como la configuración regional predeterminada, debe pasar la new Locale("ar", "AE") configuración new Locale("ar", "AE") . O si desea establecer la configuración regional predeterminada (es decir, la configuración Locale que establece automáticamente el sistema operativo), debe pasar Locale.US .

PASO 2:

Además, debe agregar la siguiente línea de código:

new WebView(this).destroy();

en el onCreate() de su clase de Application (si tiene uno), y en cualquier otro lugar el usuario puede estar cambiando el idioma. Esto se encargará de todo tipo de casos extremos que puedan ocurrir al reiniciar la aplicación después de cambiar el idioma (puede haber notado cadenas en otros idiomas o con la alineación opuesta después de cambiar el idioma en las Activities que tienen WebView s en Android 7.0 ++) .

Como anexo, las pestañas personalizadas de Chrome son ahora la forma preferida de representar páginas web integradas en la aplicación.

Referencias

1. Android 7.0: cambios para WebView .

2. Comprender los parches de seguridad de WebView y Android .

3. WebView para Android .

4. WebView: desde "Powered by Chrome" hasta Chrome .

5. Turrón WebView .

6. Android 7.0 Turrón .

7. Android N Mysteries, Parte 1: ¿El sistema Android WebView es solo "Chrome" ahora? .