๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐ŸŽ iOS

[iOS] Notification Service Extension์™€ Firebase ์ •๋ฆฌ

by ํ‹ด๋”” 2022. 6. 15.
๋ฐ˜์‘ํ˜•

[Emmanuel Jason Eliphalet] https://www.pexels.com/ko-kr/photo/9956765/

UNNotificationServiceExtension

์›๊ฒฉ ํ‘ธ์‹œ ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜์˜ ์ปจํ…์ธ ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๊ฐ์ฒด. ์‚ฌ์šฉ์ž์—๊ฒŒ ์ „๋‹ฌ๋˜๊ธฐ ์ „์— ์ˆ˜ํ–‰๋จ

class UNNotificationServiceExtension : NSObject
  • notification service ์•ฑ ๊ธฐ๋Šฅ ํ™•์žฅ => ์‚ฌ์šฉ์ž์—๊ฒŒ remote notification ์ด ์ „๋‹ฌ๋˜๊ธฐ ์ด์ „์— ์ปจํ…์ธ ๋ฅผ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ
  • UI๋ฅผ ๊ฐ€์ง€์ง€ ์•Š์Œ
  • notification ์ด ์‚ฌ์šฉ์ž์˜ ๊ธฐ๊ธฐ์— ์ „๋‹ฌ๋˜๋ฉด ๋Ÿฐ์นญ๋จ
  • notification ์˜ ๋‚ด์šฉ์„ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ์ด๋ฏธ์ง€, ๋น„๋””์˜ค ๋“ฑ์„ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ ์•”ํ˜ธํ™” ํ˜น์€ ๋ณตํ˜ธํ™”๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜๋„ ์žˆ์Œ
  • silent notification, ์‚ฌ์šด๋“œ๋งŒ ์žฌ์ƒ์‹œํ‚ค๊ธฐ, ์•ฑ ์•„์ด์ฝ˜์— ํ‘œ์‹œ๋˜๋Š” ๋ฑƒ์ง€๋Š” ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€
  • UNNotificationServiceExtension์„ ์ง์ ‘ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ target์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์‚ฌ์šฉํ•จ
  • target์„ ์ถ”๊ฐ€ํ•˜๋ฉด UNNotificationServiceExtension์˜ ์„œ๋ธŒ ํด๋ž˜์Šค๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฉฐ ์ด๋ฅผ ์ˆ˜์ •ํ•˜์—ฌ ์‚ฌ์šฉํ•จ
  • ์•ฑ์ด remote notification์„ ๋ฐ›์Œ -> ์‹œ์Šคํ…œ์ด UNNotificationServiceExtension์˜ didRecive(_:withContentHandler:) ๋ฉ”์†Œ๋“œ๋ฅผ ๋กœ๋“œํ•จ

ํƒ€๊ฒŸ ์ถ”๊ฐ€ํ•˜๊ธฐ

  • File > New > Target ์„ ์ˆœ์„œ๋Œ€๋กœ ์„ ํƒํ•˜์—ฌ Target์„ ์ถ”๊ฐ€ํ•ด ์คŒ ๋˜๋Š” xcodeproj์—์„œ ํ•˜๋‹จ์— + ๋ฒ„ํŠผ ๋ˆŒ๋Ÿฌ์„œ ์ถ”๊ฐ€

  • Notification Service Extension ์„ ํƒ 

  • Product Name๊ณผ Team ์„ค์ • ํ›„ Finish ์„ ํƒ. Language๋Š” obj-c ์„ ํƒ ๊ฐ€๋Šฅ

 

