- Need to use minimal Dart SDK version ^3.5.0
- Need to use minimal Flutter version 3.24.3
- Rename package from
common_module_fluttertoosam_common_module_flutter- On pubspec.yaml, change
common_module_fluttertoosam_common_module_flutter - On imports, change
import 'package:common_module_flutter/common_module_flutter.dart';toimport 'package:osam_common_module_flutter/osam_common_module_flutter.dart';
- On pubspec.yaml, change
- To import, use only
import 'package:osam_common_module_flutter/osam_common_module_flutter.dart';and not src/ or other subdirectories. - Need to use minimal Dart SDK version 3.0.0
- Need to use minimal Flutter version 3.10.0
Des de la OSAM es proporcionen mòduls per realitzar un conjunt de tasques comunes a totes les apps publicades per l'Ajuntament de Barcelona. El mòdul comú (Flutter) està disponible com a repositori a Github
Useful links:
- Lògica de negoci
- Backend (json)
- Modul comú requirements catalá o espanyol
A partir de la versió 3.0.0 la llibreria es un wrapper de la desenvolupada en Kotlin Multiplatform
-
Afegeix aquesta dependència al pubspec:
osam_common_module_flutter: git: url: https://github.com/AjuntamentdeBarcelona/modul_comu_osam_flutter.git ref: '8.1.0'
En cas que les dependències de Firebase Analytics, Firebase Performance, Firebase Messaging i Firebase Crashlytics fallin, cal afegir aquestes aquesta configuració al pubspec:
dependency_overrides: firebase_crashlytics_platform_interface: 3.1.13 firebase_analytics_platform_interface: 3.0.5 firebase_performance_platform_interface: ^0.1.1+18 firebase_messaging_platform_interface: ^5.0.0
-
Actualitzar mitjançant el comandament 'flutter packages get' les dependències.
-
Afegir el import on sigui necessari:
import 'package:osam_common_module_flutter/osam_common_module_flutter.dart';
-
Per utilitzar la llibreria necessitem crear una instància de la clase OSAM, la qual es fa a través del mètode estàtic (i asíncron)
init().Tenim un example de inicialització on example/lib/di/di.dart
En el cas de l'app d'exemple, accedim a la instància creada a través de OsamRepository
En l'exemple anterior tenim la URL del mòdul comú hardcoded a la pròpia lògica. Però aquesta URL s'ha d'externalitzar com a variable de configuració, d'aquesta manera es pot generar la versió de producció només substituint el fitxer amb els valors correctes.
Per fer-ho només cal crear el fitxer ".env" a l'arrel del projecte de Flutter i carregar aquest fitxer amb el plugin flutter_dotenv. En aquesta URL hi ha la documentació de com afegir aquest fitxer i com carregar les dades al codi
El fitxer ".env" ha de contenir la URL del mòdul comú en la variable "COMMON_MODULE_URL". Quedaria de la següent manera:
COMMON_MODULE_URL=https://dev-osam-modul-comu.dtibcn.cat/S'ha d'utilitzar, com a mínim, la versió 1.9.0 de Kotlin.
L'atribut compileSdkVersion del fitxer build.gradle de l'aplicació d'Android ha de tenir el valor
31 o superior.
Si la versió mínima de Android a la que es dona suport (minSdkVersion) a l'aplicació d'Android es inferior a 21, serà necessari habilitar multidex, ja que, si no, apareixerà un error al compilar.
Si volem que els pop-ups es vegin amb l'estil correcte, haurem d'utilitzar un estil que extengui d' AppCompat. A l'aplicació de Android que crea Flutter s'hauria de modificar els fitxers styles.xml
En el Podfile del projecte d'iOS creat por Flutter haurem d'incloure el pod del mòdul comú de Kotlin Multiplatform Mobile. Això es fa incloent la següent linea:
pod 'OSAMCommon', :git => 'https://github.com/AjuntamentdeBarcelona/modul_comu_osam.git', :tag => '2.2.3'El Podfile quedaria de la següent manera
Per crear el missatge d'alerta, únicament hem de cridar a la funció que descarregarà el json amb les variables ja definides i mostrarà l'alerta segons els valors rebuts. Exemple:
void _onVersionControl() async {
final result = await DI.osamSdk.versionControl(
language: Language.CA,
);
switch (result) {
case VersionControlResponse.ACCEPTED:
break;
case VersionControlResponse.DISMISSED:
break;
case VersionControlResponse.CANCELLED:
break;
case VersionControlResponse.ERROR:
break;
}
}No és necessari capturar la resposta si no es necessita realitzar cap acció adicional, ja que el mòdul comú s'encarregarà de mostrar el popup si es compleixen els requeriments per a que es mostri
Si és necessari executar el control de versions cada vegada que l'app torna a primer pla, a l'app demo hem implementat aquesta funcionalitat en un mixin anomenat OsamVersionChecker:
class _MyHomePageState extends State<MyHomePage> with OsamVersionChecker {Hem utilitzat el package flutter_fgbg:
mixin OsamVersionChecker<T extends StatefulWidget> on State<T> implements RouteAware {
StreamSubscription<FGBGType> subscription;
@override
void initState() {
super.initState();
subscription = FGBGEvents.stream.listen((event) async {
if (event.toString() == "FGBGType.foreground") {
await DI.osamRepository.checkForUpdates(context);
}
});
}
}Per crear el missatge d'alerta, únicament hem de cridar a la funció que descarregarà el json amb les variables ja definides i mostrarà l'alerta segons els valors rebuts. Exemple:
void _onRating() async {
final result = await DI.osamSdk.rating(
language: Language.EN,
);
switch (result) {
case RatingControlResponse.ACCEPTED:
break;
case RatingControlResponse.DISMISSED:
break;
case RatingControlResponse.CANCELLED:
break;
}
}No és necessari capturar la resposta si no es necessita realitzar cap acció adicional, ja que el mòdul comú s'encarregarà de mostrar el popup si es compleixen els requeriments per a que es mostri
Per obtenir la informació del dispositiu i de l'aplicació Exemple:
void _onDeviceInformation(BuildContext context) async {
final result = await DI.osamRepository.deviceInformation();
_showToast(context, "${result.platformName}");
_showToast(context, "${result.platformVersion}");
_showToast(context, "${result.platformModel}");
}
void _onAppInformation(BuildContext context) async {
final result = await DI.osamRepository.appInformation();
_showToast(context, "${result.appName}");
_showToast(context, "${result.appVersionName}");
_showToast(context, "${result.appVersionCode}");
}Aquesta funció orquestra tota la lògica associada al canvi d'idioma de l'aplicació. En ser invocada, actualitza les preferències locals desant tant l'idioma nou com l'anterior, registra un esdeveniment language_change a Firebase Analytics amb els detalls del canvi, i actualitza la subscripció als topics de notificacions de Firebase Cloud Messaging per garantir que l'usuari rebi les comunicacions en l'idioma seleccionat.
Exemple:
void _onChangeLanguageEvent(BuildContext context) async {
final result = await DI.osamRepository.changeLanguageEvent();
if (context.mounted) {
switch (result) {
case AppLanguageResponse.SUCCESS:
_showToast(context, AppLanguageResponse.SENT.name);
break;
case LanguageInformationResponse.UNCHANGED:
_showToast(context, AppLanguageResponse.NOT_SENT.name);
break;
case LanguageInformationResponse.ERROR:
_showToast(context, AppLanguageResponse.ERROR.name);
break;
}
}
}Aquesta funció, que s'ha de cridar en iniciar l'aplicació, gestiona la subscripció inicial o l'actualització dels topics de notificacions per assegurar que el dispositiu estigui subscrit al canal correcte de Firebase Cloud Messaging. El procés recupera l'últim topic registrat, construeix el nou basant-se en la versió de l'app i l'idioma del dispositiu, actualitza la subscripció a Firebase donant de baixa l'antic i registrant el nou, i finalment desa localment la informació de la nova versió per a futures execucions.
void _onFirstTimeOrUpdateEvent(BuildContext context) async {
final result = await DI.osamRepository.firstTimeOrUpdateEvent();
if (context.mounted) {
switch (result) {
case AppLanguageResponse.SUCCESS:
_showToast(context, AppLanguageResponse.SUCCESS.name);
break;
case LanguageInformationResponse.UNCHANGED:
_showToast(context, AppLanguageResponse.UNCHANGED.name);
break;
case LanguageInformationResponse.ERROR:
_showToast(context, AppLanguageResponse.ERROR.name);
break;
}
}
}Aquesta funció permet subscriure l'aplicació a un topic de notificacions de Firebase amb un nom específic i personalitzat.
És útil per a campanyes de màrqueting o per segmentar usuaris en grups que no depenen de la versió de l'app o de l'idioma. La funció s'encarrega de gestionar la comunicació amb Firebase per realitzar la subscripció de manera asíncrona.
void _onSubscribeToCustomTopic(BuildContext context, String topic) async {
final result = await DI.osamRepository.subscribeToCustomTopic(topic: topic);
if (context.mounted) {
switch (result) {
case AppLanguageResponse.ACCEPTED:
_showToast(context, AppLanguageResponse.ACCEPTED.name);
break;
case LanguageInformationResponse.ERROR:
_showToast(context, AppLanguageResponse.ERROR.name);
break;
}
}
}Aquesta funció permet desubscriure l'aplicació d'un topic de notificacions de Firebase amb un nom específic i personalitzat.
És l'operació inversa a subscribeToCustomTopic i és útil per aturar la recepció de notificacions d'una campanya concreta o per netejar subscripcions quan ja no són necessàries. La funció s'encarrega de gestionar la comunicació amb Firebase per realitzar la desubscripció de manera asíncrona.
void _onUnsubscribeToCustomTopic(BuildContext context, String topic) async {
final result = await DI.osamRepository.unsubscribeToCustomTopic(topic: topic);
if (context.mounted) {
switch (result) {
case AppLanguageResponse.ACCEPTED:
_showToast(context, AppLanguageResponse.ACCEPTED.name);
break;
case LanguageInformationResponse.ERROR:
_showToast(context, AppLanguageResponse.ERROR.name);
break;
}
}
}Aquesta funció permet obtenir el token de registre de Firebase Cloud Messaging (FCM) del dispositiu. Aquest token és un identificador únic que s'utilitza per enviar notificacions push directament a un dispositiu específic. L'operació es realitza de manera asíncrona.
void _onGetFCMToken(BuildContext context) async {
final result = await DI.osamRepository.getFCMToken();
if (context.mounted) {
switch (result) {
case Success(token: final token):
_showToast(context, 'SUCCESS: $token');
case Error(error: final error):
_showToast(context, 'ERROR: ${error.toString()}');
}
}
}Perquè aquesta funció s’executi correctament, és necessari inicialitzar la lògica del MessagingEvent. Pots veure’n un exemple a example.lib.di.di.dart, tal com es mostra a continuació:
static _onMessagingEvent(String topic, String action) async {
switch (action) {
case 'subscribe':
await FirebaseMessaging.instance.subscribeToTopic(topic);
break;
case 'unsubscribe':
await FirebaseMessaging.instance.unsubscribeFromTopic(topic);
break;
case 'getToken':
cacheTokenForNative();
break;
default:
debugPrint("MessagingEvent error: Unknown action $action");
}
}
static Future<void> cacheTokenForNative() async {
String? token = await FirebaseMessaging.instance.getToken();
if (token != null) {
await _prefs.setString('fcm_token', token);
}Hi ha una app demo en aquest mòdul flutter amb moltes funcionalitats disponibles que poden ajudar a entendre com funciona el mòdul comú i veure quines accions es duen a terme i com.