Flutter로 개발을 하다보면 종종 안드로이드와 ios에서 다르게 동작하는 상황을 마주하게된다.
현재 회사서비스에서는 FCM
과 flutter_local_notifications
을 사용해서 notification을 구현하고 있는데 안드로이드 background에서 notification이 동작하지 않는 것을 확인하였다.
... When received, an isolate is spawned (Android only, iOS/macOS does not require a separate isolate) allowing you to handle messages even when your application is not running. ... FlutterFire > CloudMessaging > Background messages
FCM
문서를 참고하면, ios와 달리 안드로이드에서는 background에서 notification을 받으면 새로운 isolate
에서 동작한다.
따라서 ios와 달리 안드로이드 background에서는 context를 포함해 모든 값에 접근할 수 없다(null이 들어간다).
이 때문에 background에서 notification을 클릭했을 때 router를 사용하거나, notification message를 다국어 처리하기 위해 사용한 context를 읽을 수 없어 원하는대로 동작하지 않았다.
다른 앱에서도 흔히 볼 수 있는 것처럼, 우리 앱에서도 inbox 아이콘이 있고, 새로운 푸쉬 알림이 오면 빨간 점이 새로 떠서 유저에게 확인하지 않은 알림이 있다는 걸 알려준다.
hivebox를 만들어서 새로운 알림이 오는 걸 알려주었는데, 안드로이드에서는 이 hivebox 자체를 열 수가 없다.
앞에서 언급한 것처럼 안드로이드는 별도의 isolate에서 동작하기 때문에 사실상 기존 코드 위에 있는 모든 변수는 사용할 수가 없었다.
그래서 방법을 찾아보던 중에 isolate끼리도 통신을 할 수 있다는 걸 알게 되었다.
먼저 background에서 새로운 notification이 생긴 경우, 처리하는 로직에 다음과 같은 코드를 추가해주었다.
FirebaseMessaging.onBackgroundMessage(_handleBackgroundMessage);
...
Future<void> _handleBackgroundMessage(RemoteMessage event) async {
final notification = event.notification;
...
IsolateNameServer.lookupPortByName('main_port')?.send(inbox);
...
}
'main_port'란 이름의 IsolateNameServer에 새로운 inbox정보를 전달해주었다.
그리고 main_page의 initState에 이 'main_port'를 listen하는 함수를 추가하였다.
background notification에서는 Inbox
라는 모델로 데이터를 전달했기 때문에, 여기서도 타입을 체크해서 일치하는 경우에는 hivebox에 새로운 notification을 set해주도록 하였다.
late ReceivePort receivePort;
@override
void initState() {
...
receivePort = ReceivePort();
IsolateNameServer.registerPortWithName(receivePort.sendPort, 'main_port');
receivePort.listen((dynamic message) {
if (message is Inbox) {
HiveHelper.setHasNewNotification(
context.router.current.name != InboxRoute.name,
);
}
});
...
}
@override
void dispose() {
...
receivePort.close();
...
}
처음에는 막연히 안드로이드만 background에서 아무 데이터도 읽지 못한다고 생각했는데, 공식문서를 찾아보면서 isolate
라는 개념을 처음 알게되었다.
다트의 isolate에 대해서도 다시 찾아보게 되었고, 통신도 가능하다는 것을 알게되었다.
마침 stackoverflow에서 유사한 질문이 있어서 해결방법을 빠르게 찾을 수 있었다.(https://stackoverflow.com/questions/68678778/how-to-save-data-in-hive-database-when-receiving-data-in-the-background)
주로 isolate는 연산이 복잡하거나 api call이 오래걸릴 경우 새로운 isolate를 사용해서 병렬로 처리하기 위한 목적으로 많이 사용하는 것 같다.