diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index c166a14f..4615f97b 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -4,8 +4,6 @@ PODS: - Flutter (1.0.0) - flutter_fgbg (0.0.1): - Flutter - - flutter_local_notifications (0.0.1): - - Flutter - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS @@ -14,7 +12,6 @@ DEPENDENCIES: - alarm (from `.symlinks/plugins/alarm/ios`) - Flutter (from `Flutter`) - flutter_fgbg (from `.symlinks/plugins/flutter_fgbg/ios`) - - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) EXTERNAL SOURCES: @@ -24,8 +21,6 @@ EXTERNAL SOURCES: :path: Flutter flutter_fgbg: :path: ".symlinks/plugins/flutter_fgbg/ios" - flutter_local_notifications: - :path: ".symlinks/plugins/flutter_local_notifications/ios" shared_preferences_foundation: :path: ".symlinks/plugins/shared_preferences_foundation/darwin" @@ -33,7 +28,6 @@ SPEC CHECKSUMS: alarm: 6c1f6a9688f94cd6bf8f104c67cc26e78c9d8d13 Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 flutter_fgbg: 31c0d1140a131daea2d342121808f6aa0dcd879d - flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743 shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126 PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 diff --git a/example/pubspec.lock b/example/pubspec.lock index 2e105762..f7d1557d 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -8,14 +8,6 @@ packages: relative: true source: path version: "3.0.0-dev.1" - args: - dependency: transitive - description: - name: args - sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 - url: "https://pub.dev" - source: hosted - version: "2.4.2" async: dependency: transitive description: @@ -64,14 +56,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.6" - dbus: - dependency: transitive - description: - name: dbus - sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac" - url: "https://pub.dev" - source: hosted - version: "0.7.10" fake_async: dependency: transitive description: @@ -117,30 +101,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" - flutter_local_notifications: - dependency: transitive - description: - name: flutter_local_notifications - sha256: "6d11ea777496061e583623aaf31923f93a9409ef8fcaeeefdd6cd78bf4fe5bb3" - url: "https://pub.dev" - source: hosted - version: "16.1.0" - flutter_local_notifications_linux: - dependency: transitive - description: - name: flutter_local_notifications_linux - sha256: "33f741ef47b5f63cc7f78fe75eeeac7e19f171ff3c3df054d84c1e38bedb6a03" - url: "https://pub.dev" - source: hosted - version: "4.0.0+1" - flutter_local_notifications_platform_interface: - dependency: transitive - description: - name: flutter_local_notifications_platform_interface - sha256: "7cf643d6d5022f3baed0be777b0662cce5919c0a7b86e700299f22dc4ae660ef" - url: "https://pub.dev" - source: hosted - version: "7.0.0+1" flutter_test: dependency: "direct dev" description: flutter @@ -215,14 +175,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.1" - petitparser: - dependency: transitive - description: - name: petitparser - sha256: eeb2d1428ee7f4170e2bd498827296a18d4e7fc462b71727d111c0ac7707cfa6 - url: "https://pub.dev" - source: hosted - version: "6.0.1" platform: dependency: transitive description: @@ -348,14 +300,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.1" - timezone: - dependency: transitive - description: - name: timezone - sha256: "1cfd8ddc2d1cfd836bc93e67b9be88c3adaeca6f40a00ca999104c30693cdca0" - url: "https://pub.dev" - source: hosted - version: "0.9.2" vector_math: dependency: transitive description: @@ -388,14 +332,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.3" - xml: - dependency: transitive - description: - name: xml - sha256: af5e77e9b83f2f4adc5d3f0a4ece1c7f45a2467b695c2540381bac793e34e556 - url: "https://pub.dev" - source: hosted - version: "6.4.2" sdks: dart: ">=3.2.0 <4.0.0" flutter: ">=3.16.0" diff --git a/ios/Classes/SwiftAlarmPlugin.swift b/ios/Classes/SwiftAlarmPlugin.swift index b2eb9109..3816f02b 100644 --- a/ios/Classes/SwiftAlarmPlugin.swift +++ b/ios/Classes/SwiftAlarmPlugin.swift @@ -66,27 +66,30 @@ public class SwiftAlarmPlugin: NSObject, FlutterPlugin { let args = call.arguments as! Dictionary + let id = args["id"] as! Int + let delayInSeconds = args["delayInSeconds"] as! Double + let notificationTitle = args["notificationTitle"] as? String + let notificationBody = args["notificationBody"] as? String + + if (notificationTitle != nil && notificationBody != nil && delayInSeconds >= 1.0) { + self.scheduleNotification(id: String(id), delayInSeconds: Int(floor(delayInSeconds)), title: notificationTitle!, body: notificationBody!) + } + notifOnKillEnabled = (args["notifOnKillEnabled"] as! Bool) notificationTitleOnKill = (args["notifTitleOnAppKill"] as! String) notificationBodyOnKill = (args["notifDescriptionOnAppKill"] as! String) if notifOnKillEnabled && !observerAdded { observerAdded = true - do { - NotificationCenter.default.addObserver(self, selector: #selector(applicationWillTerminate(_:)), name: UIApplication.willTerminateNotification, object: nil) - } catch { - NSLog("SwiftAlarmPlugin: Failed to register observer for UIApplication.willTerminateNotification: \(error)") - } + NotificationCenter.default.addObserver(self, selector: #selector(applicationWillTerminate(_:)), name: UIApplication.willTerminateNotification, object: nil) } - let id = args["id"] as! Int - let delayInSeconds = args["delayInSeconds"] as! Double let loopAudio = args["loopAudio"] as! Bool let fadeDuration = args["fadeDuration"] as! Double let vibrationsEnabled = args["vibrate"] as! Bool let volume = args["volume"] as? Double let assetAudio = args["assetAudio"] as! String - + var volumeFloat: Float? = nil if let volumeValue = volume { volumeFloat = Float(volumeValue) @@ -249,6 +252,8 @@ public class SwiftAlarmPlugin: NSObject, FlutterPlugin { } private func stopAlarm(id: Int, result: FlutterResult) { + self.cancelNotification(id: String(id)) + self.mixOtherAudios() self.vibrate = false @@ -421,4 +426,34 @@ public class SwiftAlarmPlugin: NSObject, FlutterPlugin { NSLog("SwiftAlarmPlugin: BGTaskScheduler not available for your version of iOS lower than 13.0") } } + + func scheduleNotification(id: String, delayInSeconds: Int, title: String, body: String) { + // Request permission + let center = UNUserNotificationCenter.current() + center.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in + if granted { + // Schedule the notification + let content = UNMutableNotificationContent() + content.title = title + content.body = body + content.sound = UNNotificationSound.default + + let trigger = UNTimeIntervalNotificationTrigger(timeInterval: TimeInterval(delayInSeconds), repeats: false) + let request = UNNotificationRequest(identifier: "alarm-\(id)", content: content, trigger: trigger) + + center.add(request) { error in + if let error = error { + NSLog("SwiftAlarmPlugin: Error scheduling notification: \(error.localizedDescription)") + } + } + } else { + NSLog("SwiftAlarmPlugin: Notification permission denied") + } + } + } + + func cancelNotification(id: String) { + let center = UNUserNotificationCenter.current() + center.removePendingNotificationRequests(withIdentifiers: ["alarm-\(id)"]) + } } \ No newline at end of file diff --git a/lib/alarm.dart b/lib/alarm.dart index fcb39d46..d4b54550 100644 --- a/lib/alarm.dart +++ b/lib/alarm.dart @@ -6,7 +6,6 @@ import 'dart:async'; import 'package:alarm/model/alarm_settings.dart'; import 'package:alarm/src/ios_alarm.dart'; import 'package:alarm/src/android_alarm.dart'; -import 'package:alarm/service/notification.dart'; import 'package:alarm/service/storage.dart'; import 'package:flutter/foundation.dart'; @@ -38,7 +37,6 @@ class Alarm { await Future.wait([ if (android) AndroidAlarm.init(), - AlarmNotification.instance.init(), AlarmStorage.init(), ]); await checkAlarm(); @@ -82,20 +80,6 @@ class Alarm { await AlarmStorage.saveAlarm(alarmSettings); - if (iOS) { - await AlarmNotification.instance.scheduleAlarmNotif( - id: alarmSettings.id, - dateTime: alarmSettings.dateTime, - title: alarmSettings.notificationTitle, - body: alarmSettings.notificationBody, - fullScreenIntent: alarmSettings.androidFullScreenIntent, - ); - } - - if (alarmSettings.enableNotificationOnKill) { - await AlarmNotification.instance.requestNotificationPermission(); - } - if (iOS) { return IOSAlarm.setAlarm( alarmSettings, @@ -129,8 +113,6 @@ class Alarm { static Future stop(int id) async { await AlarmStorage.unsaveAlarm(id); - AlarmNotification.instance.cancel(id); - return iOS ? await IOSAlarm.stopAlarm(id) : await AndroidAlarm.stop(id); } diff --git a/lib/service/notification.dart b/lib/service/notification.dart deleted file mode 100644 index 5852caa2..00000000 --- a/lib/service/notification.dart +++ /dev/null @@ -1,128 +0,0 @@ -import 'dart:async'; - -import 'package:alarm/alarm.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter_local_notifications/flutter_local_notifications.dart'; -import 'package:timezone/data/latest_all.dart' as tz; -import 'package:timezone/timezone.dart' as tz; - -/// The purpose of this class is to show a notification to the user -/// when the alarm rings so the user can understand where the audio -/// comes from. He also can tap the notification to open directly the app. -class AlarmNotification { - static final instance = AlarmNotification._(); - - final localNotif = FlutterLocalNotificationsPlugin(); - - AlarmNotification._(); - - /// Adds configuration for local notifications and initialize service. - Future init() async { - const initializationSettingsAndroid = AndroidInitializationSettings( - '@mipmap/ic_launcher', - ); - const initializationSettingsIOS = DarwinInitializationSettings( - requestAlertPermission: false, - requestSoundPermission: false, - requestBadgePermission: false, - ); - const initializationSettings = InitializationSettings( - android: initializationSettingsAndroid, - iOS: initializationSettingsIOS, - ); - - await localNotif.initialize(initializationSettings); - tz.initializeTimeZones(); - } - - /// Shows notification permission request. - Future requestNotificationPermission() async { - if (defaultTargetPlatform == TargetPlatform.iOS) { - final res = await localNotif - .resolvePlatformSpecificImplementation< - IOSFlutterLocalNotificationsPlugin>() - ?.requestPermissions(alert: true, badge: true, sound: true); - return res ?? false; - } - if (defaultTargetPlatform == TargetPlatform.android) { - final res = await localNotif - .resolvePlatformSpecificImplementation< - AndroidFlutterLocalNotificationsPlugin>() - ?.requestNotificationsPermission(); - - return res ?? false; - } - return false; - } - - tz.TZDateTime nextInstanceOfTime(DateTime dateTime) { - final now = DateTime.now(); - - if (dateTime.isBefore(now)) { - dateTime = dateTime.add(const Duration(days: 1)); - } - - return tz.TZDateTime.from(dateTime, tz.local); - } - - /// Schedules notification at the given [dateTime]. - Future scheduleAlarmNotif({ - required int id, - required DateTime dateTime, - required String title, - required String body, - required bool fullScreenIntent, - }) async { - const iOSPlatformChannelSpecifics = DarwinNotificationDetails( - presentAlert: true, - presentBadge: false, - presentSound: false, - ); - - final androidPlatformChannelSpecifics = AndroidNotificationDetails( - 'alarm', - 'alarm_plugin', - channelDescription: 'Alarm plugin', - importance: Importance.max, - priority: Priority.max, - playSound: false, - enableLights: true, - fullScreenIntent: fullScreenIntent, - visibility: NotificationVisibility.public, - ); - - final platformChannelSpecifics = NotificationDetails( - android: androidPlatformChannelSpecifics, - iOS: iOSPlatformChannelSpecifics, - ); - - final zdt = nextInstanceOfTime(dateTime); - - final hasNotificationPermission = await requestNotificationPermission(); - if (!hasNotificationPermission) { - alarmPrint('Notification permission not granted'); - } - - try { - await localNotif.zonedSchedule( - id, - title, - body, - tz.TZDateTime.from(zdt.toUtc(), tz.UTC), - platformChannelSpecifics, - androidScheduleMode: AndroidScheduleMode.alarmClock, - uiLocalNotificationDateInterpretation: - UILocalNotificationDateInterpretation.absoluteTime, - ); - alarmPrint( - 'Notification with id $id scheduled successfuly at $zdt GMT', - ); - } catch (e) { - throw AlarmException('Schedule notification with id $id error: $e'); - } - } - - /// Cancels notification. Called when the alarm is cancelled or - /// when an alarm is overriden. - Future cancel(int id) => localNotif.cancel(id); -} diff --git a/lib/src/ios_alarm.dart b/lib/src/ios_alarm.dart index 8b52cb18..60de9d67 100644 --- a/lib/src/ios_alarm.dart +++ b/lib/src/ios_alarm.dart @@ -36,6 +36,8 @@ class IOSAlarm { 'vibrate': settings.vibrate, 'volume': settings.volume, 'notifOnKillEnabled': settings.enableNotificationOnKill, + 'notificationTitle': settings.notificationTitle, + 'notificationBody': settings.notificationBody, 'notifTitleOnAppKill': AlarmStorage.getNotificationOnAppKillTitle(), 'notifDescriptionOnAppKill': diff --git a/pubspec.yaml b/pubspec.yaml index c16c3c16..440b460c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,9 +11,7 @@ dependencies: flutter: sdk: flutter flutter_fgbg: ^0.3.0 - flutter_local_notifications: ^16.1.0 shared_preferences: ^2.2.2 - timezone: ^0.9.2 dev_dependencies: flutter_test: