Skip to content

Instantly share code, notes, and snippets.

@CoderNamedHendrick
Last active June 12, 2024 20:24
Show Gist options
  • Save CoderNamedHendrick/d606754becad57a4238bcb0d87f5f69f to your computer and use it in GitHub Desktop.
Save CoderNamedHendrick/d606754becad57a4238bcb0d87f5f69f to your computer and use it in GitHub Desktop.
Notification Integration
import 'dart:async';
import 'package:amplify_flutter/amplify_flutter.dart';
import 'notification_dto.dart';
import 'service.dart';
Future<void> amplifyBackgroundNotificationReceivedHandler(
PushNotificationMessage notification) async {
NotificationService.backgroundNotificationReceivedHandler(
notification.toNotificationDto(),
);
}
final class AmplifyNotificationService implements NotificationService {
const AmplifyNotificationService([this._pushCategory]);
final PushNotificationsCategory? _pushCategory;
PushNotificationsCategory get _amplifyNotification =>
_pushCategory ?? Amplify.Notifications.Push;
NotificationDto _onNotificationReceived(PushNotificationMessage message) {
return message.toNotificationDto();
}
@override
Future<String?> get deviceToken async {
return await _amplifyNotification.onTokenReceived
.firstWhere((token) => token.isNotEmpty);
}
@override
Stream<NotificationDto> foregroundNotificationsHandler() async* {
yield* _amplifyNotification.onNotificationReceivedInForeground
.map(_onNotificationReceived);
}
@override
Stream<NotificationDto> foregroundNotificationReceivedHandler() async* {
yield* _amplifyNotification.onNotificationOpened
.map(_onNotificationReceived);
}
@override
Future<NotificationDto?> get launchNotification async =>
_amplifyNotification.launchNotification?.toNotificationDto();
@override
Future<void> requestPermission() async {
try {
final status = await _amplifyNotification.getPermissionStatus();
switch (status) {
case PushNotificationPermissionStatus.granted:
case PushNotificationPermissionStatus.denied:
break;
case PushNotificationPermissionStatus.shouldRequest:
await _amplifyNotification.requestPermissions();
case PushNotificationPermissionStatus.shouldExplainThenRequest:
await _amplifyNotification.requestPermissions();
}
} catch (_) {
rethrow;
}
}
}
extension on PushNotificationMessage {
NotificationDto toNotificationDto() {
return NotificationDto(
id: hashCode,
title: title,
body: body,
deeplinkUrl: deeplinkUrl,
);
}
}
import 'dart:io';
import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_flutter/amplify_flutter.dart' hide LogLevel;
import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:firebase_remote_config/firebase_remote_config.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'amplifyconfiguration.dart';
import 'firebase_options.dart';
import 'shared/services/services.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
await FirebaseMessaging.instance.setAutoInitEnabled(true);
await _configureAmplify();
await LocalNotificationManager.initialise();
NotificationService.initialise(const FirebaseNotificationService());
await NotificationService.instance.requestPermission();
FirebaseMessaging.onBackgroundMessage(
firebaseBackgroundNotificationReceivedHandler);
debugPrint = (String? message, {int? wrapWidth}) {
if (kDebugMode) {
debugPrintSynchronously(message, wrapWidth: wrapWidth);
}
};
runApp(const ProviderScope(child: App()));
}
Future<void> _configureAmplify() async {
try {
final auth = AmplifyAuthCognito();
notificationPlugin.onNotificationReceivedInBackground(
amplifyBackgroundNotificationReceivedHandler,
);
// await Amplify.addPlugins([auth]);
await Amplify.addPlugin(auth);
if (!Amplify.isConfigured) {
await Amplify.configure(amplifyconfig);
}
} on Exception catch (e) {
safePrint('An error occurred while configuring Amplify: $e');
}
}
class App extends ConsumerStatefulWidget {
const App({super.key});
@override
ConsumerState<App> createState() => _AppState();
}
class _AppState extends ConsumerState<App> {
late final StreamSubscription<NotificationDto>
foregroundPushNotificationSubscription;
late final StreamSubscription<NotificationDto>
foregroundNotificationLaunchSubscription;
void onPushNotificationReceived(NotificationDto message) {
LocalNotificationManager.showNotification(message);
}
void onPushNotificationLaunched(NotificationDto message) {}
@override
void initState() {
super.initState();
foregroundPushNotificationSubscription = NotificationService.instance
.foregroundNotificationsHandler()
.listen(onPushNotificationReceived);
foregroundNotificationLaunchSubscription = NotificationService.instance
.foregroundNotificationReceivedHandler()
.listen(onPushNotificationLaunched);
}
@override
void dispose() {
super.dispose();
foregroundPushNotificationSubscription.cancel();
foregroundNotificationLaunchSubscription.cancel();
}
@override
Widget build(BuildContext context) {
// code deleted to show example
return Container();
}
}
import 'package:companion/firebase_options.dart';
import 'package:companion/shared/services/notification/notification.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
Future<void> firebaseBackgroundNotificationReceivedHandler(
RemoteMessage message) async {
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
NotificationService.backgroundNotificationReceivedHandler(
message.toNotificationDto(),
);
}
final class FirebaseNotificationService implements NotificationService {
const FirebaseNotificationService();
static final _firebaseMessaging = FirebaseMessaging.instance;
NotificationDto _onRemoteMessageReceived(RemoteMessage message) {
if (message.notification == null && message.notification?.android == null) {
throw UnimplementedError();
}
return message.toNotificationDto();
}
@override
Future<String?> get deviceToken async => await _firebaseMessaging.getToken();
@override
Stream<NotificationDto> foregroundNotificationReceivedHandler() async* {
yield* FirebaseMessaging.onMessageOpenedApp.map(_onRemoteMessageReceived);
}
@override
Stream<NotificationDto> foregroundNotificationsHandler() async* {
yield* FirebaseMessaging.onMessage.map(_onRemoteMessageReceived);
}
@override
Future<NotificationDto?> get launchNotification async =>
(await _firebaseMessaging.getInitialMessage())?.toNotificationDto();
@override
Future<void> requestPermission() async {
try {
await _firebaseMessaging.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
await _firebaseMessaging.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
} catch (_) {
rethrow;
}
}
}
extension on RemoteMessage {
NotificationDto toNotificationDto() {
return NotificationDto(
id: hashCode,
title: notification?.title,
body: notification?.body,
deeplinkUrl: notification?.android?.clickAction,
);
}
}
import 'package:equatable/equatable.dart';
final class NotificationDto extends Equatable {
final int id;
final String? title;
final String? body;
final String? deeplinkUrl;
const NotificationDto({
required this.id,
this.title,
this.body,
this.deeplinkUrl,
});
@override
List<Object?> get props => [id, title, body, deeplinkUrl];
}
import 'dart:async';
import 'amplify_notification_service.dart';
import 'notification_dto.dart';
abstract interface class NotificationService {
const NotificationService._();
static Future<void> backgroundNotificationReceivedHandler(
NotificationDto message) async {
// TODO: handle background notification
}
static NotificationService? _instance;
static void initialise(
[NotificationService service = const AmplifyNotificationService()]) {
_instance ??= service;
}
static NotificationService get instance {
if (_instance == null) {
throw ArgumentError(
'No instance has been assigned, please call the initialise method before getting the instance');
}
return _instance!;
}
Future<void> requestPermission();
Stream<NotificationDto> foregroundNotificationsHandler();
Stream<NotificationDto> foregroundNotificationReceivedHandler();
Future<NotificationDto?> get launchNotification;
Future<String?> get deviceToken;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment