개발자

flutter 플러터 알림 기능

2024년 03월 11일조회 207

flutter_local_notifications를 사용해서 알림 기능을 구현하고 있는데, 함수는 작동하는데 알림이 안뜹니다. 권한도 설정했고 로컬 설정도 서울로 확인했는데, 시간 변환이 문제인 건지 온갖 걸 다해봐도 알림이 뜨지 않습니다. 며칠을 붙잡고 있는데 검토 한 번만 부탁드리겠습니다..

1import 'package:flutter/material.dart';
2import 'package:flutter_local_notifications/flutter_local_notifications.dart';
3import 'package:shared_preferences/shared_preferences.dart';
4import 'package:table_calendar/table_calendar.dart';
5import 'package:timezone/standalone.dart';
6import 'package:timezone/timezone.dart' as tz;
7import 'package:timezone/data/latest.dart' as tz;
8import 'main.dart';
9
10class ShuttleBus extends StatefulWidget {
11  const ShuttleBus({super.key});
12
13  @override
14  State<ShuttleBus> createState() => ShuttleBusState();
15}
16
17class ShuttleBusState extends State<ShuttleBus> {
18  CalendarFormat calendarFormat = CalendarFormat.month;
19  DateTime focusedDay = DateTime.now();
20  DateTime? selectedDay;
21  List<DateTime> markedDays = [];
22
23
24  //**초기 */
25  @override
26  void initState() {
27    super.initState();
28    tz.initializeTimeZones();
29    var seoul = tz.getLocation('Asia/Seoul');
30    tz.setLocalLocation(seoul);
31
32    AndroidInitializationSettings androidInitializationSettings = const AndroidInitializationSettings('mipmap/ic_launcher');
33    DarwinInitializationSettings iosInitializationSettings = const DarwinInitializationSettings(
34      requestAlertPermission: false,
35      requestBadgePermission: false,
36      requestSoundPermission: false,
37    );
38    
39    InitializationSettings initializationSettings = InitializationSettings(
40      android: androidInitializationSettings,
41      iOS: iosInitializationSettings,
42    );
43
44    flutterLocalNotificationsPlugin.initialize(initializationSettings);
45    loadMarkedDays();
46  }
47
48
49  //**셔틀 예약 알림 */
50  Future<void> scheduleAlarm(DateTime scheduledNotificationDateTime) async {
51    var androidNotificationDetails = const AndroidNotificationDetails(
52      '1 channel id',
53      '2 channel name',
54      priority: Priority.high,
55      importance: Importance.max,
56    );
57
58    var notificationDetails = NotificationDetails(
59        android: androidNotificationDetails,
60        iOS: const DarwinNotificationDetails(badgeNumber: 1));
61
62    // 선택된 날짜에서 이틀 전의 오후 8시 30분 계산
63    var notificationTime = DateTime.now().add(const Duration(days: 2, hours: 22, minutes: 22));
64
65    // TZDateTime으로 변환
66    tz.TZDateTime scheduledTimeZoneDateTime =
67        tz.TZDateTime.from(notificationTime, tz.local);
68    print(tz.TZDateTime.now(tz.local));
69    print(notificationTime);
70    print(scheduledNotificationDateTime);
71    
72    //푸시알림 내용
73    await flutterLocalNotificationsPlugin.zonedSchedule(
74        0, 'test title', 'test body', scheduledTimeZoneDateTime, notificationDetails,
75        androidScheduleMode: AndroidScheduleMode.inexactAllowWhileIdle,
76        uiLocalNotificationDateInterpretation:
77            UILocalNotificationDateInterpretation.absoluteTime);
78    print('scheduleAlarm completed');
79  }
80
81  //**알림 로드 및 로컬 저장 */
82  Future<void> loadMarkedDays() async {
83    SharedPreferences prefs = await SharedPreferences.getInstance();
84    setState(() {
85      markedDays = (prefs.getStringList('markedDays') ?? []).map((item) => DateTime.parse(item)).toList();
86    });
87  }
88
89  Future<void> saveMarkedDays() async {
90    SharedPreferences prefs = await SharedPreferences.getInstance();
91    await prefs.setStringList('markedDays', markedDays.map((item) => item.toString()).toList());
92    setState(() {});
93  }
94
95  //화면 위젯
96  @override
97  Widget build(BuildContext context) {
98    return Scaffold(
99      appBar: AppBar(
100        title: const Text('셔틀버스'),
101      ),
102      body: Padding(padding: const EdgeInsets.all(16),
103        child: ListView(
104          children: <Widget> [
105            const Text('운행시간',
106              style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
107            Padding(padding: const EdgeInsets.fromLTRB(10, 20, 10, 10),
108              child: Image.asset('assets/images/shuttle_bus_time.png')),
109            const SizedBox(height: 30),
110
111            const Text('셔틀 예약 알림',
112              style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
113
114            TableCalendar(
115              //locale: 'ko_KR',
116              firstDay: DateTime.now(),
117              lastDay: DateTime(2024, 6, 21),
118              focusedDay: focusedDay,
119              headerStyle: const HeaderStyle(formatButtonVisible: false),
120
121              eventLoader: (day) {
122                return markedDays.where((event) => isSameDay(event, day)).toList();
123              },
124              selectedDayPredicate: (day) {
125                return isSameDay(selectedDay, day);
126              },
127
128              onDaySelected: (selectedDay, focusedDay) async {
129                setState(() {
130                  this.focusedDay = selectedDay;
131
132                  if (markedDays.contains(selectedDay)) {
133                    showDialog(
134                      context: context,
135                      builder: (context) => AlertDialog(
136                        title: const Text("알림 삭제"),
137                        content: const Text("셔틀 예약 알림을 삭제하시겠습니까?"),
138                        actions: <Widget>[
139                          TextButton(
140                            child: const Text("예"),
141                            onPressed: () {
142                              markedDays.remove(selectedDay);
143                              saveMarkedDays();
144                              Navigator.of(context).pop();
145                            },
146                          ),
147                          TextButton(
148                            child: const Text("아니오"),
149                            onPressed: (){
150                              Navigator.of(context).pop();
151                            },
152                          ),
153                        ],
154                      ),
155                    );
156                  } else {
157                    DateTime now = DateTime.now();
158                    DateTime notificationTime = selectedDay.subtract(const Duration(days: 2)).add(const Duration(hours: 22, minutes: 20));
159                    if (notificationTime.isBefore(now) || notificationTime.isAtSameMomentAs(now)) {
160                      showDialog(
161                        context: context,
162                        builder: (context) => AlertDialog(
163                          title: const Text("알림 불요"),
164                          content: const Text("해당 날짜의 셔틀 신청 기간입니다.\n지금 바로 셔틀을 신청하세요."),
165                          actions: <Widget>[
166                            TextButton(
167                              child: const Text("확인"),
168                              onPressed: () {
169                                Navigator.of(context).pop();
170                              },
171                            ),
172                          ],
173                        ),
174                      );
175                  } else {
176                    showDialog(
177                      context: context,
178                      builder: (context) => AlertDialog(
179                        title: const Text("알림 예약"),
180                        content: const Text("알림을 예약하시겠습니까?"),
181                        actions: <Widget>[
182                          TextButton(
183                            child: const Text("예"),
184                            onPressed: () {
185                              markedDays.add(selectedDay);
186                              saveMarkedDays();
187                              scheduleAlarm(selectedDay);
188                              Navigator.of(context).pop();
189                            },
190                          ),
191                          TextButton(
192                            child: const Text("아니오"),
193                            onPressed: () {
194                              Navigator.of(context).pop();
195                            },
196                          ),
197                        ],
198                      ),
199                    );
200                  }
201                  //this.focusedDay = selectedDay;
202                  //this.selectedDay = selectedDay;
203                  }
204                });
205              },
206            ),
207            const SizedBox(height: 30),
208
209            const Text('셔틀 예약',
210              style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
211          ]
212        )
213      )
214    );
215  }
216}
이 질문이 도움이 되었나요?
'추천해요' 버튼을 누르면 좋은 질문이 더 많은 사람에게 노출될 수 있어요. '보충이 필요해요' 버튼을 누르면 질문자에게 질문 내용 보충을 요청하는 알림이 가요.
profile picture
익명님의 질문

답변 1

강병진님의 프로필 사진

저는 firebase로만 notification을 구현해봤는데, 안드로이드 에뮬레이터나 애플 시뮬레이터에서는 작동하지않고, 실제 기기에 빌드해야 테스트 가능했습니다. 왠지 같은 이유일 것 같습니다

지금 가입하면 모든 질문의 답변을 볼 수 있어요!

현직자들의 명쾌한 답변을 얻을 수 있어요.

또는

이미 회원이신가요?

목록으로
키워드로 질문 모아보기

실무, 커리어 고민이 있다면

새로운 질문 올리기

지금 가입하면 모든 질문의 답변을 볼 수 있어요!