push notifications

This commit is contained in:
2026-08-15 12:00:28 +03:00
parent ab36215b7a
commit 3caa3e676e
14 changed files with 526 additions and 6 deletions
+10
View File
@@ -3,6 +3,8 @@ plugins {
id("kotlin-android") id("kotlin-android")
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id("dev.flutter.flutter-gradle-plugin") id("dev.flutter.flutter-gradle-plugin")
// Firebase Cloud Messaging: legge android/app/google-services.json.
id("com.google.gms.google-services")
} }
android { android {
@@ -11,6 +13,9 @@ android {
ndkVersion = flutter.ndkVersion ndkVersion = flutter.ndkVersion
compileOptions { compileOptions {
// Richiesto da flutter_local_notifications (notifiche mostrate quando
// l'app e' aperta).
isCoreLibraryDesugaringEnabled = true
sourceCompatibility = JavaVersion.VERSION_17 sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17
} }
@@ -42,3 +47,8 @@ android {
flutter { flutter {
source = "../.." source = "../.."
} }
dependencies {
// Libreria di supporto richiesta dal desugaring (flutter_local_notifications).
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4")
}
@@ -4,4 +4,9 @@
to allow setting breakpoints, to provide hot reload, etc. to allow setting breakpoints, to provide hot reload, etc.
--> -->
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<!-- Solo per lo sviluppo: il backend locale (Docker) risponde in HTTP,
e da Android 9 il traffico in chiaro e' bloccato di default.
Questo file vale solo per la build di debug: la release resta in HTTPS. -->
<application android:usesCleartextTraffic="true" />
</manifest> </manifest>
+4
View File
@@ -1,4 +1,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Notifiche push: da Android 13 (API 33) il permesso va chiesto a runtime.
Lo fa PushService.registerAfterLogin() dopo il login. -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<application <application
android:label="yogibook_app" android:label="yogibook_app"
android:name="${applicationName}" android:name="${applicationName}"
+2
View File
@@ -21,6 +21,8 @@ plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0" id("dev.flutter.flutter-plugin-loader") version "1.0.0"
id("com.android.application") version "8.11.1" apply false id("com.android.application") version "8.11.1" apply false
id("org.jetbrains.kotlin.android") version "2.2.20" apply false id("org.jetbrains.kotlin.android") version "2.2.20" apply false
// Necessario per Firebase (legge android/app/google-services.json).
id("com.google.gms.google-services") version "4.4.2" apply false
} }
include(":app") include(":app")
+4
View File
@@ -4,11 +4,15 @@ import 'package:intl/date_symbol_data_local.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'screens/login_page.dart'; import 'screens/login_page.dart';
import 'services/push_service.dart';
import 'state/app_state.dart'; import 'state/app_state.dart';
Future<void> main() async { Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
await initializeDateFormatting('it_IT'); await initializeDateFormatting('it_IT');
await PushService.initFirebase();
await PushService.enableForegroundNotifications();
runApp( runApp(
ChangeNotifierProvider(create: (_) => AppState(), child: const MyApp()), ChangeNotifierProvider(create: (_) => AppState(), child: const MyApp()),
); );
+86
View File
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import '../models/school.dart'; import '../models/school.dart';
import '../services/push_api.dart';
import '../services/vanguard_api.dart'; import '../services/vanguard_api.dart';
import '../widgets/yogibook_background.dart'; import '../widgets/yogibook_background.dart';
@@ -41,12 +42,54 @@ class _AccountPageState extends State<AccountPage> {
bool _obscurePw = true; bool _obscurePw = true;
bool _obscurePw2 = true; bool _obscurePw2 = true;
bool? _pushEnabled;
bool _savingPush = false;
final _picker = ImagePicker(); final _picker = ImagePicker();
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_loadProfile(); _loadProfile();
_loadPushPreference();
}
Future<void> _loadPushPreference() async {
try {
final attive = await PushApi.fetchPreference(token: widget.token);
if (!mounted) return;
setState(() => _pushEnabled = attive);
} catch (_) {
if (!mounted) return;
setState(() => _pushEnabled = null);
}
}
Future<void> _togglePush(bool valore) async {
final precedente = _pushEnabled;
setState(() {
_pushEnabled = valore;
_savingPush = true;
});
try {
final salvato = await PushApi.updatePreference(
token: widget.token,
enabled: valore,
);
if (!mounted) return;
setState(() => _pushEnabled = salvato);
_snack(
salvato ? 'Notifiche attivate.' : 'Notifiche disattivate.',
);
} catch (e) {
if (!mounted) return;
setState(() => _pushEnabled = precedente);
_snack('Errore nel salvataggio: $e');
} finally {
if (mounted) setState(() => _savingPush = false);
}
} }
@override @override
@@ -252,6 +295,8 @@ class _AccountPageState extends State<AccountPage> {
const SizedBox(height: 20), const SizedBox(height: 20),
_profileCard(), _profileCard(),
const SizedBox(height: 16), const SizedBox(height: 16),
_notificationsCard(),
const SizedBox(height: 16),
_passwordCard(), _passwordCard(),
const SizedBox(height: 8), const SizedBox(height: 8),
], ],
@@ -409,6 +454,47 @@ class _AccountPageState extends State<AccountPage> {
); );
} }
Widget _notificationsCard() {
if (_pushEnabled == null) {
return _card(
title: 'Notifiche',
children: const [
Row(
children: [
SizedBox(
width: 18,
height: 18,
child: CircularProgressIndicator(strokeWidth: 2),
),
SizedBox(width: 12),
Expanded(child: Text('Carico le impostazioni...')),
],
),
],
);
}
return _card(
title: 'Notifiche',
children: [
SwitchListTile(
contentPadding: EdgeInsets.zero,
activeThumbColor: kGreen,
value: _pushEnabled!,
onChanged: _savingPush ? null : _togglePush,
title: const Text(
'Notifiche push',
style: TextStyle(fontWeight: FontWeight.w700),
),
subtitle: const Text(
'Promemoria delle lezioni del giorno, scadenza abbonamento e '
'certificato medico.',
),
),
],
);
}
Widget _passwordCard() { Widget _passwordCard() {
return _card( return _card(
title: 'Cambia password', title: 'Cambia password',
+5
View File
@@ -1,4 +1,7 @@
import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../services/push_service.dart';
import '../services/vanguard_api.dart'; import '../services/vanguard_api.dart';
import '../models/school.dart'; import '../models/school.dart';
import 'home_page.dart'; import 'home_page.dart';
@@ -47,6 +50,8 @@ class _LoginPageState extends State<LoginPage> {
password: passwordController.text.trim(), password: passwordController.text.trim(),
); );
unawaited(PushService.registerAfterLogin(token));
if (!mounted) return; if (!mounted) return;
// Bypass SelectSchoolPage: scuola unica, si va dritti alla Home. // Bypass SelectSchoolPage: scuola unica, si va dritti alla Home.
+92
View File
@@ -0,0 +1,92 @@
import 'dart:convert';
import 'package:http/http.dart' as http;
import '../config/api_config.dart';
class PushApi {
static Map<String, String> _headers(String token) => {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer $token',
};
static Future<String> registerDevice({
required String token,
required String deviceToken,
required String platform,
String? appVersion,
}) async {
final uri = Uri.parse('${ApiConfig.laravelApiBase}/register_device.php');
final res = await http.post(
uri,
headers: _headers(token),
body: jsonEncode({
'device_token': deviceToken,
'platform': platform,
if (appVersion != null) 'app_version': appVersion,
}),
);
final data = _decode(res.body, res.statusCode);
return (data['push_enabled'] ?? 'Y').toString();
}
static Future<void> unregisterDevice({
required String token,
required String deviceToken,
}) async {
final uri = Uri.parse('${ApiConfig.laravelApiBase}/register_device.php');
final res = await http.delete(
uri,
headers: _headers(token),
body: jsonEncode({'device_token': deviceToken}),
);
_decode(res.body, res.statusCode);
}
static Future<bool> fetchPreference({required String token}) async {
final uri = Uri.parse('${ApiConfig.laravelApiBase}/push_preference.php');
final res = await http.get(uri, headers: _headers(token));
final data = _decode(res.body, res.statusCode);
return (data['push_enabled'] ?? 'Y').toString().toUpperCase() == 'Y';
}
static Future<bool> updatePreference({
required String token,
required bool enabled,
}) async {
final uri = Uri.parse('${ApiConfig.laravelApiBase}/push_preference.php');
final res = await http.post(
uri,
headers: _headers(token),
body: jsonEncode({'enabled': enabled}),
);
final data = _decode(res.body, res.statusCode);
return (data['push_enabled'] ?? 'Y').toString().toUpperCase() == 'Y';
}
static Map<String, dynamic> _decode(String body, int statusCode) {
Map<String, dynamic> data;
try {
data = jsonDecode(body) as Map<String, dynamic>;
} catch (_) {
throw Exception('Risposta non valida ($statusCode): $body');
}
if (statusCode != 200 || data['success'] != true) {
throw Exception(data['error'] ?? data['message'] ?? 'Errore notifiche');
}
return data;
}
}
+162
View File
@@ -0,0 +1,162 @@
import 'dart:io' show Platform;
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'push_api.dart';
class PushService {
static String? _deviceToken;
static bool _firebaseReady = false;
static final FlutterLocalNotificationsPlugin _locali =
FlutterLocalNotificationsPlugin();
static const AndroidNotificationChannel _canale = AndroidNotificationChannel(
'yogibook_notifiche',
'Notifiche YogiBook',
description: 'Promemoria delle lezioni, scadenze abbonamento e certificato',
importance: Importance.high,
);
static Future<void> initFirebase() async {
if (_firebaseReady) return;
try {
await Firebase.initializeApp();
FirebaseMessaging.onBackgroundMessage(_backgroundHandler);
await _preparaNotificheLocali();
_firebaseReady = true;
} catch (e) {
debugPrint('Firebase non inizializzato: $e');
}
}
static Future<void> _preparaNotificheLocali() async {
const impostazioni = InitializationSettings(
android: AndroidInitializationSettings('@mipmap/ic_launcher'),
iOS: DarwinInitializationSettings(
requestAlertPermission: false,
requestBadgePermission: false,
requestSoundPermission: false,
),
);
await _locali.initialize(settings: impostazioni);
await _locali
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin
>()
?.createNotificationChannel(_canale);
FirebaseMessaging.onMessage.listen(_mostraInPrimoPiano);
}
static Future<void> _mostraInPrimoPiano(RemoteMessage messaggio) async {
if (kIsWeb || !Platform.isAndroid) return;
final notifica = messaggio.notification;
if (notifica == null) return;
await _locali.show(
id: notifica.hashCode,
title: notifica.title,
body: notifica.body,
notificationDetails: NotificationDetails(
android: AndroidNotificationDetails(
_canale.id,
_canale.name,
channelDescription: _canale.description,
importance: Importance.high,
priority: Priority.high,
icon: '@mipmap/ic_launcher',
),
),
);
}
static Future<void> registerAfterLogin(String authToken) async {
if (!_firebaseReady) return;
try {
final messaging = FirebaseMessaging.instance;
final settings = await messaging.requestPermission();
if (settings.authorizationStatus == AuthorizationStatus.denied) {
debugPrint('Permesso notifiche negato dall\'utente.');
return;
}
final deviceToken = await messaging.getToken();
if (deviceToken == null) return;
_deviceToken = deviceToken;
await PushApi.registerDevice(
token: authToken,
deviceToken: deviceToken,
platform: _platformName(),
);
messaging.onTokenRefresh.listen((nuovo) async {
_deviceToken = nuovo;
try {
await PushApi.registerDevice(
token: authToken,
deviceToken: nuovo,
platform: _platformName(),
);
} catch (e) {
debugPrint('Aggiornamento token fallito: $e');
}
});
} catch (e) {
debugPrint('Registrazione push fallita: $e');
}
}
static Future<void> unregisterOnLogout(String authToken) async {
final deviceToken = _deviceToken;
if (deviceToken == null) return;
try {
await PushApi.unregisterDevice(
token: authToken,
deviceToken: deviceToken,
);
_deviceToken = null;
} catch (e) {
debugPrint('Disattivazione dispositivo fallita: $e');
}
}
static Future<void> enableForegroundNotifications() async {
if (!_firebaseReady) return;
try {
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
} catch (e) {
debugPrint('Impostazione notifiche in foreground fallita: $e');
}
}
static String _platformName() {
if (kIsWeb) return 'web';
return Platform.isIOS ? 'ios' : 'android';
}
}
@pragma('vm:entry-point')
Future<void> _backgroundHandler(RemoteMessage message) async {
debugPrint('Notifica in background: ${message.messageId}');
}
@@ -8,6 +8,9 @@ import Foundation
import audioplayers_darwin import audioplayers_darwin
import file_picker import file_picker
import file_selector_macos import file_selector_macos
import firebase_core
import firebase_messaging
import flutter_local_notifications
import google_sign_in_ios import google_sign_in_ios
import path_provider_foundation import path_provider_foundation
import shared_preferences_foundation import shared_preferences_foundation
@@ -17,6 +20,9 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin"))
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin"))
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin")) FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
+142 -6
View File
@@ -1,6 +1,22 @@
# Generated by pub # Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile # See https://dart.dev/tools/pub/glossary#lockfile
packages: packages:
_flutterfire_internals:
dependency: transitive
description:
name: _flutterfire_internals
sha256: "6727cf2ced9b104abca9daa278380be2eca2b98ce33d4b46f11708e387dc6b4d"
url: "https://pub.dev"
source: hosted
version: "1.3.76"
args:
dependency: transitive
description:
name: args
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
url: "https://pub.dev"
source: hosted
version: "2.7.0"
async: async:
dependency: transitive dependency: transitive
description: description:
@@ -121,6 +137,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.8" version: "1.0.8"
dbus:
dependency: transitive
description:
name: dbus
sha256: "792974a4007974fbc5c1b5433eb2330a9db3e368c3f906253af4c007d0f49a91"
url: "https://pub.dev"
source: hosted
version: "0.7.13"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@@ -185,6 +209,54 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.9.3+5" version: "0.9.3+5"
firebase_core:
dependency: "direct main"
description:
name: firebase_core
sha256: "9478ca6700c02d315c6aba37e206e612317f98bb4f335bb1cbd6e0ce67dcf764"
url: "https://pub.dev"
source: hosted
version: "4.13.0"
firebase_core_platform_interface:
dependency: transitive
description:
name: firebase_core_platform_interface
sha256: e28f9afdcb5b0f0a8ea74ea3b322f5a7592c81cb45dd9d189913bdae08a2089a
url: "https://pub.dev"
source: hosted
version: "8.1.0"
firebase_core_web:
dependency: transitive
description:
name: firebase_core_web
sha256: f471a288b0101a45567548322ac4a5ad31e3ecbf87a576dcc0e424e6a11e04ea
url: "https://pub.dev"
source: hosted
version: "3.10.0"
firebase_messaging:
dependency: "direct main"
description:
name: firebase_messaging
sha256: "55cf1000dd72d229ebff3ce6a399bd35705a7675275478b31308afd90ac85751"
url: "https://pub.dev"
source: hosted
version: "16.5.0"
firebase_messaging_platform_interface:
dependency: transitive
description:
name: firebase_messaging_platform_interface
sha256: e5fbb62bd23a27c983825277877ac91fdfdb6bfb31c6e5399700963ae586e339
url: "https://pub.dev"
source: hosted
version: "4.9.3"
firebase_messaging_web:
dependency: transitive
description:
name: firebase_messaging_web
sha256: "663d320e90a41fe57d651ec79df2bc831bf29e051bc0c2cd41faf3106eb412d9"
url: "https://pub.dev"
source: hosted
version: "4.2.4"
fixnum: fixnum:
dependency: transitive dependency: transitive
description: description:
@@ -206,6 +278,46 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.0.0" version: "6.0.0"
flutter_local_notifications:
dependency: "direct main"
description:
name: flutter_local_notifications
sha256: "1447ba911c60f2ba3f25dae1af151ec187162566b0f57e37771bf0b400f013ad"
url: "https://pub.dev"
source: hosted
version: "22.3.0"
flutter_local_notifications_linux:
dependency: transitive
description:
name: flutter_local_notifications_linux
sha256: "9ca97e63776f29ab1b955725c09999fc2c150523269db150c39274f2a43c5a8b"
url: "https://pub.dev"
source: hosted
version: "8.0.1"
flutter_local_notifications_platform_interface:
dependency: transitive
description:
name: flutter_local_notifications_platform_interface
sha256: "43c3761d916c9bd3d5c7ebbc44d82f4990329840c0c5d62ad5260cc1b5d399bd"
url: "https://pub.dev"
source: hosted
version: "12.2.0"
flutter_local_notifications_web:
dependency: transitive
description:
name: flutter_local_notifications_web
sha256: "516afaf97a2d1e67a036c6617321b00d205d72f7a67b6eccf936cd565f985878"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
flutter_local_notifications_windows:
dependency: transitive
description:
name: flutter_local_notifications_windows
sha256: "6f43bdd03b171b7a90f22647506fea33e2bb12294b7c7c7a3d690e960a382945"
url: "https://pub.dev"
source: hosted
version: "3.1.1"
flutter_localizations: flutter_localizations:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@@ -493,6 +605,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.0" version: "2.3.0"
petitparser:
dependency: transitive
description:
name: petitparser
sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675"
url: "https://pub.dev"
source: hosted
version: "7.0.2"
platform: platform:
dependency: transitive dependency: transitive
description: description:
@@ -630,10 +750,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636" sha256: "2a122cbe059f8b610d3a5415f42e255b6c17b1f21eee1d960f31080237fb4f11"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.9" version: "0.7.12"
timezone:
dependency: transitive
description:
name: timezone
sha256: "981d1020d6ef8fe1e7b3de5054e5b25579ae7c403d7734adc508ffc47668e9cb"
url: "https://pub.dev"
source: hosted
version: "0.11.1"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
@@ -718,10 +846,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vector_math name: vector_math
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b sha256: f36f9f3be64c6198714492bb455c11056e33e2f85d9a0b676a48301e44fdcf47
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.0" version: "2.4.2"
vm_service: vm_service:
dependency: transitive dependency: transitive
description: description:
@@ -754,6 +882,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.0"
xml:
dependency: transitive
description:
name: xml
sha256: "67f0aff7be013d107995e9b75bf4e7f2c3ef2dfdb2c8e68024bba0a7fd5756a4"
url: "https://pub.dev"
source: hosted
version: "7.0.1"
sdks: sdks:
dart: ">=3.10.4 <4.0.0" dart: ">=3.11.0 <4.0.0"
flutter: ">=3.35.0" flutter: ">=3.38.1"
+3
View File
@@ -44,6 +44,9 @@ dependencies:
mime: ^2.0.0 mime: ^2.0.0
provider: ^6.1.5+1 provider: ^6.1.5+1
shared_preferences: ^2.2.3 shared_preferences: ^2.2.3
firebase_core: ^4.13.0
firebase_messaging: ^16.5.0
flutter_local_notifications: ^22.3.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
@@ -8,6 +8,7 @@
#include <audioplayers_windows/audioplayers_windows_plugin.h> #include <audioplayers_windows/audioplayers_windows_plugin.h>
#include <file_selector_windows/file_selector_windows.h> #include <file_selector_windows/file_selector_windows.h>
#include <firebase_core/firebase_core_plugin_c_api.h>
#include <url_launcher_windows/url_launcher_windows.h> #include <url_launcher_windows/url_launcher_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) { void RegisterPlugins(flutter::PluginRegistry* registry) {
@@ -15,6 +16,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin")); registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin"));
FileSelectorWindowsRegisterWithRegistrar( FileSelectorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FileSelectorWindows")); registry->GetRegistrarForPlugin("FileSelectorWindows"));
FirebaseCorePluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FirebaseCorePluginCApi"));
UrlLauncherWindowsRegisterWithRegistrar( UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows")); registry->GetRegistrarForPlugin("UrlLauncherWindows"));
} }
+2
View File
@@ -5,10 +5,12 @@
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
audioplayers_windows audioplayers_windows
file_selector_windows file_selector_windows
firebase_core
url_launcher_windows url_launcher_windows
) )
list(APPEND FLUTTER_FFI_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST
flutter_local_notifications_windows
) )
set(PLUGIN_BUNDLED_LIBRARIES) set(PLUGIN_BUNDLED_LIBRARIES)