La configuración y puesta a punto para el desarrollo en macOSX de aplicaciones Flutter, puede llevar mas tiempo productivo del deseable. Acá sigue el resumen de los inconvenientes y sus soluciones mínimas.

Índice

Conceptos clave

Key concepts

  • Los mixins son simplemente clases sin constructor.
mixin GotosMixin {
  static const _scrollDelta = 200.0;
  static const _refreshTrigger = -60.0;
  
  ...

  void _handleScroll() {
    ...
  }
}

class _LoginPageState extends State<LoginPage> with GotosMixin {
 ...
}

TL;DR

Generando claves utilizando keytool

¡No instales el JDK completo! Muchas soluciones en Stackoverflow lo sugieren. Sin embargo alcanza con utilizar la herramienta que trae el propio Android Studio en la siguiente ruta:

/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/keytool

Generamos la clave para el ambiente debug:

./keytool -genkey -v -keystore ~/[DESTINO]/key2.jks -keyalg RSA -keysize 2048 -validity 10000 -alias androiddebugkey

MacOS X no viene con un JDK preinstalado por lo tanto el comando /usr/libexec/java_home nos devolverá que la versión de JVM no pudo ser encontrada.

Para obtener la huella digital o firma del certificado SHA-1 lo hacemos con el siguiente comando:

./keytool -keystore ~/key.jks -list -v

Para Facebook deberemos generar el hash de la clave de desarrollo. Y recordar que si nuestra app ya se publicó » también debes agregar el hash de clave de activación.»

/keytool -exportcert -alias androiddebugkey -keystore [KEY_PATH] | openssl sha1 -binary | openssl base64

 

Conservando el estado en un StatefulWidget

// agregar el SingleTickerProviderStateMixin y sobreescribir el getter wantKeepAlive
class _FavoritesViewState extends State<FavoritesView> with SingleTickerProviderStateMixin {

  @override
  bool get wantKeepAlive => true;
}

 

Actualizar el estado del Widget padre mediante callback

# En el Widget Hijo : Agregar parámetro de la función
# De ser necesario también hacer que acepte parámetros "dynamic Function(int a)?"

class ChildWidget extends StatefulWidget {
  final Function() notifyParent;
  ChildWidget({Key key, @required this.notifyParent}) : super(key: key);
}

# 2.En el Widget Padre : crear una función para que el hijo haga el callback

refresh() {
  setState(() {});
}

# 3. En el Widget Padre : pasar la función como parámetro para el Widget Hijo.

new ChildWidget( notifyParent: refresh );  

# 4. En el Widget Hijo : llamar la función del padre.

  widget.notifyParent();

Existen otras veces que en Flutter necesitamos actualizar datos globales de la aplicación desde una vista del Navigator y actualizar el widget o la vista que queda debajo tras realizar un pop.

Lo hacemos así:

// En la primera página

Navigator.pushNamed(context, '/page2').then((_) => setState(() {}));

// En la segunda página:

Navigator.pop(context);

Esta solución no es propia sino del usuario CopsOnRoad de StackOverflow. Se puede encontrar la respuesta completa en este enlace.

 

Cambiar el estado de un Widget inmediatamente después del build

Algunas veces necesitamos actualizar un estado en el build. En esta instancia esto no es posible ya que el widget está en construcción, por lo que tenemos que esperar que Flutter termine el renderizado para poder cambiar un estado.

Lo conseguimos de la siguiente manera:

 @override
  void initState() {
    super.initState();
    _lastOrderData = SharedServices.lastShippingDetails(); // futuro

    WidgetsBinding.instance?.addPostFrameCallback((_){

      _lastOrderData.then((value){
        _dropdownValue = value!.city!; // obtenemos el valor deseado y cambiamos el estado
      });

    });

  }

Sobreescribir el Theme para una parte de la aplicación.

A veces necesitamos sobre-escribir el los estilos de nuestra aplicación declarados, por ejemplo como colorScheme, para algún widget en particular, sin afectar al resto de la app.

