Parte 4 – Configurar Proyecto Flutter para escuchar las notificaciones

Este post es parte del tutorial Flutter agregar push notificaciones para IOS y Android

En main importar el paquete

import 'package:firebase_messaging/firebase_messaging.dart';

En _MyHomePageState , agregar una variable de firebase messaging y configurar sus listener.

...
class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
  
  @override
  void initState() {
    super.initState();
    _firebaseMessaging.configure(
      onMessage: (Map<String, dynamic> message) async {
        print("onMessage: $message");
      },
      onLaunch: (Map<String, dynamic> message) async {
        print("onLaunch: $message");
      },
      onResume: (Map<String, dynamic> message) async {
        print("onResume: $message");
      },
    );
    _firebaseMessaging.requestNotificationPermissions(
        const IosNotificationSettings(
            sound: true, badge: true, alert: true, provisional: true));
    _firebaseMessaging.onIosSettingsRegistered
        .listen((IosNotificationSettings settings) {
      print("Settings registered: $settings");
    });
    _firebaseMessaging.getToken().then((String token) {
      assert(token != null);
      print("Token: $token");
    });
  }
...

Lanzar el emulador IOS, en caso no sepa como hacerlo, en los siguientes link se describe como:

.

.

Corriendo debera notar que imprime un token

Con el token podemos dirigir la notificación para este dispositivo, esto es opcional ya que sino lo especificamos enviara a todos, pero lo haremos así para poder probar mas rápido porque las notificaciones pueden demorar hasta 1 semana según la documentación.

Vamos a firebase > Cloud Messaging > send your first message

Luego llenamos el formulario y click en “Enviar mensaje de prueba”

Pegamos el token en la ventana luego click en boton “+” y click en “probar”

Revisando el output en visual studio code, se vera la notificación

flutter: onMessage: {from: 1064278709680, collapse_key: com.example.demoNotifications, notification: {body: Contenido de prueba, title: Prueba, e: 1, tag: campaign_collapse_key_5758946879053100963}}

Parte 3 – Creamos proyecto en Firebase

Este post es parte del tutorial Flutter agregar push notificaciones para IOS y Android

Creamos proyecto en firebase desde https://console.firebase.google.com/ y luego click en “Agregar proyecto

En este caso lo nombraremos demo-notifications-flutter

seguir los siguientes pasos, continue hasta crear el proyecto,

En el panel que se muestra, escogemos IOS

En el formulario de registro, pedirá el Id del proyecto, para obtenerlo abrir el proyecto en xcode, abrir el archivo Runner.xcworkspace

Seleccionar según la imagen Runner>Runner>General y copiar lo que indica en Bundle identifier

Volvemos al registro de firebase y llenamos los datos, click en “Registrar app

Descargamos el archivo GoogleService-Info.plist

Copiar el archivo según indica, ojo: copiarlo en la carpeta no tendrá efecto, debe copiarse en el proyecto en xcode, click en siguiente

En este paso se agregaría la librería de firebase, pero eso lo hicimos en un paso previo

Luego ejecutar pod install, flutter ya instancio el pod, para eso ubicarse en la carpeta ios desde la terminal y ejecutar pos install

Si todo va bien debería mostrar un mensaje así.

SI Xcode muestra una advertencia puede cerrarlo, será necesario abrirlo luego.

Ignoraremos el siguiente paso, ya que estamos en un proyecto flutter, eso lo haremos en el proyecto flutter en el siguiente paso, click en Siguiente

y click en “Ir a consola”.

Parte 2 – Agregar dependencias de Firebase Messaging

Este post es parte del tutorial Flutter agregar push notificaciones para IOS y Android

Abrir el proyecto flutter en Visual studio code

Ahora buscamos los paquetes que necesitaremos en https://pub.dev y buscar firebase messaging

Click en “Installing” y seguir las instrucciones, para esta versión indica, agregar firebase_messaging: ^7.0.3 en el archivo pubspec.yaml las dependencias

...
dependencies:
  flutter:
    sdk: flutter
  firebase_messaging: ^7.0.3
...

Guardar el archivo y Visual Studio comenzará a obtener las dependencias, esperar que termine.

Si todo va bien debe mostrar el siguiente mensaje

Listo.

Flutter agregar push notificaciones para IOS y Android

Nota: Revisar la fecha y las dependencias usadas, ya que por políticas de las plataformas o nuevas versiones de estas librerías las indicaciones pueden variar

Para los que pueden guiarse de la documentación oficial, solo necesitan:

Sino pueden ver paso a paso.

Parte 1 – Creamos un proyecto Flutter

Este post es parte del tutorial Flutter agregar push notificaciones para IOS y Android

Para este ejemplo creo una aplicación por defecto de flutter

flutter create demo_notifications

Figma to Android , Exportar icono desde Figma para proyecto android ( svg )

En Figma, seleccionar el icono y en el menú derecho inferior buscar la opción exportar, escoger el formato y click en exportar.

Si es como un archivo no vector , se puede pegar tal cual o redimencionar para cada formato

Una web que puede servir según para que se use es

https://romannurik.github.io/AndroidAssetStudio/index.html

Luego para importar la imagen como vector, desde android ir a la carpeta drawable ( click derecho )> New > Vector Asset

