Saltar al contenido principal

Capacidades y políticas

Aprende a adaptar tu app a las capacidades y políticas requeridas por la plataforma, la tienda de aplicaciones, tu empresa, etc.

La mayoría de las apps del mundo real necesitan adaptarse a las capacidades y políticas de diferentes dispositivos y plataformas. Esta página contiene consejos sobre cómo gestionar estos escenarios en tu código.

Diseña aprovechando las fortalezas de cada tipo de dispositivo

#

Considera las fortalezas y debilidades únicas de los diferentes dispositivos. Más allá del tamaño de su pantalla y sus entradas, como táctil, mouse, teclado, ¿qué otras capacidades únicas puedes aprovechar? Flutter permite que tu código se ejecute en diferentes dispositivos, pero un buen diseño es más que simplemente ejecutar código. Piensa en lo que hace mejor cada plataforma y mira si hay capacidades únicas que aprovechar.

Por ejemplo: la App Store de Apple y la Play Store de Google tienen reglas diferentes a las que las apps deben atenerse. Los diferentes sistemas operativos anfitriones tienen capacidades distintas a lo largo del tiempo así como entre ellos mismos.

Otro ejemplo es aprovechar la barrera de entrada extremadamente baja de la web para compartir. Si estás desplegando una app web, decide qué enlaces profundos (deep links) admitir, y diseña las rutas de navegación teniéndolos en cuenta.

El patrón recomendado por Flutter para gestionar diferentes comportamientos basados en estas capacidades únicas es crear un conjunto de clases Capability y Policy para tu app.

Capacidades

#

Una capacidad (capability) define lo que el código o dispositivo puede hacer. Ejemplos de capacidades incluyen:

  • La existencia de una API
  • Restricciones impuestas por el SO
  • Requisitos de hardware físico (como una cámara)

Políticas

#

Una política (policy) define lo que el código debería hacer.

Ejemplos de políticas incluyen:

  • Guías de la tienda de aplicaciones
  • Preferencias de diseño
  • Recursos (assets) o textos que hacen referencia al dispositivo anfitrión
  • Funciones habilitadas en el lado del servidor

Cómo estructurar el código de políticas

#

La forma mecánica más simple es Platform.isAndroid, Platform.isIOS y kIsWeb. Estas API te permiten saber mecánicamente dónde se está ejecutando el código, pero tienen algunos problemas a medida que la app expande dónde se puede ejecutar, y a medida que las plataformas anfitrionas añaden funcionalidad.

Las siguientes guías explican las mejores prácticas al desarrollar las capacidades y políticas para tu app:

Evita usar Platform.isAndroid y funciones similares para tomar decisiones de diseño (layout) o suposiciones sobre lo que un dispositivo puede hacer.

En su lugar, describe aquello sobre lo que deseas ramificar en un método.

Ejemplo: Tu app tiene un enlace para comprar algo en un sitio web, pero no quieres mostrar ese enlace en dispositivos iOS por razones de política.

dart
bool shouldAllowPurchaseClick() {
  // Banned by Apple App Store guidelines.
  return !Platform.isIOS;
}

...
TextSpan(
  text: 'Buy in browser',
  style: new TextStyle(color: Colors.blue),
  recognizer: shouldAllowPurchaseClick ? TapGestureRecognizer()
    ..onTap = () { launch('<some url>') : null;
  } : null,

¿Qué obtuviste al añadir una capa adicional de indirección? El código deja más claro por qué existe la ruta ramificada. Este método puede existir directamente en la clase, pero es probable que otras partes del código necesiten esta misma verificación. Si es así, coloca el código en una clase.

policy.dart
dart

class Policy {

  bool shouldAllowPurchaseClick() {
    // Banned by Apple App Store guidelines.
    return !Platform.isIOS;
  }
}

Con este código en una clase, cualquier prueba de widget puede simular (mock) Policy().shouldAllowPurchaseClick y verificar el comportamiento independientemente de dónde se ejecute el dispositivo. También significa que más adelante, si decides que comprar en la web no es el flujo adecuado para los usuarios de Android, puedes cambiar la implementación y las pruebas para texto cliqueable no necesitarán cambiar.

Capacidades

#

A veces quieres que tu código haga algo pero la API no existe, o tal vez dependes de una función de plugin que aún no está implementada en todas las plataformas que admites. Esta es una limitación de lo que el dispositivo puede hacer.

Esas situaciones son similares a las decisiones de política descritas anteriormente, pero se denominan capacidades (capabilities). ¿Por qué separar las clases de políticas de las capacidades cuando la estructura de las clases es similar? El equipo de Flutter ha descubierto en apps en producción que hacer una distinción lógica entre lo que las apps pueden hacer y lo que deberían hacer ayuda a que los productos más grandes respondan a los cambios en lo que las plataformas pueden hacer o requerir, además de tus propias preferencias después de que se escribe el código inicial.

Por ejemplo, considera el caso en el que una plataforma añade un nuevo permiso que requiere que los usuarios interactúen con un diálogo del sistema antes de que tu código llame a una API sensible. Tu equipo realiza el trabajo para la plataforma 1 y crea una capacidad llamada requirePermissionDialogFlow. Luego, si y cuando la plataforma 2 añada un requisito similar pero solo para versiones nuevas de la API, entonces la implementación de requirePermissionDialogFlow ahora puede verificar el nivel de API y devolver true para la plataforma 2. Has aprovechado el trabajo que ya habías hecho.

Políticas

#

Te animamos a comenzar con una clase Policy inicialmente incluso si parece que no tomarás muchas decisiones basadas en políticas. A medida que crece la complejidad de la clase o se expande el número de entradas, podrías decidir dividir la clase de políticas por función u otros criterios.

Para la implementación de políticas, puedes usar implementaciones respaldadas en tiempo de compilación, tiempo de ejecución o llamadas a procedimientos remotos (RPC).

Las verificaciones de políticas en tiempo de compilación son buenas para plataformas donde es poco probable que cambie la preferencia y donde cambiar accidentalmente el valor podría tener grandes consecuencias. Por ejemplo, si una plataforma exige que no enlaces a la Play Store, o exige que uses un proveedor de pagos específico dado el contenido de tu app.

Las verificaciones en tiempo de ejecución pueden ser buenas para determinar si hay una pantalla táctil que el usuario pueda usar. Android tiene una función que puedes verificar y tu implementación web podría verificar los puntos táctiles máximos.

Los cambios de política respaldados por RPC son buenos para el despliegue incremental de funciones o para decisiones que podrían cambiar más adelante.

Resumen

#

Utiliza una clase Capability para definir lo que el código puede hacer. Podrías verificar la existencia de una API, restricciones impuestas por el SO y requisitos de hardware físico (como una cámara). Una capacidad suele implicar verificaciones en tiempo de compilación o ejecución.

Utiliza una clase Policy (o clases según la complejidad) para definir lo que el código debería hacer para cumplir con las guías de la tienda de aplicaciones, preferencias de diseño y recursos o textos que necesiten hacer referencia al dispositivo anfitrión. Las políticas pueden ser una mezcla de verificaciones en tiempo de compilación, ejecución o RPC.

Prueba el código ramificado simulando (mocking) capacidades y políticas para que las pruebas de widgets no necesiten cambiar cuando las capacidades o políticas cambien.

Nombra los métodos en tus clases de capacidades y políticas en función de lo que intentan ramificar, en lugar del tipo de dispositivo.