APP-iOS3rd / PJ3T2_Mymory

멋쟁이사자처럼 iOS 앱스쿨 3기 팀 프로젝트
10 stars 3 forks source link

[Feat] Push notification #146

Closed iAmSomething closed 7 months ago

iAmSomething commented 7 months ago

PR 가이드라인

PR Checklist

PR 날릴 때 체크 리스트

PR Type

어떤 종류의 PR인가요?

연관되는 issue 정보를 알려주세요

Issue Number: N/A

PR 설명하기

Push notification을 개발해보았습니다. 우선 로직은 다음과 같아요!

  1. 30초마다 현재 위치를 가지고 반경 50미터(수정가능)내의 메모들을 fetch
  2. 메모들 중 가장 최신 메모를 하나 가져와서 그 내용을 가지고 UUID를 담아 Push notification 등록
  3. push notification 전송
  4. 클릭 시 UUID를 가지고 다시 메모 fetch
  5. fetch된 메모가 정상적인 경우 navigation으로 메모 디테일 뷰로 이동 이런 순서로 진행됩니다.

어떻게 작동하나요? code 기반으로 설명해주세요

수신할 때

// in LocationsHandler.swift
    ///  Push 서버에 쿼리 날리는 부분입니다. location기준으로 특정 영역(50미터) 이내의 메모들 중 가장 최신 메모를 선택했어요
    /// - Parameters:
    ///   - location : 위치값입니다 CLLocation
    /// - Returns: void, 메모 성공하면 push 를 보냅니다.
    func sendQueryToServer(with location: CLLocation) {
        let content = UNMutableNotificationContent()
        Task{
            do {
                if let memo = try await MemoService.shared.fetchPushMemo(in: location) {
                    content.title = "근처에 새로운 메모가 있어요!"
                    content.body = "\(memo.title)"
                    content.sound = UNNotificationSound.default
                    let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
                    let request = UNNotificationRequest(identifier:memo.id ?? UUID().uuidString, content: content, trigger: trigger)
                    UNUserNotificationCenter.current().add(request) { error in
                        if let error = error {
                            print("푸시 알림 예약 중 오류가 발생했습니다: \(error.localizedDescription)")
                        } else {
                            print("푸시 알림이 예약되었습니다.")
                        }
                    }
                }
            } catch {
                print(error.localizedDescription)
            }

        }
    }
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        ...
        // 서버에 쿼리 날리기 30초에 한번?
        #if DEBUG
        let timer = Timer.scheduledTimer(withTimeInterval: 30, repeats: true) { [weak self] t in
            guard let loc = self?.location else { return }
            self?.sendQueryToServer(with: loc)
        }
        #endif
    }

송신은 여기서 합니다.

// in MyMemoryApp.swift

//MARK: - Push notificaiton 관련
extension AppDelegate: UNUserNotificationCenterDelegate {
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        completionHandler([.banner, .sound, .badge])
    }
    /// Notification 수신하는 부분입니다. 이 부분에서는 Memo uuid를 활용해서 다시 하나의 메모만 fetch해서 넘겨줍니다.
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async {
        let id = response.notification.request.identifier
        do {
            if let memo = try await MemoService.shared.fetchMemo(id: id) {
                print(memo.description)
                PushNotification.shared.memo = memo
            }
        } catch {
            print(error.localizedDescription)
        }
    }
}

여기서 Push 관리를 합니다.


가능하다면 추가해주세요

변경 사항 스크린샷 혹은 화면 녹화

https://github.com/APP-iOS3rd/PJ3T2_Mymory/assets/38745420/bca6f41e-c11a-41c9-b5ea-6da1d2a87d3c

Test 여부

Test 정보

//예시
let testDatas: [TestData] = [.init(...),...]

기타 언급해야 할 사항들