Seleccionar local, configurar y finalizar

Debe quedar un archivo xml mostrando el icono ,y se puede usar como drawable.

Kotlin Koin inyección con parámetros

koin

Para instalar y configurar un ejemplo básico de ejemplo puede verlo en la documentación https://start.insert-koin.io/#/quickstart/android-java

Luego surge la pregunta de cómo hacerlo si al momento de construir necesita parámetros del lugar donde se instancia , como el caso del Presenter(iView), donde al instancia el presenter se debe pasar la vista que implementa la interfaz de la vista que usa el presenter.

Modificando un poco el ejemplo se puede hacer así.

Para mi caso, la clase Presenter y interfaz en kotlin es:

class PedidosPresenter(var view: IPedidosView) {
    fun sayHello () {
        view.sayHello()
    }
}

interface IPedidosView
{
    fun sayHello()
}

sayHello, solo es un método para comprobar que view es el fragment que debe referenciar.

En mi caso el fragment esta en Java, mas abajo coloco el como es el mismo código en kotlin.

public class PedidosFragment extends Fragment implements IPedidosView {

    private Lazy<PedidosPresenter> pedidosPresenter = KoinJavaComponent.inject(PedidosPresenter.class, null , () -> DefinitionParametersKt.parametersOf(this)); //se coloco THIS porque el fragmento es quien implemento IPedidosView

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
       
        View view = inflater.inflate(R.layout.fragment_home_pedidos, container, false);
        pedidosPresenter.getValue().sayHello();
         /**more code**/
        return view;
    }

    @Override
    public void sayHello() {
        Log.i("KOIN","Oh yes");
    }
 /**more code**/
}

Y la configuración de los módulos:

object KoinModules
{
    @JvmStatic
    fun getModules(): Module {
        return module {
            single { (view : IPedidosView) -> PedidosPresenter(view) }
        }
    }
}

En resumen, en la configuración de módulos se indica que parámetros recibirá

single { (view : IPedidosView) -> PedidosPresenter(view) }

y en la inyección, se debe agregar como tercer parámetro un mapeo de los parámetros que necesita.

private Lazy<PedidosPresenter> pedidosPresenter = KoinJavaComponent.inject(PedidosPresenter.class, null , () -> DefinitionParametersKt.parametersOf(this)); //se coloco THIS porque el fragmento es quien implemento IPedidosView

Las demás configuraciones son igual al de la guía.

Referencias:

Inyección con parámetros en kotlin
https://github.com/InsertKoinIO/koin/blob/master/koin-projects/docs/reference/koin-core/injection-parameters.md

Issue del tema en caso deseen reabrirlo
https://github.com/InsertKoinIO/koin/issues/62

Github de Koin
https://github.com/InsertKoinIO/koin

Kodein opción a Koin en caso no se pudiera
https://www.kotlindevelopment.com/koin-vs-kodein/

Articulo de Clean arquitecture por el cual surgió la duda
https://devexperto.com/clean-architecture-android/

Link de referencia que revise

Usar librería común entre dos proyectos Android

Un problema cuando se tiene dos aplicaciones del mismo proyecto que usan cosas comunes como el : estilo del app, iconos, textos, api rest, pero por ser dirigidas a diferentes roles tienen funcionalidades distintas, algunas soluciones, dirigidas a rehusar código o minimizar repetir trabajo:

  1. Usar flavor para cada tipo de rol y separarlas
  2. Usar proguard para que según una condición no compile algunos módulos
  3. Usar android app bundle para cargar las partes según demanda
  4. Usar librería común por path
  5. Usar aar común
  6. etc..

No son todas las opciones, ni las mejores, solo las que analice, dependiendo del problema alguno puede ser mejor, en mi caso:

  1. Tendría varios flavor y manejar las constantes seria un poco trabajoso, ademas de la demora de compilación por todo el código en una app
  2. Agrega mas tiempo de compilación.
  3. Seria una idea a probar si la app fuera de cero, pero ya esta avanzada y tendría que refactorizarla, lo cual si esta bien estructurada no seria muy complejo pero si trabajoso, pero es también el tiempo de probar nuevamente cada módulo.
  4. Es la que escogí ya que como esta en desarrollo, los cambios que haga en una serán reflejadas en la otra fuente sin tener que reimportar el modulo.
  5. Seria una solución si los recursos comunes ya estaría casi en su versión final o final.

Entonces aplicando la solución 4 se podría hacer así:

Escoger los recursos comunes : rest api, sql, estilos, views, cadenas, traducciones, colores, layouts, constantes de servidor, iconos, raws, librerias comunes, etc.

Mover los recursos comunes en una librería, en mi caso lo llame common

Estructura del proyecto

Luego agregarlo como referencia en build.gradle

apply plugin: 'com.android.application'
.....
dependencies {
    ....
    //LIBRARY COMUN
    implementation project(':common')
}

Luego en los demás proyectos que usen la librería se debe importar por dirección de la carpeta, esto se hace desde el archivo settings.gradle

include ':app',':common'
project(':common').projectDir = new File( '/ruta/a/carpeta/common')

Y en build.gradle, agregarlo igual que en el proyecto original

apply plugin: 'com.android.application'
.....
dependencies {
    ....
    //LIBRARY COMUN
    implementation project(':common')
}