Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

푸쉬 알림 오류 개선 #374

Merged
merged 7 commits into from
Dec 8, 2022
13 changes: 13 additions & 0 deletions Mogakco/Sources/App/DIContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ final class DIContainer {
repository.chatRoomDataSource = resolver.resolve(ChatRoomDataSourceProtocol.self)
repository.localUserDataSource = resolver.resolve(LocalUserDataSourceProtocol.self)
repository.reportDataSource = resolver.resolve(ReportDataSourceProtocol.self)
repository.pushNotificationService = resolver.resolve(PushNotificationServiceProtocol.self)
return repository
}
container.register(UserRepositoryProtocol.self) { resolver in
Expand Down Expand Up @@ -197,13 +198,25 @@ final class DIContainer {
useCase.tokenRepository = resolver.resolve(TokenRepositoryProtocol.self)
return useCase
}
container.register(SubscribePushNotificationUseCaseProtocol.self) { resolver in
var useCase = SubscribePushNotificationUseCase()
useCase.pushNotificationService = resolver.resolve(PushNotificationServiceProtocol.self)
return useCase
}
container.register(UnsubscribePushNotificationUseCaseProtocol.self) { resolver in
var useCase = UnsubscribePushNotificationUseCase()
useCase.pushNotificationService = resolver.resolve(PushNotificationServiceProtocol.self)
return useCase
}
}

