• Grouped notifications

    • 기본적으로 자동으로 그룹화

    • 커스텀 그루핑을 위해서는 Thread Identifier를 사용(기존에 있던 프로퍼티)

      • 기존에는 notification이 왔을 때 기존에 있던 노티피케이션을 업데이트 한다던지 하는데 사용했다.
      let content = UNMutableNotificationContent()
      content.title = "New Photo"
      content.body = "Jane Doe Posted a new Photo"
      content.threadIdentifier = "thread-identifier"
      
      // remote notification
      {
      	"aps" : {
      		"alert" : {
      			"title" : "New Photo",
      			"body" : "Jane Doe posted a new photo",
      			"thread-id": "thread-identifier",
      		},
      	},
      }
      
    • 동작 원리

      • 새로운 노티피케이션 발생
        • thread-identifier가 없는 경우는 기본 앱 그룹으로 간다.
        • thread-identifier가 있는 경우는 커스텀 그룹으로 간다.
          • 앱은 여러개의 커스텀 그룹을 가질 수 있다.
    • 사용자 옵션

      • Automatic - 앱 기본 그룹 + 커스텀 그룹
      • By App - 앱 기본 그룹만 사용
      • Off - 미사용
  • Notification content extensions - iOS 10에 이미 도입되었던 것

    • 현재는 acion이 dynamic하지 않고, 카테고리에 묶여있다는 문제가 있다.

    • 그래서 NSExtensionContext에 notificationActions를 정의하게 되었다.

      extension NSExtensionContext {
      	@avaliable(iOS 12.0, *)
      	var notificationActions: [UNNotificationAction]
      }
      
      class NotificationViewController: UIViewController, UNNotificationContentExtension {
      	func didReceive(_ response: UNNotificationResponse, completionHandler completion: (UNNotificationContentExtensionResponseOption) -> Void) {
      		if response.actionIdentifier == "like-action" {
      			// update state...
      			let unlikeAction = UNNotificationAction(identifier: "unlike-action",
      																							title: "Unlike", options: [])
      			let currentActions = extensionContext?.notificationActions
      			let commentAction = currentActions![1]
      			let newActions = [ unlikeAction, commentAction ]
      			extensionContext?.notificationActions = newActions		
      		}
      	}
      }
      
      • 이제 action을 바꾸기 위해서 카테고리를 아예 바꿀 필요가 없다. 뷰 셋업할 때 아예 할당해놓는 것도 된다.

        func didReceive(_ notification: UNNotification) {
        	// Set up Content extension view...
        	extensionContext?.notificationActions = newActions
        }
        
      • 계층적으로 동작하는 것처럼 보이게도 할 수 있다.

        func didReceive(_ response: UNNotificationResponse,
        								completionHandler completion: (UNNotificationContentExtensionResponseOption) -> Void) {
        	if response.actionIdentifier = "rate-action" {
        		extensionContext?.notificationActions = [ oneStarAction, twoStarAction, threeStarAction ]
        	}
        }
        
      • 아예 액션을 지울 수도 있다.

        func didReceive(_ response: UNNotificationResponse,
        								completionHandler completion: (UNNotificationContentExtensionResponseOption) -> Void) {
        	if response.actionIdentifier = "rate-action" {
        		extensionContext?.notificationActions = [ ]
        	}
        }
        
    • iOS 12부터 Notification Content에서 유저 인터렉션이 허용된다.

      • info.plist에 UNNotificaitonExtensionUserInteractionEnabled 옵션을 YES로 주면 된다.
    • 앱 실행

      • 기존 앱 실행 경로

        • 유저 인터렉션이 안되어 있는 뷰를 터치하는 경우
        • 좌상단 앱 아이콘 터치
        • 앱을 실행하는 Notification action 추가
      • 커스텀 컨트롤로 실행하기 위해, 새로운 API 추가

        • default action: 앱을 실행하고, UserNotificationCenterDelegate의 delegate를 통해서 UNNotificationResponse가 들어옴. 이때 action의 identifer는 UNNotificationDefaultActionIdentifier
        extension NSExtensionContext {
        		@available(iOS 12.0, *)
        		func performNotificationDefaultAction()
        }
        
    • 커스텀 컨트롤로 notification dismiss하기

      • 이 API는 notification을 center에서 없애지는 않는다. 없애는 건 따로 API호출을 해야한다.
      extension NSExtensionContext {
      		@available(iOS 12.0, *)
      		func dismissNotificationContentExtension()
      }
      
  • Notification management

    • 설정에 들어가지 않고도, Notification을 swipe하면 manage가 가능하도록 변경

      • long view로도 진입 가능
      • 종종 관리 suggestion이 뜰 때도 확인 가능
    • Delivery 옵션

      • 기존 옵션은 상세하지만, 라이트 유저에게는 복잡하다.
      • 그래서 간략화 했다.
        • Prominent: 가능한 모든 옵션 활성화
        • Quiet: 노티피케이션 센터에서만 볼 수 있고, 소리도 나지 않는다.
    • 기본 값에 더해, 앱 내에서 커스텀할 수 있도록 엔트리포인트를 제공할 수 있다.

      class AppDelegate: UIApplicationDelegate, UNUserNotificationCenterDelegate {
      	func userNotificationCenter(_ center: UNUserNotificationCenter,
      									openSettingsFor notification: UNNotification? ) {
      		// notification을 통해서 들어왔으면 notification이 있을 것이고
      		// 설정 화면을 통해서 들어왔으면 notifiacation이 nil일 것이다.		
      	}
      }
      
  • Provisional authorization

    • 기존 방법은 사용자가 노티피케이션이 제공하는 것을 보지 못하고 승인 여부를 결정해야 했다.
    • 이제는 사용자 프롬프트 없이도 일단 Quiet로 보내고, 노티피케이션을 보고 사용자가 승인 여부를 거기서 결정할 수 있게 만들 수 있다.
    notificationCenter.requestAuthorization(
    							options: [.badge, .sound, .alert, .provisional]) {
    
    }
    
  • Critical alerts

    • 크리티컬한 Alert이 필요한 카테고리 → 공통적으로 유저의 즉각적인 액션을 요구한다.
      • 의료, 건강
      • 집 보안 관련
      • 공공 안전
    • 이런 중요한 알람은 방해 금지 모드에 상관 없이 동작한다.
    • 소리가 무조건 나게 된다.
    • 이를 사용하기 위해서는 별도의 entitlement를 등록해야 한다.
    • 이 역시도 사용자가 끌 수 있다.
    notificationCenter.requestAuthorization(
    							options: [.badge, .sound, .alert, .criticalAlert]) {
    
    }
    
    // 소리 설정
    let content = UNMutableNotificationContent()
    content.title = "WARNING: LOW BLOOD SUGAR"
    content.body = "Glucose level at 57"
    content.categoryIdentifier = "low-glucose-alert"
    content.sound = UNNotificationSound.defaultCritical
    
    // 커스텀 사운드 설정
    content.sound = .criticalSoundNamed(.init("warning-sound"), withAudioVolume: 1.00)
    
    // push payload
    
    {
    	"aps" : {
    		"sound": {
    			"critical" : 1,
    			"name": "warning-sound.aiff",
    			"volume": 1.0
    		}
    	}
    }