feat: basic test web notifications using PWA
This commit is contained in:
parent
cedea7fbb0
commit
b2a4ffeb9b
@ -1 +1,2 @@
|
|||||||
|
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||||
#include "Generated.xcconfig"
|
#include "Generated.xcconfig"
|
||||||
|
|||||||
@ -1 +1,2 @@
|
|||||||
|
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||||
#include "Generated.xcconfig"
|
#include "Generated.xcconfig"
|
||||||
|
|||||||
43
ios/Podfile
Normal file
43
ios/Podfile
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# Uncomment this line to define a global platform for your project
|
||||||
|
# platform :ios, '12.0'
|
||||||
|
|
||||||
|
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||||
|
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||||
|
|
||||||
|
project 'Runner', {
|
||||||
|
'Debug' => :debug,
|
||||||
|
'Profile' => :release,
|
||||||
|
'Release' => :release,
|
||||||
|
}
|
||||||
|
|
||||||
|
def flutter_root
|
||||||
|
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
|
||||||
|
unless File.exist?(generated_xcode_build_settings_path)
|
||||||
|
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
|
||||||
|
end
|
||||||
|
|
||||||
|
File.foreach(generated_xcode_build_settings_path) do |line|
|
||||||
|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
|
||||||
|
return matches[1].strip if matches
|
||||||
|
end
|
||||||
|
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
|
||||||
|
end
|
||||||
|
|
||||||
|
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
|
||||||
|
|
||||||
|
flutter_ios_podfile_setup
|
||||||
|
|
||||||
|
target 'Runner' do
|
||||||
|
use_frameworks!
|
||||||
|
|
||||||
|
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
||||||
|
target 'RunnerTests' do
|
||||||
|
inherit! :search_paths
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
post_install do |installer|
|
||||||
|
installer.pods_project.targets.each do |target|
|
||||||
|
flutter_additional_ios_build_settings(target)
|
||||||
|
end
|
||||||
|
end
|
||||||
74
lib/firebase_options.dart
Normal file
74
lib/firebase_options.dart
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
|
||||||
|
import 'package:flutter/foundation.dart'
|
||||||
|
show defaultTargetPlatform, kIsWeb, TargetPlatform;
|
||||||
|
|
||||||
|
class DefaultFirebaseOptions {
|
||||||
|
static FirebaseOptions get currentPlatform {
|
||||||
|
if (kIsWeb) {
|
||||||
|
return web;
|
||||||
|
}
|
||||||
|
switch (defaultTargetPlatform) {
|
||||||
|
case TargetPlatform.android:
|
||||||
|
return android;
|
||||||
|
case TargetPlatform.iOS:
|
||||||
|
return ios;
|
||||||
|
case TargetPlatform.macOS:
|
||||||
|
return macos;
|
||||||
|
case TargetPlatform.windows:
|
||||||
|
return windows;
|
||||||
|
case TargetPlatform.linux:
|
||||||
|
throw UnsupportedError(
|
||||||
|
'DefaultFirebaseOptions have not been configured for linux - '
|
||||||
|
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
throw UnsupportedError(
|
||||||
|
'DefaultFirebaseOptions are not supported for this platform.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const FirebaseOptions web = FirebaseOptions(
|
||||||
|
apiKey: 'AIzaSyB5C-HmErqNFRlJwM4S4wfs-arMkJRVmGA',
|
||||||
|
appId: '1:865533380916:web:46725564ea0e1d4e70fd61',
|
||||||
|
messagingSenderId: '865533380916',
|
||||||
|
projectId: 'wesalapp-bc676',
|
||||||
|
authDomain: 'wesalapp-bc676.firebaseapp.com',
|
||||||
|
storageBucket: 'wesalapp-bc676.firebasestorage.app',
|
||||||
|
measurementId: 'G-V4BQJQB24E',
|
||||||
|
);
|
||||||
|
|
||||||
|
static const FirebaseOptions android = FirebaseOptions(
|
||||||
|
apiKey: 'AIzaSyB5C-HmErqNFRlJwM4S4wfs-arMkJRVmGA',
|
||||||
|
appId: '1:865533380916:android:46725564ea0e1d4e70fd61',
|
||||||
|
messagingSenderId: '865533380916',
|
||||||
|
projectId: 'wesalapp-bc676',
|
||||||
|
storageBucket: 'wesalapp-bc676.firebasestorage.app',
|
||||||
|
);
|
||||||
|
|
||||||
|
static const FirebaseOptions ios = FirebaseOptions(
|
||||||
|
apiKey: 'AIzaSyB5C-HmErqNFRlJwM4S4wfs-arMkJRVmGA',
|
||||||
|
appId: '1:865533380916:ios:46725564ea0e1d4e70fd61',
|
||||||
|
messagingSenderId: '865533380916',
|
||||||
|
projectId: 'wesalapp-bc676',
|
||||||
|
storageBucket: 'wesalapp-bc676.firebasestorage.app',
|
||||||
|
iosBundleId: 'com.example.wesalApp',
|
||||||
|
);
|
||||||
|
|
||||||
|
static const FirebaseOptions macos = FirebaseOptions(
|
||||||
|
apiKey: 'AIzaSyB5C-HmErqNFRlJwM4S4wfs-arMkJRVmGA',
|
||||||
|
appId: '1:865533380916:macos:46725564ea0e1d4e70fd61',
|
||||||
|
messagingSenderId: '865533380916',
|
||||||
|
projectId: 'wesalapp-bc676',
|
||||||
|
storageBucket: 'wesalapp-bc676.firebasestorage.app',
|
||||||
|
iosBundleId: 'com.example.wesalApp',
|
||||||
|
);
|
||||||
|
|
||||||
|
static const FirebaseOptions windows = FirebaseOptions(
|
||||||
|
apiKey: 'AIzaSyB5C-HmErqNFRlJwM4S4wfs-arMkJRVmGA',
|
||||||
|
appId: '1:865533380916:windows:46725564ea0e1d4e70fd61',
|
||||||
|
messagingSenderId: '865533380916',
|
||||||
|
projectId: 'wesalapp-bc676',
|
||||||
|
storageBucket: 'wesalapp-bc676.firebasestorage.app',
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,7 +1,17 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:firebase_core/firebase_core.dart';
|
||||||
|
import 'firebase_options.dart';
|
||||||
import 'screens/home_screen.dart';
|
import 'screens/home_screen.dart';
|
||||||
|
import 'services/notification_service.dart';
|
||||||
|
|
||||||
void main() {
|
void main() async {
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
await Firebase.initializeApp(
|
||||||
|
options: DefaultFirebaseOptions.currentPlatform,
|
||||||
|
);
|
||||||
|
|
||||||
|
await NotificationService().initialize();
|
||||||
|
|
||||||
runApp(MyApp());
|
runApp(MyApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import '../../services/notification_service.dart';
|
||||||
|
|
||||||
class FeedPage extends StatefulWidget {
|
class FeedPage extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
@ -105,6 +106,17 @@ class _FeedPageState extends State<FeedPage> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
floatingActionButton: FloatingActionButton(
|
||||||
|
onPressed: () async {
|
||||||
|
final token = await NotificationService().getToken();
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text('FCM Token: ${token ?? "Not available"}')),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
backgroundColor: Color(0xFF6A4C93),
|
||||||
|
child: Icon(Icons.notifications, color: Colors.white),
|
||||||
|
tooltip: 'Show FCM Token',
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
163
lib/services/notification_service.dart
Normal file
163
lib/services/notification_service.dart
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
|
class NotificationService {
|
||||||
|
static final NotificationService _instance = NotificationService._internal();
|
||||||
|
factory NotificationService() => _instance;
|
||||||
|
NotificationService._internal();
|
||||||
|
|
||||||
|
FirebaseMessaging? _messaging;
|
||||||
|
|
||||||
|
static const String vapidKey = 'BKrFSFm2cb2DNtEpTNmEy3acpi2ziRA5DhzKSyjshqAWANaoydztUTa0Cn3jwh1v7KN6pHUQfsODFXUWrKG6aSU';
|
||||||
|
|
||||||
|
static const List<String> topics = [
|
||||||
|
'all',
|
||||||
|
'newposts',
|
||||||
|
'newinvites',
|
||||||
|
'invitesfollowup',
|
||||||
|
'appnews',
|
||||||
|
];
|
||||||
|
|
||||||
|
Future<void> initialize() async {
|
||||||
|
if (!kIsWeb) {
|
||||||
|
print('Notifications are only supported on web platform');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_messaging = FirebaseMessaging.instance;
|
||||||
|
|
||||||
|
await _requestPermission();
|
||||||
|
await _subscribeToTopics();
|
||||||
|
await _setupMessageHandlers();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _requestPermission() async {
|
||||||
|
if (_messaging == null) return;
|
||||||
|
|
||||||
|
NotificationSettings settings = await _messaging!.requestPermission(
|
||||||
|
alert: true,
|
||||||
|
announcement: false,
|
||||||
|
badge: true,
|
||||||
|
carPlay: false,
|
||||||
|
criticalAlert: false,
|
||||||
|
provisional: false,
|
||||||
|
sound: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
print('User granted permission: ${settings.authorizationStatus}');
|
||||||
|
|
||||||
|
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
|
||||||
|
print('User granted permission for notifications');
|
||||||
|
} else if (settings.authorizationStatus == AuthorizationStatus.provisional) {
|
||||||
|
print('User granted provisional permission for notifications');
|
||||||
|
} else {
|
||||||
|
print('User declined or has not accepted permission for notifications');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _subscribeToTopics() async {
|
||||||
|
if (_messaging == null) return;
|
||||||
|
|
||||||
|
for (String topic in topics) {
|
||||||
|
try {
|
||||||
|
await _messaging!.subscribeToTopic(topic);
|
||||||
|
print('Subscribed to topic: $topic');
|
||||||
|
} catch (e) {
|
||||||
|
print('Error subscribing to topic $topic: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _setupMessageHandlers() async {
|
||||||
|
if (_messaging == null) return;
|
||||||
|
|
||||||
|
// Handle foreground messages
|
||||||
|
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
|
||||||
|
print('Got a message whilst in the foreground!');
|
||||||
|
print('Message data: ${message.data}');
|
||||||
|
|
||||||
|
if (message.notification != null) {
|
||||||
|
print('Message also contained a notification: ${message.notification}');
|
||||||
|
_showNotification(message.notification!);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle background messages
|
||||||
|
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
|
||||||
|
|
||||||
|
// Handle notification taps
|
||||||
|
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
|
||||||
|
print('A new onMessageOpenedApp event was published!');
|
||||||
|
print('Message data: ${message.data}');
|
||||||
|
_handleNotificationTap(message);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get the initial message if the app was opened from a notification
|
||||||
|
RemoteMessage? initialMessage = await _messaging!.getInitialMessage();
|
||||||
|
if (initialMessage != null) {
|
||||||
|
print('App opened from notification: ${initialMessage.data}');
|
||||||
|
_handleNotificationTap(initialMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the FCM token for this device
|
||||||
|
String? token = await _messaging!.getToken(vapidKey: vapidKey);
|
||||||
|
print('FCM Token: $token');
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showNotification(RemoteNotification notification) {
|
||||||
|
// For web, we rely on the service worker to show notifications
|
||||||
|
// This is mainly for logging and debugging
|
||||||
|
print('Notification Title: ${notification.title}');
|
||||||
|
print('Notification Body: ${notification.body}');
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleNotificationTap(RemoteMessage message) {
|
||||||
|
// Handle notification tap actions here
|
||||||
|
print('Notification tapped: ${message.data}');
|
||||||
|
|
||||||
|
// You can navigate to specific screens based on the notification data
|
||||||
|
// For example:
|
||||||
|
// if (message.data['type'] == 'newpost') {
|
||||||
|
// // Navigate to posts screen
|
||||||
|
// } else if (message.data['type'] == 'newinvite') {
|
||||||
|
// // Navigate to invitations screen
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> unsubscribeFromTopic(String topic) async {
|
||||||
|
if (_messaging == null) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await _messaging!.unsubscribeFromTopic(topic);
|
||||||
|
print('Unsubscribed from topic: $topic');
|
||||||
|
} catch (e) {
|
||||||
|
print('Error unsubscribing from topic $topic: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> subscribeToTopic(String topic) async {
|
||||||
|
if (_messaging == null) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await _messaging!.subscribeToTopic(topic);
|
||||||
|
print('Subscribed to topic: $topic');
|
||||||
|
} catch (e) {
|
||||||
|
print('Error subscribing to topic $topic: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String?> getToken() async {
|
||||||
|
if (_messaging == null) return null;
|
||||||
|
return await _messaging!.getToken(vapidKey: vapidKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Background message handler must be a top-level function
|
||||||
|
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
||||||
|
print('Handling a background message: ${message.messageId}');
|
||||||
|
print('Message data: ${message.data}');
|
||||||
|
|
||||||
|
if (message.notification != null) {
|
||||||
|
print('Background message contained a notification: ${message.notification}');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1 +1,2 @@
|
|||||||
|
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||||
#include "ephemeral/Flutter-Generated.xcconfig"
|
#include "ephemeral/Flutter-Generated.xcconfig"
|
||||||
|
|||||||
@ -1 +1,2 @@
|
|||||||
|
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||||
#include "ephemeral/Flutter-Generated.xcconfig"
|
#include "ephemeral/Flutter-Generated.xcconfig"
|
||||||
|
|||||||
@ -5,6 +5,10 @@
|
|||||||
import FlutterMacOS
|
import FlutterMacOS
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
import firebase_core
|
||||||
|
import firebase_messaging
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
|
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
|
||||||
|
FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin"))
|
||||||
}
|
}
|
||||||
|
|||||||
42
macos/Podfile
Normal file
42
macos/Podfile
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
platform :osx, '10.14'
|
||||||
|
|
||||||
|
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||||
|
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||||
|
|
||||||
|
project 'Runner', {
|
||||||
|
'Debug' => :debug,
|
||||||
|
'Profile' => :release,
|
||||||
|
'Release' => :release,
|
||||||
|
}
|
||||||
|
|
||||||
|
def flutter_root
|
||||||
|
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
|
||||||
|
unless File.exist?(generated_xcode_build_settings_path)
|
||||||
|
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
|
||||||
|
end
|
||||||
|
|
||||||
|
File.foreach(generated_xcode_build_settings_path) do |line|
|
||||||
|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
|
||||||
|
return matches[1].strip if matches
|
||||||
|
end
|
||||||
|
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
|
||||||
|
end
|
||||||
|
|
||||||
|
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
|
||||||
|
|
||||||
|
flutter_macos_podfile_setup
|
||||||
|
|
||||||
|
target 'Runner' do
|
||||||
|
use_frameworks!
|
||||||
|
|
||||||
|
flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
|
||||||
|
target 'RunnerTests' do
|
||||||
|
inherit! :search_paths
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
post_install do |installer|
|
||||||
|
installer.pods_project.targets.each do |target|
|
||||||
|
flutter_additional_macos_build_settings(target)
|
||||||
|
end
|
||||||
|
end
|
||||||
79
pubspec.lock
79
pubspec.lock
@ -1,6 +1,14 @@
|
|||||||
# 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: a5788040810bd84400bc209913fbc40f388cded7cdf95ee2f5d2bff7e38d5241
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.58"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -57,6 +65,54 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.3"
|
version: "1.3.3"
|
||||||
|
firebase_core:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: firebase_core
|
||||||
|
sha256: c6e8a6bf883d8ddd0dec39be90872daca65beaa6f4cff0051ed3b16c56b82e9f
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.15.1"
|
||||||
|
firebase_core_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: firebase_core_platform_interface
|
||||||
|
sha256: "5dbc900677dcbe5873d22ad7fbd64b047750124f1f9b7ebe2a33b9ddccc838eb"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.0.0"
|
||||||
|
firebase_core_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: firebase_core_web
|
||||||
|
sha256: "0ed0dc292e8f9ac50992e2394e9d336a0275b6ae400d64163fdf0a8a8b556c37"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.24.1"
|
||||||
|
firebase_messaging:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: firebase_messaging
|
||||||
|
sha256: "0f3363f97672eb9f65609fa00ed2f62cc8ec93e7e2d4def99726f9165d3d8a73"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "15.2.9"
|
||||||
|
firebase_messaging_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: firebase_messaging_platform_interface
|
||||||
|
sha256: "7a05ef119a14c5f6a9440d1e0223bcba20c8daf555450e119c4c477bf2c3baa9"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.6.9"
|
||||||
|
firebase_messaging_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: firebase_messaging_web
|
||||||
|
sha256: a4547f76da2a905190f899eb4d0150e1d0fd52206fce469d9f05ae15bb68b2c5
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.10.9"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -75,6 +131,11 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_web_plugins:
|
||||||
|
dependency: transitive
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
leak_tracker:
|
leak_tracker:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -139,6 +200,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.9.1"
|
||||||
|
plugin_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: plugin_platform_interface
|
||||||
|
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.8"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -208,6 +277,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "15.0.0"
|
version: "15.0.0"
|
||||||
|
web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web
|
||||||
|
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.8.1 <4.0.0"
|
dart: ">=3.8.1 <4.0.0"
|
||||||
flutter: ">=3.18.0-18.0.pre.54"
|
flutter: ">=3.22.0"
|
||||||
|
|||||||
@ -10,6 +10,8 @@ dependencies:
|
|||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
cupertino_icons: ^1.0.8
|
cupertino_icons: ^1.0.8
|
||||||
|
firebase_core: ^3.15.1
|
||||||
|
firebase_messaging: ^15.2.9
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
109
web/firebase-messaging-sw.js
Normal file
109
web/firebase-messaging-sw.js
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
importScripts('https://www.gstatic.com/firebasejs/9.19.1/firebase-app-compat.js');
|
||||||
|
importScripts('https://www.gstatic.com/firebasejs/9.19.1/firebase-messaging-compat.js');
|
||||||
|
|
||||||
|
// Firebase configuration
|
||||||
|
const firebaseConfig = {
|
||||||
|
apiKey: "AIzaSyB5C-HmErqNFRlJwM4S4wfs-arMkJRVmGA",
|
||||||
|
authDomain: "wesalapp-bc676.firebaseapp.com",
|
||||||
|
projectId: "wesalapp-bc676",
|
||||||
|
storageBucket: "wesalapp-bc676.firebasestorage.app",
|
||||||
|
messagingSenderId: "865533380916",
|
||||||
|
appId: "1:865533380916:web:46725564ea0e1d4e70fd61",
|
||||||
|
measurementId: "G-V4BQJQB24E"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialize Firebase
|
||||||
|
firebase.initializeApp(firebaseConfig);
|
||||||
|
|
||||||
|
// Initialize Firebase Messaging
|
||||||
|
const messaging = firebase.messaging();
|
||||||
|
|
||||||
|
// Handle background messages
|
||||||
|
messaging.onBackgroundMessage((payload) => {
|
||||||
|
console.log('Received background message ', payload);
|
||||||
|
|
||||||
|
const notificationTitle = payload.notification?.title || 'Wesal App';
|
||||||
|
const notificationOptions = {
|
||||||
|
body: payload.notification?.body || 'You have a new notification',
|
||||||
|
icon: '/icons/Icon-192.png',
|
||||||
|
badge: '/icons/Icon-192.png',
|
||||||
|
data: payload.data,
|
||||||
|
tag: payload.data?.type || 'general',
|
||||||
|
requireInteraction: true,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
action: 'open',
|
||||||
|
title: 'Open App',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'close',
|
||||||
|
title: 'Close',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
return self.registration.showNotification(notificationTitle, notificationOptions);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle notification clicks
|
||||||
|
self.addEventListener('notificationclick', (event) => {
|
||||||
|
console.log('Notification clicked:', event);
|
||||||
|
|
||||||
|
event.notification.close();
|
||||||
|
|
||||||
|
if (event.action === 'close') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle notification click - open the app
|
||||||
|
event.waitUntil(
|
||||||
|
clients.matchAll({ type: 'window' }).then((clientList) => {
|
||||||
|
// If the app is already open, focus it
|
||||||
|
for (const client of clientList) {
|
||||||
|
if (client.url === '/' && 'focus' in client) {
|
||||||
|
return client.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, open a new window
|
||||||
|
if (clients.openWindow) {
|
||||||
|
return clients.openWindow('/');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle push events
|
||||||
|
self.addEventListener('push', (event) => {
|
||||||
|
console.log('Push event received:', event);
|
||||||
|
|
||||||
|
if (event.data) {
|
||||||
|
const data = event.data.json();
|
||||||
|
console.log('Push data:', data);
|
||||||
|
|
||||||
|
const notificationTitle = data.notification?.title || 'Wesal App';
|
||||||
|
const notificationOptions = {
|
||||||
|
body: data.notification?.body || 'You have a new notification',
|
||||||
|
icon: '/icons/Icon-192.png',
|
||||||
|
badge: '/icons/Icon-192.png',
|
||||||
|
data: data.data,
|
||||||
|
tag: data.data?.type || 'general',
|
||||||
|
requireInteraction: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
event.waitUntil(
|
||||||
|
self.registration.showNotification(notificationTitle, notificationOptions)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle service worker activation
|
||||||
|
self.addEventListener('activate', (event) => {
|
||||||
|
console.log('Service worker activated');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle service worker installation
|
||||||
|
self.addEventListener('install', (event) => {
|
||||||
|
console.log('Service worker installed');
|
||||||
|
self.skipWaiting();
|
||||||
|
});
|
||||||
@ -34,5 +34,20 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script src="flutter_bootstrap.js" async></script>
|
<script src="flutter_bootstrap.js" async></script>
|
||||||
|
|
||||||
|
<!-- Firebase Messaging Service Worker -->
|
||||||
|
<script>
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
window.addEventListener('load', function() {
|
||||||
|
navigator.serviceWorker.register('/firebase-messaging-sw.js')
|
||||||
|
.then(function(registration) {
|
||||||
|
console.log('Firebase Messaging Service Worker registered successfully:', registration);
|
||||||
|
})
|
||||||
|
.catch(function(error) {
|
||||||
|
console.log('Firebase Messaging Service Worker registration failed:', error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -6,6 +6,9 @@
|
|||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <firebase_core/firebase_core_plugin_c_api.h>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
|
FirebaseCorePluginCApiRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("FirebaseCorePluginCApi"));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
firebase_core
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user