μλ νμΈμ©:)
2020λ 4μμ μμ νλ [flutter] local notification Quick Start μμ μ΄νλ‘
μ΄λ² μ±μλ μλ¦Ό κΈ°λ₯μ μ μ© μμΌμΌν΄μ 2020λ 11μ κΈ°μ€μΌλ‘ λ€μ μμ±ν΄λ³΄λ €ν©λλΉ
https://pub.dev/packages/flutter_local_notifications/install
dependencies:
# notification (20.11.11 κΈ°μ€)
flutter_local_notifications: ^3.0.1+2
NotificationCompat API
λ₯Ό μ¬μ©νμ¬ κ΅¬ν Android μ₯μΉλ₯Ό μ€νν μ μμ΅λλ€.UILocalNotification API
λ₯Ό μ¬μ©ν©λλ€. UserNotification API
λ₯Ό (aka User Notifications Framework)λ iOS 10μ΄μμμ μ¬μ©λ©λλ€.λΌμ΄λΈλ¬λ¦¬ 곡μ μ€λͺ
μ ν리μΌμ΄μ μ AndroidManifest.xmlνμΌ
{flutter App} > android > app > src > main > AppDelegate.swift
<!-- local notification -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
- λΆν μ μλΉμ€(Service) μ€ννκΈ°
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
...
<application
...
>
<activity
...
android:windowSoftInputMode="adjustResize"
android:showWhenLocked="true"
android:turnScreenOn="true">
<intent-filter>
...
</intent-filter>
</activity>
...
<receiver android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" />
<receiver android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
</intent-filter>
</receiver>
...
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>
<activity
...
android:showWhenLocked="true"
android:turnScreenOn="true">
<receiver android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
</intent-filter>
</receiver>
<receiver android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" />
λΌμ΄λΈλ¬λ¦¬ 곡μ μ€λͺ
{flutter App} > ios > Runner > AppDelegate.swift
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
...
) -> Bool {
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
}
...
}
}
iOSλ κΈ°λ³Έμ μΌλ‘ μ΄νμ΄ μ΄λ €μμ λ(=foreground) μλμ΄ μΈλ¦¬μ§ μλλ‘ μ€μ λμ΄μμ΅λλ€.
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
}
β μ μΈμ€ν΄μ€λ₯Ό λ§λ λ€μ κ° νλ«νΌμ μ¬μ©ν μ€μ μΌλ‘ μ΄κΈ°ν μμ
void main() async {
...
_initNotiSetting();
runApp(MyApp());
}
void _initNotiSetting() async {
final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
final initSettingsAndroid = AndroidInitializationSettings('app_icon');
final initSettingsIOS = IOSInitializationSettings(
requestSoundPermission: false,
requestBadgePermission: false,
requestAlertPermission: false,
);
final initSettings = InitializationSettings(
android: initSettingsAndroid,
iOS: initSettingsIOS,
);
await flutterLocalNotificationsPlugin.initialize(
initSettings,
);
}
- μ΄κΈ°νλ ν λ²λ§ μνν΄μΌ νλ©° μ΄λ
main.dart
μμ κΈ°λ₯ μν
(λλ μ±μ νμλ 첫 λ²μ§Έ νμ΄μ§ λ΄μμμ΄ μμ μ μν ν μ μμ΅λλ€.)
requestSoundPermission
trueλ‘ λ³κ²½notificationμ μ€μ
μ½λ μ€λͺ
νκ² μ΅λλ€.UI
SubmitButton(
...
text: 'νμΈ',
onPressed: isDisabled ? null : _dailyAtTimeNotification,
)
onPressed
import 'package:timezone/data/latest.dart' as tz;
import 'package:timezone/timezone.dart' as tz;
Future _dailyAtTimeNotification() async {
final notiTitle = 'title';
final notiDesc = 'description';
final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
final result = await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: true,
badge: true,
sound: true,
);
var android = AndroidNotificationDetails('id', notiTitle, notiDesc,
importance: Importance.max, priority: Priority.max);
var ios = IOSNotificationDetails();
var detail = NotificationDetails(android: android, iOS: ios);
if (result) {
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.deleteNotificationChannelGroup('id');
await flutterLocalNotificationsPlugin.zonedSchedule(
0,
notiTitle,
notiDesc,
_setNotiTime(),
detail,
androidAllowWhileIdle: true,
uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime,
matchDateTimeComponents: DateTimeComponents.time,
);
}
}
tz.TZDateTime _setNotiTime() {
tz.initializeTimeZones();
tz.setLocalLocation(tz.getLocation('Asia/Seoul'));
final now = tz.TZDateTime.now(tz.local);
var scheduledDate = tz.TZDateTime(tz.local, now.year, now.month, now.day,
10, 0);
return scheduledDate;
}
}
schedule()
μ΄ λ²μ μ
μ΄ λλ©΄μ deprecated(μ¬μ©μ€λ¨) λμ΅λλ€.FlutterLocalNotificationsPlugin().zonedSchedule()
λ‘ μ¬μ©νλ©΄λλ€._setNotiTime()
UTC
λ‘ λμ΄μλ€.tz.initializeTimeZones();
νtz.setLocalLocation(tz.getLocation('Asia/Seoul'));
λ₯Ό ν΄μ€μΌνλ€.await FlutterNativeTimezone.getLocalTimezone();
μ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ΄μ©ν΄μ κ°μΈμ μΌλ‘ providerλ‘ κ΄λ¦¬ν΄μ λ°μμ€μ§λ§ λ°λ‘ μ μ§μμλλ°
κ°μΌλ 3.0.1+4 μ΄μ λ²μ μμ AndroidManifest.xml μμ μμ ν΄μΌ λ κ² λ§μ΄ μ€μλ€μ
https://pub.dev/packages/flutter_local_notifications#-android-setup