Para conseguirlo podemos utilizar el widget Theme de la siguiente manera.

Theme.of(context).copyWith(colorScheme: ColorScheme.light(primary: Colors.black))

En este caso estamos redefiniendo el color primario utilizado por el widget showDialog, exclusivamente en este contexto.

El ejemplo completo es el siguiente:

void _showMultiSelect(BuildContext context) async {
    await showDialog(
      context: context,
      //barrierColor: Colors.white,
      useSafeArea: true,
      builder: (context) {
        return Theme(
          data: Theme.of(context).copyWith(colorScheme: ColorScheme.light(primary: Colors.black)),
          child: MultiSelectDialog(
            backgroundColor: Colors.white.withOpacity(1),
            checkColor: Colors.black,
            cancelText: Text("Cancelar"),
            confirmText: Text("Buscar"),
            searchHint: "Buscar",
            title: Text("Tipos de cervezas"),
            searchable: true,
            items: _animals.map((e) => MultiSelectItem(e, e.name)).toList(),
            initialValue: _selectedBeers,
            onConfirm: (values) {
              setState(() {
                _selectedBeers = values;
              });
              Navigator.of(context).pop();
              
            },
          ),
        );
      },
    );
  }

Mas información al respecto en este enlace de la documentación oficial.

Aceptar las licencias del Android SDK

Encontrar el sdkmanager para aceptar las licencias del Android SDK, necesario para trabajar y compilar flutter, puede ser un dolor de cabeza en Mac OS.
Aquí está su ruta, los problemas comunes y las soluciones.

La ruta.

~/Library/Android/sdk/tools/bin/sdkmanager --licenses

Un posible error a encontrar al ejecutar este comando es:

The operation couldn’t be completed. Unable to locate a Java Runtime.
Please visit http://www.java.com for information on installing Java.
Instalando Flutter CLI
Instalamos las herramientas de lineas de comando.

Una vez instaladas las herramientas de lineas de comando, podemos volver con el comando previsto para la aceptación de las licencias.

flutter doctor --android-licenses

 

Generar códigos QR en Flutter

Una librería simplísima de utilizar para renderizar códigos QR en Flutter es qr_flutter.
El uso no puede ser mas simple.

    QrImage(
    data: "1234567890",
      version: QrVersions.auto,
      size: 200.0,
    ),

 

Escanear códigos QR en Flutter

Para el caso de que necesitemos escanear un código QR podemos utilizar el paquete qr_code_scanner, que utiliza zxing en Android y MTBBarcode scanner en iOS.
El amigo Johannes Milke tiene este buen video tutorial sobre cómo crear la vista.

Es importante recordar que para que qr_code_scanner funcione en Android la minSdkVersion debe ser 20.
Para modificar este valor debemos modificar el siguiente archivo:
Android > app > build.gradle. Y en el bloque defaultConfig cambiar minSdkVersion a 20.

Los demás detalles para la correcta instalación y utilización de este paquete están en su página de Github.

https://www.youtube.com/embed/hHehIGfX_yU
flutter-qr-code
Un ejemplo de qr_code_scanner en funcionamiento.

Anidando dos llamadas a futuros

En Flutter a veces necesitamos resolver mas de un FutureBuilder antes de procesar un widget.
Esta es una forma interesante de resolverlo.
La respuesta completa las podés encontrar en esta respuesta de StackOverflow.

Future<AsyncSnapshot> getProfiles() async {
  var gamesSnapshot = await Firestore.instance.collection('games').document(this.documentId).get();
  return Firestore.instance.collection('profiles').document(gamesSnapshot.data['authorId']).get()
}

@override
Widget build(BuildContext context) {
  return new FutureBuilder(
    future: getProfiles(),
    builder: (BuildContext profilesContext, AsyncSnapshot profilesSnapshot) {
      // Code goes here.
    }
  ),
}