본문 바로가기
Mobile/Flutter

[Flutter] FCM 메세지 수신시 알람음 변경하기(Android)

by 펭귄알 2024. 9. 18.

이번에 FCM 수신시에 알람음을 변경하는 방법을 삽질해보았는데, 작은 실수로 삽질을 오래하고있었습니다...(channelId를 설정안함)

 

 

우선 FCM알람음을 변경하기 위해서는 서버와 클라이언트 모두 작업을 해줘야합니다.

1. Sound 추가

우선 사용하고자 하는 알람음 파일을 /res/raw 경로에 추가해줍니다.

2. 추가한 Sound파일이름을 payload에 추가

/res/raw에 추가한 파일의 이름을 추가합니다 (확장자는 불필요함)

{
  "data": {
    "data" : "string",
  },
  "notification": {
    "title": "title",
    "body": "body",
    "android": {
      "channelId": null,
      "clickAction": null,
      "color": null,
      "count": null,
      "imageUrl": null,
      "link": null,
      "priority": 0,
      "smallIcon": null,
      "sound": "warning",
      "ticker": null,
      "tag": null,
      "visibility": 0
    },
    "apple": null
  }
}

 

3. 채널 생성

저는 기본 채널과 경고음을 출력할 두가지 채널을 생성해주겠습니다.

이 채널은 Foreground, Background 두가지에서 공통으로 사용되는 채널입니다.

final AndroidNotificationChannel defaultNotificationChannel = const AndroidNotificationChannel(
  'default_channel',
  '일반 알림',
  importance: Importance.high,
);

final AndroidNotificationChannel warningNotificationChannel = const AndroidNotificationChannel(
  'warning_channel',
  '경고 알림',
  importance: Importance.max,
  playSound: true,
  sound: RawResourceAndroidNotificationSound('warning'),
);

 

그리고 위에서 추가한 알람 채널들은 앱 설정에 알람 -> 알람 카테고리로 가면 해당 내용들이 나옵니다!

 

4. 백그라운드 알람 처리 

 

백그라운드 메시지 핸들러 

  1. 익명 함수가 아니어야 합니다.
  2. 최상위 수준 함수여야 합니다(예: 초기화가 필요한 클래스 메서드가 아님).
  3. Flutter 버전 3.3.0 이상을 사용하는 경우 메시지 핸들러는 함수 선언 바로 위에 @pragma('vm:entry-point')로 주석을 달아야 합니다(그렇지 않으면 출시 모드의 경우 트리 쉐이킹 중에 삭제될 수 있음).

이 함수는 main.dart에 정의해두었으며, main함수실행시에 onBackgroundMessage에 전달되어야합니다.

@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
}

 

5.  포그라운드 알람 처리

아래 설정은 Foreground 에서 알람 표시시에 앱 아이콘 및 알람에 대한 전반적인 설정을 바꿀수 있으며 클릭시 실행할 수 있는 행동 정의가 포함되어있습니다. 

 

resolvePlatformSpecificImplematation 매서드를 통해 3번에서 생성한 채널들에 등록해줍니다.

 

Future<void> _localNotificationInit() async {
  flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
  const AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings(
    'mipmap/launcher_icon',
  );
  const DarwinInitializationSettings initializationSettingsDarwin = DarwinInitializationSettings();
  const InitializationSettings initializationSettings = InitializationSettings(
    android: initializationSettingsAndroid,
    iOS: initializationSettingsDarwin,
  );
  await flutterLocalNotificationsPlugin.initialize(
    initializationSettings,
    onDidReceiveNotificationResponse: (NotificationResponse message) {
      Map<String, dynamic> data = jsonDecode(message.payload!);
      handleNotification(Constants.navState.currentContext!, true, data);
    },
  );
  await flutterLocalNotificationsPlugin
      .resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
      ?.createNotificationChannel(defaultNotificationChannel);
  await flutterLocalNotificationsPlugin
      .resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
      ?.createNotificationChannel(warningNotificationChannel);
}

 

 
 

그리고 아래 함수가 실질적으로 Foreground Message 수신시에 실행되는 함수 입니다. 이 함수에서는 message안에 data에서 타입에 따라 다른 알람을 보여주도록 설정해두었으며, 알람음도 다르게 설정해두었습니다.(위에 설정한 채널들의 값을 가져옴)

//알림 표시 및 Route (Android Notification 수신시)
void _showNotification(RemoteMessage message) {
  RemoteNotification? notification = message.notification;
  if (notification == null) {
    return;
  }
  if (message.data["type"] == "WARNING") {
    flutterLocalNotificationsPlugin.show(
      notification.hashCode,
      notification.title,
      notification.body,
      NotificationDetails(
        android: AndroidNotificationDetails(
          warningNotificationChannel.id,
          warningNotificationChannel.name,
          sound: warningNotificationChannel.sound,
          importance: Importance.max,
        ),
      ),
      payload: jsonEncode(message.data),
    );
  } else {
    flutterLocalNotificationsPlugin.show(
      notification.hashCode,
      notification.title,
      notification.body,
      NotificationDetails(
        android: AndroidNotificationDetails(
          defaultNotificationChannel.id,
          defaultNotificationChannel.name,
          importance: Importance.high,
        ),
      ),
      payload: jsonEncode(message.data),
    );
  }
}

 

그리고 마지막으로 포그라운드 메세지를 수신하는 Listener만 추가해주면 설정이 완료됩니다.

FirebaseMessaging.onMessage.listen((RemoteMessage message) {
  _showNotification(message);
});

 


알람음 설정 이외에도 알람 클릭시 화면 이동등 상호작용을 추가할 수 있는데요 그 내용은 다음 글에서 다뤄보겠습니다.

주요한 기능은 아니지만, 해당 내용을 구현하면서 Android Native에 대한 지식이 부족했던것 같네요. 큰 현타를 느꼇지만,, 다음에는 이런 실수를 하지않으면 된다고 생각합니다. 오늘도 빡코딩!