Mobile/Flutter

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

펭귄알 2024. 9. 18. 12:15

이번에 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에 대한 지식이 부족했던것 같네요. 큰 현타를 느꼇지만,, 다음에는 이런 실수를 하지않으면 된다고 생각합니다. 오늘도 빡코딩!