일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- swift 문자
- 스위프트 카메라
- 앱 백그라운드 푸시 데이터 저장
- Swift flutterview
- native flutter view
- 안드로이드 숏컷
- 안드로이드 앨범
- 스위프트
- flutter rotate
- 스위프트 앨범
- 노티피케이션 익스텐션
- 안드로이드 에러
- swift sms
- Swift flutterviewcontroller
- 앱 꺼졌을 때 푸시 데이터 저장
- 플러터 뷰 컨트롤러
- NotificationService Extension
- 스위프트 테이블 뷰 셀
- swift autolayout
- flutter 회전
- 안드로이드 FCM
- FlutterView MethodChannel
- 스위프트 푸시
- Flutter UIKitView MethodChannel
- silent push
- Flutter NativeView
- 푸시 데이터 저장
- 스위프트 웹뷰
- 안드로이드 바로가기
- 스위프트 UserDefaults
- Today
- Total
Things take time
[SWIFT] NotificationService Extension사용하기, Remote Notification(Silent Push)대신 사용하기, 백그라운드 푸시, 푸시 데이터 저장하기 본문
[SWIFT] NotificationService Extension사용하기, Remote Notification(Silent Push)대신 사용하기, 백그라운드 푸시, 푸시 데이터 저장하기
겸손할 겸 2022. 6. 8. 13:24[개요]
기본적으로 사용자가 푸시를 받았을 때, 포어그라운드 상태라면 AppDelegate내 함수에서 처리할 수 있다.
만약 서버쪽에서 사용자에게 푸시를 보냈을때, 특정 값을 저장 했다가 앱이 실행될 때 해당 값을 검사하여 원하는 작업을 수행하길 원한다고 하자. 포어그라운드 상태라면 위의 didReceive함수(ios 10미만의 경우, application의 didReceiveRemoteNotification일 것이고 이상인 경우 userNotification의 willPresent, didReceive)에 UserDefaults등을 활용하여 MainViewController나 특정 뷰에서 처리하면 된다.
그렇다면, 사용자가 앱을 끈 상태(inactive)거나 백그라운드(background)상태일 때는 어떻게 할 것인가?
기본적으로 iOS는 백그라운드 작업을 지원하지않는다.
다만, 여기에 추가적으로 애플이 허용한 앱 혹은 설정에 따라 백그라운드 오디오, fetch, remote notification 등을 지원하는데 여기서 고려해볼 만한 것은 Silent Push, 무음 푸시라하여 Background Mode 내 Remote Notification기능을 활성화하는 것이다.
[사일런트 푸시]
이 기능의 경우, 사용자는 푸시를 볼 수 없다. 그러므로 사용자 입장에서는 푸시에 대해 신경 쓸 필요가 없이 특정한 기능을 사용할 수 있다.
그러나 이 기능의 경우 단점이 많은데, 대표적인 예가 푸시발송을 100% 보장하지 않으며, 잦은 푸시를 사용할 경우도 권장하지 않는 등의 단점이 있다.
사용자는 서버가 푸시를 발송했을 때 알지 못한다. 그러나 앱은 알 수 있다.
AppDelegate내 함수 중 applicatiom(didReceiveRemoteNotification)함수에서 알 수 있는데, 이 함수는 iOS10 미만의 푸시 접수 함수이기도 하지만, 사일런트 푸시 수신시에도 호출된다.
사일런트 푸시의 경우, 아래의 조건과 서버 측의 apns payload 양식이다.
{
"aps" : {
"content-available" : 1
},
"acme1" : "bar",
"acme2" : 42
}
출력(applicatiom(didReceiveRemoteNotification))
didReceiveRemoteNotification userInfo: [AnyHashable("acme2"): 42, AnyHashable("acme1"): bar, AnyHashable("aps"): {
"content-available" = 1;
}]
** 참고 : 알림 전송 시 payload 양식(payload guide)
사일런트 푸시가 안좋은것은 아니다. 용도에 맞춰서 써야하는게 가장 기본이므로, 시간당 몇 개를 못보낸 다는 이유로 나는 사일런트 푸시 대신 다른 방법을 택했다.
[NotificationService Extension]
이제 새로운 타겟인 익스텐션을 추가해야한다. iOS에서는 다양한 익스텐션이 존재하는데, 예를 들어 설명하자면 웹페이지에서 공유하기를 클릭 했을 때, 카카오톡을 선택하면 카카오톡이 열리면서 친구목록/대화목록 화면이 나오는 것을 알 수 있다. 근데 이 화면은 일반적으로 카카오톡을 켰을때 나오는 화면이랑 다른 화면이다. 즉, 공유하기를 통해 왔을 때 사용자에게 새로운 화면을 중간에 넣어서, 그 화면내에서 독립적인 처리를하는 것인데, 이는 Share Extension이라하며 익스텐션 중 한 종류다.
NotificationService Extension이란 기본적으로 사용자에게 푸시 노티를 띄우기 전에 껴드는 것이다. Share의 경우에도 중간에 껴드는 것처럼 같은 맥락으로 이해하면 된다. 푸시를 이쁘게(?) 보내는 앱들을 보면, 노티 안에 그림도 들어가고 클릭 했을 때 이벤트도 있고 하는 경우가 이 익스텐션을 사용한 경우인데, 나의 경우에는 노티를 꾸미기 위해 사용하는 것이 아니라, inactive/background 상태일 때 푸시를 받고, 그 때 푸시 데이터를 저장하여 AppDelegate에서 뷰로 전달하기 위해 사용하는 용도이므로, UI에 대한 설명은 생략한다.
위의 절차를 통해 생성했을 경우, 아래처럼 새로운 디렉토리와 Target도 추가된다.
NotificationService.swift라는 파일이 생성이 되는데, 이 안에는 didReceive함수와 serviceExtensionTimeWillFire함수가 있다.
didReceive의 경우가 실제 원하는 기능을 구현할때 사용한다. 후자의 경우, 익스텐션이 시스템에의해 사라질때 호출된다는데, 딱히 검증하지 않았다. AppGroupsName은 개발사이트 내 AppGroups에서 생성한 이름이다. 모르겠으면 아래 참고.
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
if let bestAttemptContent = bestAttemptContent {
// Modify the notification content here...
bestAttemptContent.title = "G-Y-E-O-M"
bestAttemptContent.body = "B-O-D-Y"
if let userDefault = UserDefaults(suiteName: "AppGroupsName"){
let randomNum = Int.random(in: 0...100)
userDefault.set(randomNum, forKey: "test")
userDefault.synchronize()
}
contentHandler(bestAttemptContent)
}
}
함수 부분을 보자, UNMutableNotificationContent 타입의 변수인 bestAttemptContent의 title, body 속성을 변경하면 푸시 노티를 아래와 같이 변경할 수 있다. 이미지 관련 부분도 속성 중 하나일 것이다.
어쨌든, 중요한 것은 그쪽이 아니고 아래의 userDefault이다. 즉, appGroups로 지정한 UserDefaults의 경우, 실제 저장 장소가 다른 본 앱과 익스텐션 사이의 데이터를 공유할 수 있다. 여기에서 푸시를 받았을 때 노티를 띄우기 전 저장을하고, 본앱의 AppDelegate + ViewControllers에서 가져다 쓰면 된다.
위의 사일런트 푸시의 경우 "content-available" : 1가 들어갔다면, 노티피케이션서비스 익스텐션의 경우 "mutable-content": 1 가 들어가야한다. 예시로 보낸 페이로드의 경우 다음과 같다.
{
"aps":{
"sound":"default",
"mutable-content": 1,
"alert":{
"body":"body message"
}
}
}
** AppGroups 등록 방법
AppGroups의 경우 Xcode내에서도 다음과 같이 각각의 Target에서 AppGroups를 +Capability를 눌러서 세팅해야한다.
그런데 AppGroups가 보이지 않는다면
1. https://developer.apple.com
2. account
3. 로그인
4. Identifiers
5. + 버튼
생성 후 Xcode에서 AppGroups reload하면 끝이다.
어쨌든, 익스텐션의 didReceive에서 저장이 되었다면 아래와 같이 appDelegate에서 확인할 수 있다.(예)
func applicationDidBecomeActive(_ application: UIApplication) {
print("applicationDidBecomeActive")
if let groupUserDefaults = UserDefaults(suiteName: "AppGroupsName"){
print("applicationDidBecomeActive : => \(groupUserDefaults.value(forKey: "test"))")
}
}
이렇게 하면 아래와 같이 출력되는 걸 확인할 수 있다.
applicationDidBecomeActive : => Optional(90)
** didReceive에서 print출력 방법
일단, 익스텐션의 경우 자체 print로 넣는다고 출력되지 않는다. 현재 실행한 타겟은 본앱이기 때문인데, 나는 검수를 꼭 해보고 싶다면 아래와 같이 한다. (NotificationExtension이 본앱, NotificationService가 익스텐션(옆에 E버튼))
디버그 실행을 익스텐션인 NotificationService로 시작하고 앱을 선택하는 것에서는 NotificationExtension로 한다. 그리고 d푸시를 발송하고, didReceive에 print문이 정상 출력되는지 확인한다.
'iOS (기능)' 카테고리의 다른 글
[SWIFT] (이것저것) viewDidLoad는 메모리에 할당될 때 호출된다. (0) | 2022.06.28 |
---|---|
[SWIFT] URL형식으로 된 String에서 Parameter 추출 (0) | 2021.11.19 |
[SWIFT] Https 인증서 관련 우회 방법(Webview, API(Http통신/Alamofire) (0) | 2021.07.30 |
[SWIFT] 오디오 감지를 위한 옵저버 AVSystemController_SystemVolumeDidChangeNotification 사용 불가(iOS15) (1) | 2021.07.05 |
[SWIFT] CornerRadius 상단, 하단 특정 위치에만 주기 (0) | 2021.06.23 |