FCM Message

共通

  • Message data type
    • Notification Message
      • 長度限制 2KB
      • 訊息接收狀況
        • 若裝置位於app畫面
          • 不顯示notification,會觸發接收function
        • 若app已執行,在背景執行 or app尚未開啟
          • 顯示notification,不會觸發接收function
    • Data Message
      • 長度限制 4KB
      • 訊息接收狀況
        • 無論開啟與否,皆會觸發接收function
  • 訊息的種類
    • Downstream Message
      • Topic Message
        • 可註冊的topic數量不受限制
        • 適用於公開的資訊,像是新聞、氣象等消息
        • 針對資料量做優化而非延遲時間,若需要更快且安全的傳遞方式,請選擇以token為對象的訊息種類而非topic
        • 若需要送給每個user的不同裝置時,請考慮Device Group messaging
        • 使用者於APP端subscribe topic,若topic不存在則會被建立
        • topic建立後最多一天的時間,在firebase console上才會出現在列表上
      • Device Group Message
        • 係指單個User的多個不同的Device
        • 讓所有的device共用一個notification key
        • 長度限制: 在ios device為2KB,其他平台為4KB
    • Upstream Message
      • 當server使用XMPP Connection Server protocol時才可運用
  • 訊息的生命週期
    • FCM通常在發送消息後立即傳遞消息。然而,這可能並不總是可能的。例如,如果平台是Android,則設備可以被關閉,離線或以其他方式不可用。 FCM可能會故意延遲郵件,以防止應用程序佔用過多的資源和負面影響電池壽命。
    • 當這種情況發生時,FCM存儲消息並在可行時盡快發送。雖然這在大多數情況下都很好,但有些應用程序可能不會傳遞延遲的消息。例如,如果消息是來電或視頻聊天通知,則僅在呼叫終止之前的短時間段內是有意義的。或者如果消息是對事件的邀請,則在事件結束之後接收到消息是無用的。
    • 您可以使用time_to_live參數(在HTTP和XMPP請求中都支持)來指定消息的最大生命週期。此參數的值必須是從0到2,419,200秒的持續時間,並且它對應於FCM存儲和嘗試傳遞消息的最大時間段。不包含此字段的請求的最大期限為四周
    • 指定消息的生命週期的另一個優點是,FCM從不限制time_to_live(TTL)值為0秒的消息。換句話說,FCM保證對於必須“現在或從不”傳遞的消息的最大努力。請記住,time_to_live值為0表示不能立即傳遞的郵件將被丟棄。然而,因為這樣的消息從未被存儲,這提供了用於發送通知消息的最佳等待時間。
    • 當app server丟出訊息且收到回傳messageID並不代表訊息已經傳到client端,僅代表該訊息的資料是可以被受理的
    • 在最佳情況下,如果設備連接到FCM,屏幕為開啟狀態,並且沒有節流限制,則會立即傳送消息。
    • 如果設備已連接但處於打盹模式,FCM將存儲低優先級消息,直到設備脫離打盹模式。 這就是collapse_key標誌起作用的地方:如果已經存在具有相同折疊密鑰(和註冊令牌)的消息並存儲並等待傳遞,則舊消息被丟棄,並且新消息取代它的位置(即,舊的 消息由新的消息折疊)。 但是,如果未設置折疊鍵,則新消息和舊消息都將存儲以供將來交付。
    • 如果設備未連接到FCM,則會存儲消息,直到建立連接(再次遵守折疊密鑰規則)。 當建立連接時,FCM將所有掛起的消息傳遞到設備。 如果設備從未再次連接(例如,如果它已恢復出廠設置),則消息最終超時,並從FCM存儲器中丟棄。 默認超時為四周,除非設置time_to_live標誌
    • 當FCM嘗試將消息傳遞到設備並卸載應用程序時,FCM立即丟棄該消息,並使註冊令牌無效。 以後嘗試向該設備發送消息將導致NotRegistered錯誤。
  • client端token可能會改變的狀況
    • APP端刪除該token
    • APP在新裝置上還原
    • 使用者移除/重新安裝APP
    • 清除APP資料

