ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Flutter]플러터 flutter_local_notifications |안드로이드, IOS
    Flutter_끄적끄적 2022. 3. 13. 07:14

    오랜만에 flutter_local_notifications 패키지를 사용하면서 많은 자료가 없어서 정리해본다

    Flutter Local Notification 이란?

    먼저 flutter_local_notifications라는 패키지는 앱에서 특정 메시지를 보내 사용자에게 알림을 전해주는 패키지다.

    보통 firebase를 통해서 FCM을 많이 사용하지만, 어째든 firebase를 통해 메세지를 전달하는건 네트워크 트래픽이 발생하고 서비스 규모가 커지면 매번 네트워크 트래픽을 발생하기에는 비용적인 부담도 있다.

     

    flutter_local_notifications라는 패키지는 말그대로, 로컬단 앱에서 사용자에게 특정 메세지를 보내 알림 처리를 할 수 있다.(네트워크 트래픽 발생X) 그럼 사용방법을 정리해본다.

     

    P.S 이미 flutter local notifications 가이드는 구글링 해보면 정보가 있지만, 패키지 버전이 업데이트 되면서 사용방법이 약간씩 다르다. (2022년 03월 기준)

     

    • 사용 패키지
    flutter_local_notifications: ^9.4.0

     

    • 안드로이드 권한 및 옵션 세팅 [해당프로젝트]-> android-> app-> src-> main-> AndroidManifest.xml
      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        ....
        
          <!--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" />
          <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
          <!--local notification 권한 설정-->
          
         <application
         
              .............
              
              </activity>
      
             <!--local notification 재부팅 및 업데이트 시에도 작동하기 위해 설정-->
             <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>
             <!--local notification 재부팅 및 업데이트 시에도 작동하기 위해 설정-->
             
              <meta-data
                  android:name="flutterEmbedding"
                  android:value="2" />
          </application>
      </manifest>

    AndroidManifest.xml에서 추가해야하는 코드이다.

    기본적으로 알림 메세지를 이용하기 위해 필요한 권한과 사용자의 휴대폰이 재부팅 및 업데이트 시 작동하기 위한 옵션들이다(주석 참조)

     

    • IOS 권한 및 옵션 세팅 [해당프로젝트]-> ios-> Runner-> AppDelegate.swift
    @UIApplicationMain
    @objc class AppDelegate: FlutterAppDelegate {
      override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
      ) -> Bool {
        <!-- 이 부분 추가-------------------------->
        if #available(iOS 10.0, *) {
          UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
        }
        <------------------------------------------->
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
      }
    }

    IOS 특성상 foreground에서는 알림이 작동되지 않도록 설정되어있다.

    위 옵션으로 foreground이 작동되도록 설정한다.

     

     

    • main.dart 에서 초기 설정
      void main() async{
        WidgetsFlutterBinding.ensureInitialized();
        await _initNotiSetting();//local Notifcation 초기 설정
        runApp(MyApp());
      }
      
      //local Notification 함수
      Future<void> _initNotiSetting() async {
        //Notification 플로그인 객체 생성
        final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
        
        //안드로이드 초기 설정 (위에서 만든 아이콘도 같이 등록)
        final AndroidInitializationSettings initSettingsAndroid = AndroidInitializationSettings('ic_launcher');
        
        //IOS 초기 설정(권한 요청도 할 수 있음) request...값을 true로 설정 시 앱이 켜지자마자 권한 요청을 함
        final IOSInitializationSettings initSettingsIOS = IOSInitializationSettings(
          requestSoundPermission: false, requestBadgePermission: false, requestAlertPermission: false);
        
        //Notification에 위에서 설정한 안드로이드, IOS 초기 설정 값 삽입
        final InitializationSettings initSettings = InitializationSettings(android: initSettingsAndroid, iOS: initSettingsIOS,);
        
        //Notification 초기 설정
        //onSelectNotification 옵션을 넣어서 메세지를 누르면 작동되는 콜백 함수를 생성 할 수 있다.(안써도됨)
        await flutterLocalNotificationsPlugin.initialize(initSettings,onSelectNotification:[콜백] );
      }
      class MyApp extends StatelessWidget {
        const MyApp({Key? key}) : super(key: key);
      
        @override
        Widget build(BuildContext context) {

    안드로이드 초기 설정과 IOS 초기 설정은 서로 다름

    안드로이드에서는 알림 메세지를 보낼때 AndroidManifest.xml에서 권한 설정을 마무리.

    IOS는 사용자에게 별도로 허가를 받아야한다. 때문에, 초기 설정 시

    requestSoundPermission, requestBadgePermission, requestAlertPermission 설정이 필요하다.

    (본인은 앱이 실행되자마자, 권한을 얻기 보다 특정 버튼을 누르면 권한을 요청하는 구조로 가기 때문에 false를 등록해둔 것이니 알아서 잘 사용하도록 합시다!)

     

    • Notification 사용하기
      // ignore_for_file: prefer_const_declarations
      import 'dart:io';
      
      import 'package:flutter_local_notifications/flutter_local_notifications.dart';
      import 'package:timezone/data/latest.dart' as tz;
      import 'package:timezone/timezone.dart' as tz;
      
      Future ClockTimeNotification() async {
        final notiTitle = 'title'; //알람 제목
        final notiDesc = 'description'; //알람 내용
        final result;//권한 확인을 위한 변수
        //----------------------------------------------------------------------------------
        //local notification 플러그인 객체 생성
        final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
      
        //플랫폼 확인해서 OS 종류에 따라 권한 확인
        //안드로이드 일때
        if(Platform.isAndroid){
          result=true;
        }
        //IOS 일때
        else{
          result = await flutterLocalNotificationsPlugin
              .resolvePlatformSpecificImplementation<
              IOSFlutterLocalNotificationsPlugin>()
              ?.requestPermissions(
            alert: true,
            badge: true,
            sound: true,
          );
        }
        //----------------------------------------------------------------------------------
        //안드로이드 Notification 옵션
        var android = AndroidNotificationDetails('id', notiTitle,
            channelDescription: notiDesc,
            importance: Importance.max,
            priority: Priority.max,
            color: const Color.fromARGB(255, 255, 0, 0)); //여기color는 Notification Icon 배경색
            
        //IOS Notification 옵션
        var ios = IOSNotificationDetails();
      
        //Notificaiton 옵션 값 등록
        var detail = NotificationDetails(android: android, iOS: ios);
      //----------------------------------------------------------------------------------
        //권한이 있으면 실행.
        if (result==true) {
          await flutterLocalNotificationsPlugin
              .resolvePlatformSpecificImplementation<
                  AndroidFlutterLocalNotificationsPlugin>()
              ?.deleteNotificationChannelGroup('id');
      
          await flutterLocalNotificationsPlugin.zonedSchedule(
            0, // 스케줄 ID(고유)
            notiTitle, //알람 제목
            notiDesc, //알람 내용
            _setNotiTime(), //알람 시간
            detail,
            androidAllowWhileIdle: true,
            uiLocalNotificationDateInterpretation:
                UILocalNotificationDateInterpretation.absoluteTime,
            //이 옵션은 중요함(옵션 값에따라 시간만 맞춰서 작동할지, 월,일,시간 모두 맞춰서 작동할지 옵션 설정
            //아래와 같이 time으로 설정되어있으면, setNotTime에서 날짜를 아무리 지정해줘도 시간만 동일하면 알림이 발생
            matchDateTimeComponents: DateTimeComponents.time,//또는dayOfMonthAndTime
          );
        }
      }
      
      //알람 시간 세팅
      tz.TZDateTime _setNotiTime() {
        tz.initializeTimeZones();//TimeZone Database 초기화
        tz.setLocalLocation(tz.getLocation('Asia/Seoul'));//TimeZone 설정(외국은 다르게!)
        final now = tz.TZDateTime.now(tz.local);
        var scheduledDate = tz.TZDateTime(tz.local, now.year, now.month, 13, 06, 30);//알람 시간
        //var test = tz.TZDateTime.now(tz.local).add(const Duration (seconds: 5));
        print('-----------알람 시간 체크----${scheduledDate.toString()}');
        return scheduledDate;
      }

      위 생성한 Notification 객체를 이제 특정 버튼을 누르거나 특정 페이지를 불러올때 사용하면된다.
      보통 Provider에 넣어서 사용하면 된다.

      코드 내용 중 result값에서 Android는 그냥 true를 줬지만 IOS에서는 권한을 확인하는 로직이 있다.
      이유는 안드로이드는 별도의 사용자 권한을 허가 받지않아도되지만, IOS는 반드시 사용자에게 권한을 허가 받도록 해야하기 때문이다.

    끄으읏!

    댓글

Devksr