As of now for my alarm app, I used the Flutter local notification plugin to schedule notification and play the alarm ringtone by keeping the alarm ringtone as the notification sound in the code.
But because of this, in some Android and iOS devices, the sound is not playing. Is there any way better way to schedule alarms in Flutter?
Here is the code for notification that I did:
class SetAlarm {
static Future<void> setAlarmtoStorage({
int id,
TimeOfDay alarmTime,
}) async {
SharedPreferences pref = await SharedPreferences.getInstance();
pref.setStringList('$id', [alarmTime.hour.toString(), alarmTime.minute.toString()]);
}
static Future<TimeOfDay> getAlarmfromStorage({int id}) async {
SharedPreferences pref = await SharedPreferences.getInstance();
final hourAndMin = pref.getStringList('$id');
final time = TimeOfDay(
hour: int.parse(hourAndMin[0]),
minute: int.parse(hourAndMin[1]),
);
return time;
}
static Future<void> cancelAlarm(int id) async {
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
await flutterLocalNotificationsPlugin.cancel(id);
}
static Future<void> setAlarm(TimeOfDay selectedTime, int id) async {
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
tz.initializeTimeZones();
final String currentTimeZone = await FlutterNativeTimezone.getLocalTimezone();
print(currentTimeZone);
tz.setLocalLocation(tz.getLocation(currentTimeZone));
var notifydate;
final hour = (TimeOfDay.now().hour - selectedTime.hour).abs();
final min = (TimeOfDay.now().minute - selectedTime.minute).abs();
if (tz.TZDateTime.now(tz.local).isAfter(DateTime(
DateTime.now().year,
DateTime.now().month,
DateTime.now().day,
selectedTime.hour,
selectedTime.minute,
))) {
notifydate = tz.TZDateTime.local(DateTime.now().year, DateTime.now().month,
DateTime.now().add(Duration(days: 1)).day, selectedTime.hour, selectedTime.minute);
// tz.TZDateTime.now(tz.local)
// .subtract(Duration(seconds: tz.TZDateTime.now(tz.local).second))
// .add(Duration(days: 1, hours: hour, minutes: min));
print(notifydate.toString());
print('isAfter true(alarm time is after the now date)');
} else {
notifydate = tz.TZDateTime.now(tz.local)
.subtract(Duration(seconds: tz.TZDateTime.now(tz.local).second))
.add(Duration(hours: hour, minutes: min));
print('isAfter:false');
}
var androidPlatformChannelSpecifics = AndroidNotificationDetails(
'alarm_notify',
'alarm_notify',
'Channel for Alarm notification',
icon: 'time',
sound: RawResourceAndroidNotificationSound('alarm_ringtone'),
largeIcon: DrawableResourceAndroidBitmap('time'),
playSound: true,
);
var iOSPlatformChannelSpecifics = IOSNotificationDetails(
sound: 'alarm_ringtone.mp3',
presentAlert: true,
presentBadge: true,
presentSound: true,
);
var platformChannelSpecifics =
NotificationDetails(android: androidPlatformChannelSpecifics, iOS: iOSPlatformChannelSpecifics);
await flutterLocalNotificationsPlugin.zonedSchedule(
id,
'Alarm',
'Wake Up!!!',
notifydate,
platformChannelSpecifics,
androidAllowWhileIdle: true,
uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime,
);
}
}
I did all the setup required for flutter local notification. I even kept the sound in the raw folder inside res.
Related
I am working on work manager to fetxh api data and initiate a notification in flutter,
//this is the name given to the background fetch
const simplePeriodicTask = "simplePeriodicTask";
Workmanager workmanager = Workmanager();
// flutter local notification setup
Future initializeWorkManagerAndPushNotification() async {
await workmanager.initialize(
callbackDispatcher,
isInDebugMode: false,
); //to true if still in testing lev turn it to false whenever you are launching the app
await workmanager.registerPeriodicTask(
"1", simplePeriodicTask,
existingWorkPolicy: ExistingWorkPolicy.replace,
frequency: Duration(minutes: 1), //when should it check the link
initialDelay:
Duration(seconds: 5), //duration before showing the notification
constraints: Constraints(
networkType: NetworkType.connected,
),
);
}
void callbackDispatcher() async {
workmanager.executeTask((task, inputData) async {
print('Ruuning - callbackDispatcher');
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
var androidSettings = AndroidInitializationSettings('#mipmap/ic_launcher');
var iOSSettings = IOSInitializationSettings();
var initSetttings =
InitializationSettings(android: androidSettings, iOS: iOSSettings);
//
// TODO: Permission
//
await flutterLocalNotificationsPlugin.initialize(initSetttings);
String message =
await WebServiceController.getInstance.getPushNotificationMessage();
print("here 1 ================");
// print(response);
// var convert = json.decode(response.body);
// if (convert['status'] == true) {
// showNotification(convert['msg'], flutterLocalNotificationsPlugin);
// } else {
// print("no messgae");
// }
print("messgae");
print(message);
await showNotification(message, flutterLocalNotificationsPlugin);
return Future.value(true);
});
}
Future showNotification(payloadmessage, flutterLocalNotificationsPlugin) async {
print("showing notification");
var androidDetails = AndroidNotificationDetails(
'channel id', 'channel NAME', 'CHANNEL DESCRIPTION',
priority: Priority.high, importance: Importance.max);
var iOSDetails = IOSNotificationDetails();
var platform = NotificationDetails(android: androidDetails, iOS: iOSDetails);
await flutterLocalNotificationsPlugin.show(
0, 'Message - Virtual intelligent solution', '$payloadmessage', platform,
payload: 'OnClick Payload -VIS \n $payloadmessage');
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setPreferredOrientations(
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
await initializeWorkManagerAndPushNotification();
runApp(MyApp());
}
this function callbackDispatcher() function is used to Initialize Notification and fetch api data from below method.
Future<String> getPushNotificationMessage() async {
print("getting - getPushNotificationMessage");
try {
var response = await _dio.get(APIURLConstants.pushNotification);
print(response);
print("here================ ${response.data}");
var convert = json.decode(response.data);
return convert['message'].toString() ?? "";
} on DioError catch (error) {
print("Dio Error ${error.message}");
} catch (error) {
print("Error - ${error.toString()}");
}
}
as per the below output , It seems that only print(response); of getPushNotificationMessage() is executed after that below code is not executing,
Performing hot restart...
Restarted application in 2,266ms.
W/WM-WorkSpec(31092): Interval duration lesser than minimum allowed value; Changed to 900000
I/flutter (31092): getting - getPushNotificationMessage
I/flutter (31092): {"message":"Hi There I am notification","seen":0,"notification_id":"111"}
I/WM-WorkerWrapper(31092): Worker result SUCCESS for Work [ id=6c935b3b-bfe4-47fa-b30a-0965299f5224, tags={ be.tramckrijte.workmanager.BackgroundWorker } ]
I founded the issue, to make the code execute, I needed to hot restart the application to execute code from
main() method
I am making an app in that I want to send a notification to the user with the help of the flutter_local_notification package. I want to send a notification to the user at a certain time every day, for that, I am using the following function:
Future<void> showDailyAtTime() async {
////////// <<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>
var time = Time(16, 02, 00); ////// line 1 <---------- (Hour, Minute, Second)
////////// <<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>
var androidChannelSpecifics = AndroidNotificationDetails(
'CHANNEL_ID 2',
'CHANNEL_NAME 2',
"CHANNEL_DESCRIPTION 2",
importance: Importance.max,
priority: Priority.high,
);
var iosChannelSpecifics = IOSNotificationDetails();
var platformChannelSpecifics =
NotificationDetails(android: androidChannelSpecifics, iOS: iosChannelSpecifics);
await flutterLocalNotificationsPlugin.showDailyAtTime(
0,
'Test Title at ${time.hour}:${time.minute}.${time.second}',
'Test Body', //null
time,
platformChannelSpecifics,
payload: 'Test Payload',
);
}
I am storing the time using shared preferences like this:
ttime = '${time.hour} : ${time.minute} : ${time.second}';
And then I am setting it like this:
Future<void> _setNotifyTime() async{
final prefs = await SharedPreferences.getInstance();
final savedNotifyTime = await _getStringFromSharedPrefs();
await prefs.setString('notificationTime', ttime);
//print("this $savedNotifyTime");
return savedNotifyTime;
}
Then I am getting from shared preferences with the help of following code:
Future<String> _getStringFromSharedPrefs() async{
final prefs = await SharedPreferences.getInstance();
notifyTime = prefs.getString('notificationTime');
return notifyTime;
}
How can I convert this saved time to the required format (as shown in line 1), the values are in int?
How can I do it? Please help me.
Thanks for your replies in advance
var splited = notifyTime.split(':');
int hour = int.parse(splited[0]);
int minute = int.parse(splited[1]);
int second = int.parse(splited[2]);
You can do pattern splitting like in the answer by Jorge Vieira or you save yourself the parsing logic and just store it as ints.
For setting you can use setInt()
prefs.setInt("H",time.hours);
prefs.setInt("m",time.minutes);
prefs.setInt("s",time.seconds);
For getting it you can use getInt()
int hours = prefs.getInt("H");
int mins = prefs.getInt("m");
int secs = prefs.getInt("s");
Then from your methods just return the Time object
return Time(hours,mins,secs);
I've been working on the Flutter project and now I am trying to schedule notification by using flutter_local_notification. I've integrated that dependency into my project and it works fine.
Now I want to schedule a notification to be alerted on the app like 2 days before, and then 4 hours before, and then 30 minutes before.
For example, my app has an event called A, and then I want to schedule that event A to send a notification for the user like 1 day before, and then 1 hour before, and then 30 minutes before the event A starts. So it will send a notification 3 times.
For my scenario: In order to send a notification we have to pass the notification id. Let's consider event A has id '123'. Do I have to schedule that notification 3 times with the same notification id '123'?
Let's check the code I have done in order to send a notification:
Future<void> showNotification({
#required int id,
#required DateTime dateTime,
String title,
String body,
}) async {
final TimeZone timeZone = TimeZone();
final String tzName = await timeZone.getTimeZoneName();
final tz.Location location = await timeZone.getLocation(tzName);
final scheduledDate = tz.TZDateTime(
location,
dateTime.year,
dateTime.month,
dateTime.day,
dateTime.hour,
dateTime.minute,
dateTime.second,
);
log('------------> Schedule date $scheduledDate');
final AndroidNotificationDetails androidChannelSpecifics =
AndroidNotificationDetails(
'$id',
'NAME $id',
'DESCRIPTION $id',
importance: Importance.max,
priority: Priority.high,
ledOnMs: 1000,
ledOffMs: 500,
);
final IOSNotificationDetails iosNotificationSpecifics =
IOSNotificationDetails();
final notificationDetails = NotificationDetails(
iOS: iosNotificationSpecifics, android: androidChannelSpecifics);
await flutterLocalNotificationsPlugin.zonedSchedule(
id,
title,
body,
scheduledDate,
notificationDetails,
matchDateTimeComponents: DateTimeComponents.time,
uiLocalNotificationDateInterpretation: null,
androidAllowWhileIdle: true,
);
}
For notification initialization like configuring in AndroidManifest.xml, I also have done it already.
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
final BehaviorSubject<ReceivedNotification> didReceivedNotificationSub =
BehaviorSubject<ReceivedNotification>();
InitializationSettings initializationSettings;
LocalNotificationiHelper._() {
init();
}
Future<void> init() async {
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
tz.initializeTimeZones();
if (Platform.isIOS) {
_requestIOSPermission();
}
initialPlatformSpecifics();
}
void initialPlatformSpecifics() {
const AndroidInitializationSettings initializeAndroidSetting =
AndroidInitializationSettings('#mipmap/ic_launcher');
final IOSInitializationSettings initializeIOSSetting =
IOSInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: false,
onDidReceiveLocalNotification:
(int id, String title, String body, String payload) async {
final ReceivedNotification receivedNotification = ReceivedNotification(
id: id, title: title, body: body, payload: payload);
didReceivedNotificationSub.add(receivedNotification);
},
);
initializationSettings = InitializationSettings(
android: initializeAndroidSetting, iOS: initializeIOSSetting);
}
void _requestIOSPermission() {
flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin>()
.requestPermissions(
alert: false,
badge: true,
sound: true,
);
}
You might've noticed the class TimeZone(), it is just another class that I created to get the current time zone of the user.
Here is the class for TimeZone()
class TimeZone {
factory TimeZone() => _this ?? TimeZone._();
TimeZone._() {
initializeTimeZones();
}
static TimeZone _this;
Future<String> getTimeZoneName() async =>
FlutterNativeTimezone.getLocalTimezone();
Future<t.Location> getLocation([String timeZoneName]) async {
if (timeZoneName == null || timeZoneName.isEmpty) {
timeZoneName = await getTimeZoneName();
}
return t.getLocation(timeZoneName);
}
}
For example, event A with id 123 will start at 2020-11-19 16:00:00.
So I want to know that should we schedule that notification 3 times in order for it to be sent like 1 day before, 3 hours before, and 30 minutes before the event start??
This depends on how you'd like to set the interval. One way that you can schedule recurring notifications using flutter_local_notifications is by utilizing flutterLocalNotificationsPlugin.periodicallyShow() where you can set intervals like RepeatInterval.everyMinute - usage can be found in the docs.
The LocalNotificationsPlugin should be called up every minute with a different payload (variable "custom"). The call is made in a loop. I create a new instance of the plugin class and then initialise it with the settings to use it for each platform. The code works and push notifications are displayed. However, only the most recent message is shown -> the message that last went through the loop. The id is created uniquely from a random number and the time.
Why could not all messages be displayed?
Thanks a lot!
//Loop and create new Push Message
for (var i = 1; i <= final_list.length - 1; i++) {
//Info: Index not 0 because Index 0 value should not be used
final_message = final_list[i];
//Add payload
custom = final_message;
if (i == 1 ){
//First loop -> Selected time plus 1 min
finalmsgtime = selectedTime.add(new Duration(minutes: 1));
} else {
//Second loop and bigger -> finalmsgtime + 2 min //only for test :)
finalmsgtime = finalmsgtime.add(new Duration(minutes: 2));
}
//Date & Time
var now = new DateTime.now();
var notificationTime = new DateTime(
now.year, now.month, now.day, finalmsgtime.hour, finalmsgtime.minute);
//GET ID
var randomizer = new Random();
String id;
var num_id = randomizer.nextInt(10000);
id = '$num_id$now'; //Eindeutige ID
//Set push message
scheduleNotification(
flutterLocalNotificationsPlugin, id, custom, notificationTime);
} //Ende Loop
In this method we create the push message:
Future<void> scheduleNotification(
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin,
String id,
String body,
DateTime scheduledNotificationDateTime) async {
var androidPlatformChannelSpecifics = AndroidNotificationDetails(
id,
'Reminder notifications',
'Remember about it',
icon: 'app_icon',
);
var iOSPlatformChannelSpecifics = IOSNotificationDetails();
var platformChannelSpecifics = NotificationDetails(
androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
await flutterLocalNotificationsPlugin.schedule(0, 'Quote of the Day', body, //Titel von Push-Nachricht
scheduledNotificationDateTime, platformChannelSpecifics);
}
I found the solution. The Problem was that flutterLocalNotificationsPlugin.schedule(...) was called with the static value '0' for ID and not with the variable. After I changed this, the ID for each notification was unique and the notifications have been displayed correctly.
Future<void> scheduleNotification(
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin,
String id,
String body,
DateTime scheduledNotificationDateTime) async {
var androidPlatformChannelSpecifics = AndroidNotificationDetails(
id,
'Reminder notifications',
'Remember about it',
icon: 'app_icon',
);
var iOSPlatformChannelSpecifics = IOSNotificationDetails();
var platformChannelSpecifics = NotificationDetails(
androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
var myID = int.parse(id);
assert(myID is int);
myID = myID - 1000;
await flutterLocalNotificationsPlugin.schedule(myID, 'Quote of the Day', body, //Titel von Push-Nachricht
scheduledNotificationDateTime, platformChannelSpecifics);
}
I would like to ask if there's a http get in flutter local notifications? My aim here is when the flutter notification will show, a http get request will be triggered
This my http request for my api:
final String url = 'http://192.168.43.45:8000/api';//url in my request
List data;
Future<String> getData() async {
var response =await http.get(
Uri.encodeFull(url),
headers:{"Accept":"application/json"}
);//get data and decode it to json
}
This code will initialize the notifications:
initializeNotifications() async {
var initializationSettingsAndroid =
AndroidInitializationSettings('#mipmap/launcher_icon');//icon will display when notification appears
var initializationSettingsIOS = IOSInitializationSettings();
var initializationSettings = InitializationSettings(
initializationSettingsAndroid, initializationSettingsIOS);
await flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: onSelectNotification);
}
Future onSelectNotification(String payload) async {
if (payload != null) {
debugPrint('notification payload: ' + payload);
}
await Navigator.push(
context,
new MaterialPageRoute(builder: (context) => HomePage()),
);
}
Code for the notification when click it will redirect to homePage:
Future<void> scheduleNotification(Medicine medicine) async {
var hour = int.parse(medicine.startTime[0] + medicine.startTime[1]);
var ogValue = hour;
var minute = int.parse(medicine.startTime[2] + medicine.startTime[3]);
var androidPlatformChannelSpecifics = AndroidNotificationDetails(
'repeatDailyAtTime channel id',
'repeatDailyAtTime channel name',
'repeatDailyAtTime description',
importance: Importance.Max,
ledColor: Color(0xFF3EB16F),
ledOffMs: 1000,
ledOnMs: 1000,
enableLights: true,
);
//notification details
var iOSPlatformChannelSpecifics = IOSNotificationDetails();
var platformChannelSpecifics = NotificationDetails(
androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
//this code will show the whats the notification must appear
await flutterLocalNotificationsPlugin.showDailyAtTime(
int.parse(medicine.notificationIDs[i]),
'Mediminder: ${medicine.medicineName}',
medicine.medicineType.toString() !=
MedicineType.None.toString()
? 'It is time to take your Medicine, according to schedule'
: 'It is time to take your medicine, according to schedule',
Time(hour, minute,),
platformChannelSpecifics);
hour = ogValue;
}
//await flutterLocalNotificationsPlugin.cancelAll();//cancel the flutter notifications
}
}
it seems that you are using flutter_local_notifications, looking at their documentation i don't think it's possible to you to handle the onReceive notification, this is done internally by the package.
But maybe you could implement your own receiver class extending BroadCastReceiver and listen for the same action that the packages send, from there you'll be able to send HTTP requests.
Take a look at this question, maybe it helps.