El poder de los WebViews en Flutter

Argel Bejarano
Comunidad Flutter
Published in
8 min readFeb 1, 2019

Estamos de regreso muy rápido con una traducción más, en esta ocasión le toca a una gran persona que siempre esta no solo trabajando directamente para nuestro SDK favorito si no también siempre apoyando a la comunidad con este tipo de post, la vez pasada nos apoyo a descubrir el uso de Slivers, si no han adivinado aún se trata ni mas ni menos que de Emily Fortuna, una de mis personas favoritas del Flutterverse!

En esta ocasión hablaremos de uno de los widgets liberado hace no mucho tiempo y que esta teniendo un gran auge: WebView. Sin mas por el momento entremos de lleno al tema.

Logo de la comunidad de Flutter en Español

¿Quieres escribir una aplicación que pueda mostrar una página web sin tener que abrir el navegador de tu dispositivo móvil? O quizás ya tiene un flujo de pago seguro implementado en tu sitio web y no quieres volver a implementar la funcionalidad de pago en su aplicación móvil — el dinero puede ser un negocio complicado y no quieres terminar enviando accidentalmente la mitad del pago al Fondo salven al Kraken. Oh, ¿soy sólo yo? Bueno, de todas formas, el equipo de Flutter ha creado un plugin realmente genial que te permite incorporar WebViews en tu aplicación de Flutter para hacer posible toda esta funcionalidad.

Me refería a la funcionalidad de mostrar sitios web en aplicaciones Flutter… no a rehabilitar krakens!

Los WebViews de Flutter son como cualquier otro widget

Incorporar el plugin WebView en su aplicación es extremadamente sencillo. Es sólo un widget como cualquier otro: WebView(initialUrl: ‘https://flutter.io'). También puede activar o desactivar JavaScript en su WebView con el parámetro javascriptMode. Por defecto, JavaScript en su WebView está desactivado, así que para habilitarlo construya una WebView como ésta:

WebView(
initialUrl: 'https://flutter.io',
javascriptMode: JavascriptMode.unrestricted,
)

Prácticamente toda la información que quieres saber sobre su WebView y también la habilidad de controlar su WebView ocurre a través del…. esperaaa … WebViewController. Este controlador devuelve en un callback cuando el WebView está completamente construido:

WebViewController _controller;
WebView(
initialUrl: 'https://flutter-es.io',
onWebViewCreated: (WebViewController webViewController) {
_controller = webViewController;
},
);
//...mas tardes, probablemente en respuesta a algún evento:
_controller.loadUrl('http://dartlang.org/');

El WebViewController es tu ticket para modificar el WebView programáticamente desde Flutter o acceder a propiedades como la URL actual que se muestra. Para ver cómo funciona todo esto en la práctica, escribí una sencilla aplicación de navegación de Wikipedia que te permite marcar páginas para más tarde, de modo que el completador que hay en ti nunca se olvide de ese último fascinante artículo de Wikipedia la próxima vez que te encuentres cayendo en un agujero de conejo wiki.

Una aplicación para explorar Wikipedia escrita en Flutter usando WebViews. Puede guardar sus páginas favoritas para verlas más tarde

El código completo de este Wiki-rabbit-hole-browser se puede encontrar en este repositorio GitHub.

WebView es como cualquier otro widget en Flutter y puede ser compuesto con otros widgets superpuestos. Tenga en cuenta que el botón favorito es sólo un FloatingActionButton normal que está flotando en la parte superior del WebView, completo con el efecto de sombra que esperaría con el botón. Además, cuando el menú desplegable de la barra de aplicaciones está abierto, cubre parcialmente el WebView como cualquier otro widget debajo del menú.

Si observas el código, notará que utilizo la clase Completer y FutureBuilder con frecuencia en este ejemplo. Declarar la variable de instancia _controlador como Completador es como establecer un marcador de posición para el WebViewController. Podemos comprobar si tenemos el WebViewController en funcionamiento llamando a _controller.isCompleted (es decir, se completa cuando tenemos el WebViewController válido) o utilizando un FutureBuilder con _controller.future. Usar un FutureBuilder nos permite construir nuevos componentes de interfaz como el FloatingActionButton para añadir favoritos sólo después de que tengamos un WebViewController en funcionamiento (de lo contrario, el programa no tendría forma de obtener currentUrl al guardar una página favorita).

Otras dos características de WebViews pueden ser un poco complejas, así que echemos un vistazo más de cerca en las dos secciones siguientes.

WebViews pueden capturar gesticulaciones especificas también

Dado que los WebViews son widgets de Flutter, pueden participar en el protocolo de desambiguación de gestos de Flutter (también conocido como Gesture Arena). De forma predeterminada, una WebView sólo responde a un gesto si ningún otro widget lo reclama. Pero puede hacer que WebView reclame proactivamente un gesto especificando gestureRecognizers.

Si tu WebView está dentro de otro widget que responde a los gestos, por ejemplo un ListView, es posible que quieras especificar cómo responde tu aplicación a los gestos. Si el usuario arrastra el dedo por la pantalla, ¿debería desplazarse por ListView o WebView? Si desea que ambos widgets se puedan desplazar, el widget de WebView puede “capturar” el movimiento de arrastre para que se desplace cuando el usuario arrastra la vista web, pero desplaza la vista de lista de lo contrario, puede especificar qué gestos se transfieren al widget de WebView con el parámetro gestureRecognizers. El parámetro toma un conjunto de todos los GestureRecognizers que desea capturar. Tampoco se asuste por ese objeto de Fábrica — es básicamente sólo un método de construcción glorificado. Para capturar el evento de desplazamiento vertical, puedo escribir esto:

WebView(
initialUrl: someUrl,
gestureRecognizers: Set()
..add(Factory<VerticalDragGestureRecognizer>(
() => VerticalDragGestureRecognizer())),
)

O, escrito de otra manera:

var verticalGestures = Factory<VerticalDragGestureRecognizer>(
() => VerticalDragGestureRecognizer());
var gestureSet = Set.from([verticalGestures]);
return WebView(
initialUrl: someUrl,
gestureRecognizers: gestureSet,
);

Si ves el Boring Flutter Development Show, puede que nos haya visto desarrollar el Kraken News, es decir, la Hacker News Reader App.

La última versión de la aplicación Hacker News que hemos estado desarrollando en nuestro programa de YouTube

Para mostrar la captura de gestos en el contexto de una aplicación, modifiqué la aplicación Hacker News para mostrar parte de la página web como una “vista previa”. Esto permite al usuario desplazarse verticalmente por la página enlazada para determinar si desea abrirla en una página separada para una lectura más profunda.

Aplicación Hacker News Reader con vistas previas de los enlaces en WebView. Las Vistas Web capturan el gesto de arrastre vertical para permitir el desplazamiento de las vistas previas.

El código para esta aplicación de lectura Hacker News se puede encontrar en este repositorio de GitHub. (tal vez mostrar código para _buildItem aquí).

Sin embargo, si el WebView está dentro de un widget que sólo captura gestos que no le importan, no es necesario un detector de gestos. Por ejemplo, un PageController sólo responde a gestos de arrastre horizontal, y usted sólo quiere que el WebView pueda desplazarse verticalmente, puede escribir el código de esta manera:

PageView(children: [
WebView(initialUrl: urlOne),
WebView(initialUrl: urlTwo),
WebView(initialUrl: urlThree),
]));
WebViews en un PageView. El PageView controla el deslizamiento horizontal y las Vistas Web pueden desplazarse verticalmente sin trabajo adicional de su parte.

Tus WebViews podrías necesitar un parámetro clave

Probablemente has visto esos omnipresentes parámetros clave opcionales salpicados en casi todos los constructores de Widgets de la base de código de Flutter. Las claves son necesarias si tiene varios widgets de estado del mismo tipo que se eliminan, añaden o reordenan en su aplicación. Resulta que WebView es un widget de estado (el estado que incluye la página actual y el historial del navegador). Por lo tanto, si tiene múltiples WebViews en su aplicación, es posible que necesite agregar un parámetro clave.

Un ejemplo de esta situación está en la aplicación Hacker News! Esto es lo que sucede si cambiamos de pestañas y nuestras WebViews no tienen teclas:

Esto es lo que pasa si no usas las teclas en una aplicación de estado. Cuando cambiamos a la pestaña “Nuevas historias” se muestra la página de vista previa de la web equivocada.

Como puedes ver, cuando cambiamos de pestañas, la ficha “Interview with Alan Kay” (Entrevista con Alan Kay) se amplía, pero la vista web sigue mostrando la página de la BBC sobre Virgin Galactic. Esto se arregla poniendo una llave en el widget de la colección más alta (en este caso la ExpansionTile):

Whew! El uso de las claves corrige el problema mostrando un WebView diferente (y el sitio web correcto correspondiente) para cada elemento de la aplicación de lectura.

La explicación súper abreviada de por qué las claves resuelven esto es que cuando Flutter cambia la lista de historias a mostrar, ve que cada conjunto de historias está hecho de un ListView con elementos de ExpansionTile. Flutter tiene un algoritmo de comparación rápida para evitar redibujar innecesariamente la pantalla que comprueba el tipo de widget y la clave. Sin una clave, debido a que los tipos de widgets de cada lista son los mismos, todos los elementos sin estado (como los títulos de los enlaces) se actualizan, pero los componentes con estado (como el estado expandido de ExpansionTile y la URL del sitio web), no se pueden redibujar. La adición de una clave corrige este problema. Para una explicación más detallada, consulte este vídeo sobre las teclas:

Del mismo modo, si utiliza WebViews en el contexto de un widget de Hero, querrá utilizar una clave global para que Flutter sepa que las dos WebViews son realmente las mismas y no intente volver a mostrar la segunda.

Algunas cosas a tener en cuenta:

El plugin WebView se encuentra actualmente en Developer Preview mientras que nosotros terminamos de añadir polish. Esto significa que si desea ejecutar el plugin de vista web en iOS, también necesita añadir la siguiente línea dentro de <dict> en su ios/Runner/Info.plist:

<key>io.flutter.embedded_views_preview</key><string>yes</string> como se describe en este problema en GitHub.

Actualmente también hay un problema conocido con el teclado Android, y el equipo de Flutter está trabajando en una solución.

Hay otro plugin de WebView basado en la comunidad aunque no tiene toda la funcionalidad del plugin anterior por parte del equipo de Flutter. Simplemente muestra una página web en una vista nativa y no está integrada con el resto del árbol de widgets Flutter. Por lo tanto, esa versión no le permite componer vistas web con otros widgets de Flutter. El uso del plugin webview_flutter descrito en este artículo evita este problema.

¡Eso es todo amigos! Siga adelante y agregue WebViews a sus aplicaciones Flutter. Y dale a esos krakens un poco de amor también.

Así se termina una entrega más de excelentísimo trabajo que hace no solo la comunidad si no también lo que viene directamente de la fuente, Google.

No me queda mas que agradecerle la oportunidad a Emily Fortuna por trabajar con sus posts! 😃 .

No dejen de aletear!

--

--

Argel Bejarano
Comunidad Flutter

Flutter & Dart GDE | Speaker and Editor from Comunidad Flutter | Founder @EsFlutter