ํƒ€๊ฒŸ ์„ค์ •ํ•˜๊ธฐ

  • ๋นŒ๋“œ ํ•˜์ง€ ๋ง๊ณ  xcodeproj ์—์„œ ์ถ”๊ฐ€ํ•ด ์ค€ notification service target ์„ ํƒ ํ›„ Automatically manage signing ์ฒดํฌ ํ•ด์ง€ (์ฒดํฌ ํ•ด ๋†“์œผ๋ฉด Bundle Identifier๋ถ€ํ„ฐ Provisioning Profile๊นŒ์ง€ ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋จ ) 
  • ๋ฐ”๋กœ ๋ฐ‘์— ๋‚ด์šฉ์€ ์ˆ˜๋™ ์ƒ์„ฑ์‹œ ์ฐธ๊ณ 

  • ๋ฐ”์ด๋„ˆ๋ฆฌ ์ด์Šˆ ๋•Œ๋ฌธ์— ์•ฑ ์‹ฌ์‚ฌ ์•ˆ์˜ฌ๋ผ๊ฐ => Automatically manage signing ์ฒดํฌ ํ•˜๋ฉด ์ž๋™์œผ๋กœ ํ”„๋กœ๋น„์ €๋‹ ํ”„๋กœํŒŒ์ผ์„ ์„ค์ •ํ•ด ์คŒ

  • ๋งŒ์•ฝ ์ˆ˜๋™์œผ๋กœ ์„ค์น˜ํ–ˆ๋‹ค๋ฉด developer.apple.com > Identifiers > notification service extension identifiers ์„ ํƒ > Capabilities ์ถ”๊ฐ€  
  • ํ™•์ธํ•ด ๋ณด๋‹ˆ Push Notifications๋ฅผ ํฌํ•จ์‹œํ‚ค์ง€ ์•Š์•„๋„ ๋จ

  • save > confirm ๋ˆ„๋ฅด๋ฉด ๊ธฐ์กด์— ์ƒ์„ฑํ•ด ๋‘์—ˆ๋˜ provisioning profile์ด invoke ๋จ

  • ํ”„๋กœ์ ํŠธ๋กœ ๋Œ์•„์™€์„œ Notification Service Extension Target ์„ ํƒ > ์ƒ๋‹จ์— + ๋ฒ„ํŠผ ๋ˆŒ๋Ÿฌ์„œ Capabilities ์ถ”๊ฐ€ > Push Notifications ์„ ํƒ
  • ํ™•์ธํ•ด ๋ณด๋‹ˆ Notification Service์— Push Notifications Capabilities๋Š” ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์•„๋„ ๋จ

โญ ์ค‘์š” โญ

  • target ์„ ํƒ๋œ ์ƒํƒœ์—์„œ General ํƒญ์œผ๋กœ ์ด๋™
  • Identity์—์„œ version build๋Š” ์•ฑ ๋ฒ„์ „ ๋”ฐ๋ผ๊ฐ€์•ผ ํ•จ. ๋นŒ๋“œ๋‚˜ ๊ฐœ๋ฐœ์—์„œ run์€ ์ •์ƒ ๋™์ž‘ํ•˜์ง€๋งŒ ์•ฑ ์Šคํ† ์–ด์— ์—…๋กœ๋“œํ•  ๋•Œ ๋ฌธ์ œ ์ƒ๊น€
  • ๊ผญ Deployment Info ๋ฒ„์ „์ด ์•ฑ์—์„œ ์„ค์ •ํ•œ OS ๋ฒ„์ „๊ณผ ๊ฐ™์€์ง€ ํ™•์ธ

Bundle Identifier์™€ Provisioning Profile ์ƒ์„ฑํ•˜๊ธฐ

  • developer ์‚ฌ์ดํŠธ์— ๋กœ๊ทธ์ธ ํ›„ Certificates, Identifiers & Profiles ํ•ญ๋ชฉ์—์„œ  Identifiers ์„ ํƒ

  • + ๋ฒ„ํŠผ ๋ˆŒ๋Ÿฌ์„œ Bundle Identifier ์ถ”๊ฐ€

  • App IDs ์„ ํƒ ํ›„ Continue ์„ ํƒ -> App ์„ ํƒ ํ›„ Continue 

  • Description์™€ Bundle ID ์ž‘์„ฑ
  • โญ ์ด๋•Œ Bundle ID๋Š” ์•ฑ์˜ ๋ฒˆ๋“ค ์•„์ด๋””๊ฐ€ com.test.app ์ด์—ˆ๋‹ค๋ฉด com.test.app.XXXX ์ด๋ ‡๊ฒŒ prefix๋ฅผ ๋”ฐ๋ผ๊ฐ€์•ผํ•จ (XXXX ๋ถ€๋ถ„์€ ์›ํ•˜์‹œ๋Š” ์ด๋ฆ„์œผ๋กœ ํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค)

  • โญ ๋งŒ์•ฝ com.test.app.XXXX.XXXX ์ด๋ ‡๊ฒŒ dot์ด ๋‘ ๋ฒˆ ๋“ค์–ด๊ฐ€๋Š” ๊ฒฝ์šฐ ์•ฑ ์Šคํ† ์–ด ์˜ฌ๋ฆด ๋•Œ Bad Identifier ๊ฒฝ๊ณ  ๋ฐœ์ƒํ•จ (๋ฏธ๋ฆฌ ์ข€ ์•Œ๋ ค์ฃผ์ง€ ์• ํ”Œ...)

  • Bundle ID ์ƒ์„ฑ ํ›„ provisioning profile ์ƒ์„ฑ (๊ธฐ์กด ์•ฑ์˜ provisioning profile ์ƒ์„ฑ๊ณผ ๋™์ผ)

  • ๊ฐœ๋ฐœ์—์„œ๋Š” iOS App Development, ์•ฑ์Šคํ† ์–ด ์˜ฌ๋ฆด ๋•Œ App Store ์ƒ์„ฑํ•ด ์ฃผ๋ฉด๋จ(๊ธฐ์กด ์•ฑ provisioning profile ์ƒ์„ฑ๊ณผ ๋™์ผ)

  • App ID์—์„œ ๋ฐฉ๊ธˆ notification service extension์„ ์œ„ํ•ด ์ƒ์„ฑํ•œ Bundle Identifier ์„ ํƒ ํ›„ continue, download

  • ๋‹ค์‹œ ํ”„๋กœ์ ํŠธ๋กœ ๋Œ์•„์™€์„œ Bundle Identifier ์ˆ˜์ •, Provisioning Profile ์— Import ํ•ด์ฃผ๋ฉด ๋จ (๊ฐœ๋ฐœ์‹œ์—๋Š” configurations๋ฅผ Debug, ์Šคํ† ์–ด ๋ฐฐํฌ์‹œ Release ์— ์ ์šฉ)

