이번에 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. 백그라운드 알람 처리
백그라운드 메시지 핸들러
- 익명 함수가 아니어야 합니다.
- 최상위 수준 함수여야 합니다(예: 초기화가 필요한 클래스 메서드가 아님).
- 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에 대한 지식이 부족했던것 같네요. 큰 현타를 느꼇지만,, 다음에는 이런 실수를 하지않으면 된다고 생각합니다. 오늘도 빡코딩!
'Mobile > Flutter' 카테고리의 다른 글
[Flutter] Sentry 적용해보기 (0) | 2024.10.15 |
---|---|
[Flutter] Monorepo 적용해보기(feat. Melos) (0) | 2024.09.26 |
[Flutter] flutter_gen을 이용한 Asset 관리 (0) | 2024.08.13 |
[Flutter] Flutter Flavorizr 를 통한 Flavor 설정 (0) | 2024.08.09 |
[Flutter] 위젯이 생성되기 까지 (0) | 2024.08.08 |