private func registerViewModels() {
container.register(ChatViewModel.self) { resolver in
let viewModel = ChatViewModel()
viewModel.chatUseCase = resolver.resolve(ChatUseCaseProtocol.self)
viewModel.leaveStudyUseCase = resolver.resolve(LeaveStudyUseCaseProtocol.self)
viewModel.subscribePushNotificationUseCase = resolver.resolve(SubscribePushNotificationUseCaseProtocol.self)
viewModel.unsubscribePushNotificationUseCase = resolver.resolve(UnsubscribePushNotificationUseCaseProtocol.self)
return viewModel
}
container.register(ChatListViewModel.self) { resolver in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
import RxSwift

protocol PushNotificationServiceProtocol {
// FCM Token을 이용하여 특정 유저에게 푸쉬 알림을 보내는 API
// FCM Token을 이용하여 특정 유저에게 푸쉬 알림 전송
func send(request: PushNotificationRequestDTO) -> Observable<EmptyResponse>
// 특정 Topic을 구독하고 있는 유저들에게 푸쉬 알림을 보내는 API
// 특정 Topic을 구독하고 있는 유저들에게 푸쉬 알림 전송
func sendTopic(request: PushNotificationRequestDTO) -> Observable<EmptyResponse>
// Topic을 구독하는 API
func subscribeTopic(topic: String)
// Topic 구독
func subscribeTopic(topic: String) -> Observable<Void>
// Topic 구독 해제
func unsubscribeTopic(topic: String) -> Observable<Void>
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,27 @@ struct PushNotificationService: PushNotificationServiceProtocol {
return provider.request(PushNotificationTarget.send(request))
}

func subscribeTopic(topic: String) {
Messaging.messaging().subscribe(toTopic: topic) { error in
if let error = error {
print("Message Subscribe Error \(error)")
} else {
print("Message Subscribe succeeded")
func subscribeTopic(topic: String) -> Observable<Void> {
return Observable.create { emitter in
Messaging.messaging().subscribe(toTopic: topic) { error in
if let error = error {
emitter.onError(error)
}
emitter.onNext(())
}
return Disposables.create()
}
}

func unsubscribeTopic(topic: String) -> Observable<Void> {
return Observable.create { emitter in
Messaging.messaging().unsubscribe(fromTopic: topic) { error in
bumssooooo marked this conversation as resolved.
Show resolved Hide resolved
if let error = error {
emitter.onError(error)
}
emitter.onNext(())
}
return Disposables.create()
bumssooooo marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Expand Down
10 changes: 1 addition & 9 deletions Mogakco/Sources/Data/Repositories/ChatRoomRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,6 @@ struct ChatRoomRepository: ChatRoomRepositoryProtocol {
.map { $0.documents.map { $0.toDomain() } }
.map { $0.filter { ids.contains($0.id) } } ?? .empty()

// 채팅방 푸쉬 알림 구독
chatRoomsSb
.subscribe(onNext: {
$0.forEach {
self.pushNotificationService?.subscribeTopic(topic: $0.id)
}
})
.disposed(by: disposeBag)

// 최근 메세지 호출
let latestChatChatRoomsSb = BehaviorSubject<[ChatRoom]>(value: [])
chatRoomsSb
Expand Down Expand Up @@ -113,6 +104,7 @@ struct ChatRoomRepository: ChatRoomRepositoryProtocol {
request: .init(userIDs: $0.userIDs.filter { $0 != user.id })
) ?? .empty()
}
.flatMap { _ in pushNotificationService?.unsubscribeTopic(topic: chatRoom.id) ?? .empty() }
.map { _ in () } ?? .empty()

let userUpdated = Observable.zip(studyUpdated, chatRoomUpdated)
Expand Down
5 changes: 5 additions & 0 deletions Mogakco/Sources/Data/Repositories/StudyRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct StudyRepository: StudyRepositoryProtocol {
var remoteUserDataSource: RemoteUserDataSourceProtocol?
var chatRoomDataSource: ChatRoomDataSourceProtocol?
var reportDataSource: ReportDataSourceProtocol?
var pushNotificationService: PushNotificationServiceProtocol?
private let disposeBag = DisposeBag()

func list(sort: StudySort, filters: [StudyFilter]) -> Observable<[Study]> {
Expand Down Expand Up @@ -89,6 +90,9 @@ struct StudyRepository: StudyRepositoryProtocol {
.flatMap {
chatRoomDataSource?.create(request: $0) ?? .empty()
}
.flatMap {
pushNotificationService?.subscribeTopic(topic: $0.toDomain().id) ?? .empty()
}

let updateUser = user
.flatMap { user in
Expand Down Expand Up @@ -254,6 +258,7 @@ struct StudyRepository: StudyRepositoryProtocol {
)
) ?? .empty()
}
.flatMap { _ in pushNotificationService?.unsubscribeTopic(topic: id) ?? .empty() }
bumssooooo marked this conversation as resolved.
Show resolved Hide resolved

Observable.combineLatest(
updateUser,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// SubscribePushNotificationUseCaseProtocol.swift
// Mogakco
//
// Created by 김범수 on 2022/12/07.
// Copyright © 2022 Mogakco. All rights reserved.
//

import RxSwift

protocol SubscribePushNotificationUseCaseProtocol {
func excute(topic: String) -> Observable<Void>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// UnsubscribePushNotificationUseCaseProtocol.swift
// Mogakco
//
// Created by 김범수 on 2022/12/07.
// Copyright © 2022 Mogakco. All rights reserved.
//

import RxSwift

protocol UnsubscribePushNotificationUseCaseProtocol {
func excute(topic: String) -> Observable<Void>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// SubscribePushNotificationUseCase.swift
// Mogakco
//
// Created by 김범수 on 2022/12/07.
// Copyright © 2022 Mogakco. All rights reserved.
//

import RxSwift

struct SubscribePushNotificationUseCase: SubscribePushNotificationUseCaseProtocol {

var pushNotificationService: PushNotificationServiceProtocol?

func excute(topic: String) -> Observable<Void> {
return pushNotificationService?.subscribeTopic(topic: topic) ?? .empty()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// UnsubscribePushNotificationUseCase.swift
// Mogakco
//
// Created by 김범수 on 2022/12/07.
// Copyright © 2022 Mogakco. All rights reserved.
//

import RxSwift

struct UnsubscribePushNotificationUseCase: UnsubscribePushNotificationUseCaseProtocol {

var pushNotificationService: PushNotificationServiceProtocol?

func excute(topic: String) -> Observable<Void> {
return pushNotificationService?.unsubscribeTopic(topic: topic) ?? .empty()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,6 @@ final class ChatViewController: ViewController {
navigationController?.isNavigationBarHidden = false
}

override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
navigationController?.isNavigationBarHidden = true
}

override var canBecomeFirstResponder: Bool {
return true
}
Expand All @@ -116,14 +111,19 @@ final class ChatViewController: ViewController {

override func bind() {
let input = ChatViewModel.Input(
viewWillAppear: rx.viewWillAppear.map { _ in () }.asObservable(),
viewWillDisappear: rx.viewWillDisappear.map { _ in () }.asObservable(),
willEnterForeground: NotificationCenter.default
.rx.notification(UIApplication.willEnterForegroundNotification).map { _ in () },
didEnterBackground: NotificationCenter.default
.rx.notification(UIApplication.didEnterBackgroundNotification).map { _ in () },
backButtonDidTap: backButton.rx.tap.asObservable(),
studyInfoButtonDidTap: studyInfoButton.rx.tap.asObservable(),
selectedSidebar: sidebarView.tableView.rx.itemSelected.asObservable(),
sendButtonDidTap: messageInputView.sendButton.rx.tap.asObservable(),
inputViewText: messageInputView.messageInputTextView.rx.text.orEmpty.asObservable(),
pagination: collectionView.refreshControl?.rx.controlEvent(.valueChanged).asObservable()
)

let output = viewModel.transform(input: input)

Driver<[ChatSidebarMenu]>.just(ChatSidebarMenu.allCases)
Expand All @@ -133,9 +133,7 @@ final class ChatViewController: ViewController {
for: IndexPath(row: index, section: 0)) as? ChatSidebarTableViewCell else {
return UITableViewCell()
}

cell.menuLabel.text = menu.rawValue

return cell
}
.disposed(by: disposeBag)
Expand Down
35 changes: 34 additions & 1 deletion Mogakco/Sources/Presentation/Chat/ViewModel/ChatViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ enum ChatRoomNavigation {
final class ChatViewModel: ViewModel {

struct Input {
let viewWillAppear: Observable<Void>
let viewWillDisappear: Observable<Void>
let willEnterForeground: Observable<Void>
let didEnterBackground: Observable<Void>
let backButtonDidTap: Observable<Void>
let studyInfoButtonDidTap: Observable<Void>
let selectedSidebar: Observable<IndexPath>
Expand All @@ -40,6 +44,8 @@ final class ChatViewModel: ViewModel {
var chatRoomID: String = ""
var chatUseCase: ChatUseCaseProtocol?
var leaveStudyUseCase: LeaveStudyUseCaseProtocol?
var subscribePushNotificationUseCase: SubscribePushNotificationUseCaseProtocol?
var unsubscribePushNotificationUseCase: UnsubscribePushNotificationUseCaseProtocol?
private var chatArray: [Chat] = []
var messages = BehaviorRelay<[Chat]>(value: [])
let navigation = PublishSubject<ChatRoomNavigation>()
Expand All @@ -55,6 +61,8 @@ final class ChatViewModel: ViewModel {
let showMemberTap = PublishSubject<Void>()
let refreshFinished = PublishSubject<Void>()

bindPushNotification(input: input)

observeFirebase()
fetchChats()
backButtonDidTap(input: input)
Expand Down Expand Up @@ -123,7 +131,8 @@ final class ChatViewModel: ViewModel {
message: message,
chatRoomID: self.chatRoomID,
date: Date().toInt(dateFormat: Format.chatDateFormat),
readUserIDs: [user.id]
readUserIDs: [user.id],
user: user
),
to: self.chatRoomID
)
Expand All @@ -143,6 +152,30 @@ final class ChatViewModel: ViewModel {
)
}

private func bindPushNotification(input: Input) {
// 채팅방 들어올 시 -> 푸쉬 알림 구독 해제
Observable.merge(
input.viewWillAppear,
input.willEnterForeground
)
.withUnretained(self)
.flatMap { $0.0.unsubscribePushNotificationUseCase?.excute(topic: $0.0.chatRoomID) ?? .empty() }
.subscribe(onNext: { _ in
})
.disposed(by: disposeBag)

// 채팅방 나갈 시 -> 푸쉬 알림 구독
Observable.merge(
input.viewWillDisappear,
input.didEnterBackground
)
.withUnretained(self)
.flatMap { $0.0.subscribePushNotificationUseCase?.excute(topic: $0.0.chatRoomID) ?? .empty() }
.subscribe(onNext: { _ in
})
.disposed(by: disposeBag)
}

private func observeFirebase() {
chatUseCase?.observe(chatRoomID: chatRoomID)
.withLatestFrom(messages) { ($0, $1) }
Expand Down