Pod ์ถ”๊ฐ€

target 'Notification Service Extension ์ด๋ฆ„ ' do
pod 'Firebase/Messaging'
end
  • target ๋ช…์นญ์€ target ์ถ”๊ฐ€์‹œ ์ž…๋ ฅํ•ด ์ฃผ์—ˆ๋˜ Product Name (์•„๋ž˜ ์ด๋ฏธ์ง€ ์ฐธ๊ณ )

Processing Notifications

func didReceive(
    _ request: UNNotificationRequest,
    withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
)
  • notification ๋ณ€๊ฒฝ์„ ์š”์ฒญํ•œ ๋’ค ์™„๋ฃŒ๋˜๋ฉด cotentHandler๋กœ ๋ณ€๊ฒฝ๋œ content ์ „๋‹ฌ
  • request์— ์›๋ž˜ notification request ์ •๋ณด๊ฐ€ ๋‹ด๊ฒจ ์žˆ์Œ. 
    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        var bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        
        if let bestAttemptContent = bestAttemptContent {

            bestAttemptContent.title = "์ˆ˜์ • ๋จ : \(bestAttemptContent.title)"
            bestAttemptContent.body = "์ˆ˜์ • ๋จ : \(bestAttemptContent.content)"

            Messaging.serviceExtension().populateNotificationContent(bestAttemptContent, withContentHandler: contentHandler)
            
            contentHandler(bestAttemptContent)
        }
    }
  • request.content๋ฅผ ์ˆ˜์ •ํ•œ ๋’ค contentHandler๋กœ ์ „๋‹ฌ, Firebase์˜ Messagin.serviceExtension().populateNotificationContent์— ์ˆ˜์ •๋œ notification๊ณผ handler ์ „๋‹ฌ

์ถ”๊ฐ€

func serviceExtensionTimeWillExpire()
  • didReceive์—์„œ completion block ์ฒ˜๋ฆฌ๊ฐ€ ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•จ (๋„ํ๋จผํŠธ์—๋Š” last chance to execute the block์ด๋ผ ์„ค๋ช…๋˜์–ด ์žˆ์Œ)
  • ์šฉ๋Ÿ‰์ด ํฐ ์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ ํ•  ๊ฒฝ์šฐ ํ•ด๋‹น ๋ฉ”์†Œ๋“œ ์ฒ˜๋ฆฌ ํ•„์š”(๋งŒ์•ฝ didReceive์—์„œ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ด์„œ ์ •ํ•ด์ง„ ์‹œ๊ฐ„ ๋‚ด์— completion handler์„ ์‹คํ–‰ํ•˜์ง€ ๋ชปํ•œ ๊ฒฝ์šฐ ์˜ค๋ฆฌ์ง€๋„ ์ปจํ…์ธ ๊ฐ€ ํ‘œ์‹œ๋จ)

mutable_content ์ถ”๊ฐ€ํ•˜๊ธฐ

  • apns ํŒŒ์ผ์„ ์‚ฌ์šฉํ•  ๋•Œ "mutable-content" : true ํ˜น์€ "mutable-content" : 1 ์„ ๋ณด๋‚ด์•ผ ํ•จ

  • firebase์—์„œ ํŽ˜์ด๋กœ๋“œ๋Š” "mutable_content" : true ํ˜น์€ "mutable_content" : 1 
  • โญ์ฃผ์˜ ์‚ฌํ•ญ(์‚ฝ์งˆ ๊ตฌ๊ฐ„ ์ฃผ์˜โ›”) : firebase์—์„œ payload๋Š” ์–ธ๋”๋ฐ”!!!, apns์—์„œ๋Š” ์ง๋Œ€๊ธฐ
  • (์‚ฝ์งˆ ๊ตฌ๊ฐ„ ์ฃผ์˜โ›”) ํ˜น์‹œ ํ‘ธ์‹œ ์ž‘์—…ํ•˜์‹œ๋Š” ๋ฐฑ์—”๋“œ ๋ถ„ ๋”ฐ๋กœ ์žˆ๊ณ  ๋‚˜๋Š” ํ”„๋ก ํŠธ๋งŒ ํ•œ๋‹ค -> ๋ณ€๊ฒฝ๋œ ํ‘ธ์‹œ๋กœ ์•ˆ์˜ค๋Š”๋ฐ ๋ฐฑ์—”๋“œ ์ž‘์—… ๋๋‚ฌ๋‹ค๊ณ  ์•ˆ๋‚ด๋ฐ›์Œ ->ํ”„๋ก ํŠธ๋„ ๋ฌธ์ œ ์—†๋Š”๊ฑฐ ๊ฐ™๋‹ค -> ์•„๋ž˜ ๋ฐฉ๋ฒ•์œผ๋กœ ํ™•์ธ
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void)
  • UNUserNotificationCenterDelegate ์˜ didReceive, willPresent์—์„œ ๋ธŒ๋ ˆ์ดํฌ ํฌ์ธํŠธ ๊ฑธ๊ณ  ์ฝ˜์†”๋กœ 
  • didReceive์—์„œ๋Š” response.notification.request, willPresent์—์„œ๋Š” notification.requet ํ™•์ธ

  • mutableContent: YES๋กœ ์™€์•ผ ์ •์ƒ ์ž‘๋™. ์ด ๋ถ€๋ถ„์ด NO๋กœ ์˜ค๋ฉด payload ์œ„์น˜๋‚˜, ์˜คํƒ€ ํ™•์ธ

์•ฑ์Šคํ† ์–ด ์—…๋กœ๋“œ

  • ์Šคํฌ๋กค ๋‚ด๋ ค์„œ NotificationService์˜ ๋ฐฐํฌ์šฉ ํ”„๋กœ๋น„์ €๋‹ ํŒŒ์ผ ์„ ํƒ

 

์—๋Ÿฌ ํ•ธ๋“ค๋ง

  • ์ˆ˜์ •๋œ ํ‘ธ์‹œ๋กœ ์•ˆ์˜ฌ๊ฒฝ์šฐ
    • mutable_content ๋ฅผ true๋กœ ๋ณด๋‚ด๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธ
  • ๋นŒ๋“œ๊ฐ€ ์•ˆ๋จ
    • DerivedData ์‚ญ์ œ -> ๋นŒ๋“œ ํด๋ฆฐ -> ์žฌ๋นŒ๋“œ (DerivedData ์‚ญ์ œํ•˜๋Š” ๋ฒ• : terminal์—์„œ rm -rf ~/Library/Developer/Xcode/DerivedData   ์ž…๋ ฅํ•˜์—ฌ ์‚ญ์ œ)
    • pod ํŒŒ์ผ์˜ ๋ฌธ์ œ์ผ ๊ฐ€๋Šฅ์„ฑ์ด ํผ : pod update > ๋นŒ๋“œ ํด๋ฆฐ > ์žฌ ๋นŒ๋“œ
    • multiple pod ํ™•์ธ : target์— ์ค‘๋ณต๋œ pod์ด ๋“ค์–ด๊ฐ„ ๊ฒฝ์šฐ 

=> ์ค‘๋ณต๋˜๋Š” pod์„ shared_pods์œผ๋กœ ์ •์˜ํ•˜์—ฌ ์‚ฌ์šฉ. 