android

  • 接收狀況統整圖

  • 步驟如下 (https://firebase.google.com/docs/cloud-messaging/android/client)

    1. 在firebase console建立專案
    2. 加入android項目,設定keystore SHA1值
    3. 下載 google-services.json 放到 {ProjectRoot}/app 底下
    4. 專案:build.gradle(Project)加入:
      dependencies 
      {
       compile 'com.google.firebase:firebase-messaging:10.0.0'
      }
      
    5. 建立繼承 FirebaseMessagingService 的 Service (例如:MyFirebaseMessagingService)並在AndroidManifest.xml加入:

      <service
       android:name=".MyFirebaseMessagingService">
       <intent-filter>
           <action android:name="com.google.firebase.MESSAGING_EVENT"/>
       </intent-filter>
      </service>
      
    6. 建立繼承 FirebaseInstanceIdService 的 Service (例如:MyFirebaseInstanceIDService)並在AndroidManifest.xml加入:

      <service
       android:name=".MyFirebaseInstanceIDService">
       <intent-filter>
           <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
       </intent-filter>
      </service>
      
  • API參考

ios

  • 接收狀況:
    1. 若APP完全未開啟則無法收到訊息
    2. (ios-10.1.1-iphone6)若APP已開啟
      • 在背景執行時,收到notification message,會觸發AppDelegate.didReceiveRemoteNotification(),點擊通知才會呼叫AppDelegate.userNotificationCenter()
      • 在背景執行時,收到data message,只觸發AppDelegate.didReceiveRemoteNotification()
      • 若APP正在執行,皆可接收訊息,但notification不會顯示,若為notification message,則只有AppDelegate.userNotificationCenter()會觸發
    3. (ios-9.3.5-iphone4s)
  • 步驟: (https://firebase.google.com/docs/cloud-messaging/ios/client)

    1. 在Firebase console加入app,下載設定檔(GoogleService-Info.plist) 放到 {project-root}
    2. 在Project中加入SDK (open terminal)
      • 建立podFile
        $ cd {project-root}
        $ pod init
        
      • 編輯podFile並加入:
        pod 'Firebase/Core'
        pod 'Firebase/Messaging'
        
      • 安裝pods
        $ pod install
        $ open {.xcworkspace in project-root}
        
      • 安裝完後須在"Build Setting"->"Framework Search Path"加入“$(inherited)”,不然會出現framwork not found的問題
      • 步驟會為您的應用程式建立 .xcworkspace 檔案。應用程式日後的所有開發作業都將使用這個檔案
    3. APNs相關設定

    4. 在APP中初始化Firebase (Swift)

      • 在AppDelegate類別中加入以下程式碼

        import UIKit
        import Firebase  //<==here
        
        @UIApplicationMain
        class AppDelegate: UIResponder, UIApplicationDelegate {
        
         var window: UIWindow?
        
         func application(application: UIApplication,
           didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?)
           -> Bool {
           FIRApp.configure()  //<==here
           return true
         }
        }
        
    5. 註冊notification

      • 在 AppDelegate 類別中加入以下程式碼 (https://github.com/firebase/quickstart-ios/blob/master/messaging/MessagingExampleSwift/AppDelegate.swift#L33-L51)

        if #available(iOS 10.0, *) {
         let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
         UNUserNotificationCenter.current().requestAuthorization(
           options: authOptions,
           completionHandler: {_, _ in })
        
         // For iOS 10 display notification (sent via APNS)
         UNUserNotificationCenter.current().delegate = self  //will be error here
         // For iOS 10 data message (sent via FCM)
         FIRMessaging.messaging().remoteMessageDelegate = self  //will be error here
        
        } else {
         let settings: UIUserNotificationSettings =
         UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
         application.registerUserNotificationSettings(settings)
        }
        
        application.registerForRemoteNotifications()
        
      • 解決上述error需在 AppDelegate 後面(class scope外)加入兩個extension

        @available(iOS 10, *)
        extension AppDelegate : UNUserNotificationCenterDelegate {
         // Receive displayed notifications for iOS 10 devices.
         func userNotificationCenter(_ center: UNUserNotificationCenter,
                                     willPresent notification: UNNotification,
           withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
           let userInfo = notification.request.content.userInfo
           // Print message ID.
           print("Message ID: \(userInfo["gcm.message_id"]!)")
           // Print full message.
           print(userInfo)
         }
         func userNotificationCenter(_ center: UNUserNotificationCenter,
                                     didReceive response: UNNotificationResponse,
                                     withCompletionHandler completionHandler: @escaping () -> Void) {
           let userInfo = response.notification.request.content.userInfo
           // Print message ID.
           print("Message ID: \(userInfo["gcm.message_id"]!)")
           // Print full message.
           print(userInfo)
         }
        }
        
        extension AppDelegate : FIRMessagingDelegate {
         // Receive data message on iOS 10 devices while app is in the foreground.
         func applicationReceivedRemoteMessage(_ remoteMessage: FIRMessagingRemoteMessage) {
           print(remoteMessage.appData)
         }
        }
        

Server

results matching ""

    No results matching ""