=> ํƒ€๊ฒŸ์— use_frameworks! ์ถ”๊ฐ€ํ•˜๊ธฐ -> pod update

=> GoogleUtilities ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ์œ„์™€ ๊ฐ™์ด ๊ฒฝ๊ณ  ๋œธ ์ด๋•Œ pod์— ์ถ”๊ฐ€ํ•ด์ฃผ๊ณ  pod update ํ˜น์€ install

  • ์•ฑ์Šคํ† ์–ด์— ์•ˆ์˜ฌ๋ผ๊ฐ
    • Notification Service extension version์ด ์•ฑ์˜ ๋ฒ„์ „๊ณผ ์ผ์น˜ํ•˜๋Š” ์ง€ ํ™•์ธ
    • bad identifier์ธ์ง€ ํ™•์ธ (bundle ID ๊ธฐ์ค€์ด ์ƒ๊ฐ๋ณด๋‹ค ์—„๊ฒฉ...) : ์˜ˆ๋ฅผ ๋“ค์–ด ์•ฑ์˜ ๋ฒˆ๋“ค ์•„์ด๋””๊ฐ€ com.app.ex์ธ๋ฐ Notification Service Extension ์˜ bundle id์˜ .์ด ๋‘ ๊ฐœ ์ด์ƒ์ธ ๊ฒฝ์šฐ bad identifier! com.app.ex.notification.service => com.app.ex.notification์œผ๋กœ ์ˆ˜์ •
     

 

์ฐธ๊ณ  ์‚ฌ์ดํŠธ 

https://developer.apple.com/documentation/usernotifications/unnotificationserviceextension

 

Apple Developer Documentation

 

developer.apple.com

https://velog.io/@dody_/RN-Library-rn-firebase-cloud-messaging-FCM-%EC%84%B8%ED%8C%85%ED%95%98%EA%B8%B0

 

[RN Library ๐Ÿ“š] rn์—์„œ ํ‘ธ์‹œ์•Œ๋ฆผ ๋ณด๋‚ด๊ธฐ! firebase cloud messaging FCM ์„ธํŒ…ํ•˜๊ธฐ

์ž๋„ค! ์ด๋ฒˆ ์—…๋ฌด๋Š” rn์— ํ‘ธ์‰ฌ์•Œ๋ฆผ์„ ์„ธํŒ…ํ•˜๋Š” ๊ฑธ์„ธ .. .. ์˜ค์ผ€์ด ... ๋ชฉ์ฐจ install FCM ์„ธํŒ… ios ํ‘ธ์‹œ์•Œ๋ฆผ ๊ถŒํ•œ ์„ค์ • ios FCM ํ…Œ์ŠคํŠธ android FCM ํ…Œ์ŠคํŠธ ์ฐธ๊ณ ์‚ฌ์ดํŠธ rn FCM ๋ฌธ์„œ rn FCM api ๋ฌธ์„œ Install fcm์„

velog.io

https://yoonandro.tistory.com/98

 

[Swift] iOS Push Image๋„ ๋ฐ›์•„๋ณด๊ธฐ(Feat.FCM) 2/2

์•ˆ๋…•ํ•˜์„ธ์š”. 1/2๋Š” ์–ด๋””๊ฐ”๋ƒ๊ตฌ์š”? 1/2๋Š” ๊ท€์ฐฎ์•„์„œ 2/2 ๋จผ์ € ๋ณด๊ณ  ํ• ๋ ค๊ตฌ์šฉใ…‹ใ…‹ใ…‹ ์˜ค๋Š˜์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ImagePush๋กœ ๋ฐ›๋Š” ๋ฐฉ๋ฒ•์„ ๊ณต๋ถ€ํ•ด๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ƒˆ๋กœ ๋งŒ๋“œ๋Š” ์•ฑ๋•Œ๋ฌธ์— ํ…Œ์ŠคํŠธ ํ•ด๋ณด๋ฉด์„œ ์ง„ํ–‰ํ–ˆ์Šต

yoonandro.tistory.com

ํ˜น์‹œ ์ด์ƒํ•˜๊ฑฐ๋‚˜ ์ž˜ ๋ชป๋œ ๊ฒƒ์ด ์žˆ๋‹ค๋ฉด ์–ธ์ œ๋“  ๋Œ“๊ธ€ ๋ถ€ํƒ๋“œ๋ ค์š”!

728x90
๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€