FCM設定推送訊息的時效性(若目標裝置沒有在限定時間內收到推送則放棄推送)

正半軸發表於2020-11-18

前言

專案裡進行谷歌推送的時候,希望能再加入一個功能,如果使用者沒有在一定的時間內收到推送,則取消這條推送,改為推送另一條訊息(XX未收到)。

研究思路

第一步:提取要素

這個功能的期望特徵是什麼?
從測試反饋的情況來看,某裝置本需要在若干時間後收到某個推送,但是沒有收到,然後過一段時間才收到。而超時後,就可能導致推送失效,比如通話請求推送。
關鍵在於:通知的時效性
如果這個通知不能在某段時間內收到就使其無效改為推送其他訊息
既然如此邏輯上就要考慮一個節點,怎麼知道通知沒能在某段時間內收到呢。

第二步:場景分析

在實際使用過程中有什麼期望?
我期望,伺服器知道通知超時,並且根據超時的時間進行處理
關鍵在於:可控的時效性引數
通過對於FCM官方sdk的研究我找到了合適的方案
官網連結:https://firebase.google.com/docs/cloud-messaging/concept-options
原文如下:

  • FCM 通常會在訊息發出之後馬上進行傳遞。 但是,也有一些例外情況。例如,如果在 Android 平臺上,裝置有可能處於關閉、離線或不可用狀態。 FCM 可能會有意延遲訊息傳遞,以防止應用消耗過多資源和對電池續航時間產生不良影響。

  • 在這種情況下,FCM 會儲存訊息,等到可行時立即傳送。儘管大多數情況下這樣做都沒什麼問題,但有些應用可能永遠不會傳遞延遲訊息。舉例來說,如果訊息是來電或視訊聊天通知,則它僅在通話終止之前的這段較短時間內有意義。或者,如果訊息是活動邀請,那麼如果在活動結束後才收到訊息,它將毫無用處。

  • 在 Android 和 Web/JavaScript 上,您可以指定訊息的最長有效期。此值必須是介於 0 至 2419200 秒(28 天)之間的一段持續時間,其對應於 FCM 儲存並嘗試傳遞訊息的最長時間期限。不含此欄位的請求預設為最長期限(四周)。
    官網案例:

{
  "message":{
    "token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
    "data":{
      "Nick" : "Mario",
      "body" : "great match!",
      "Room" : "PortugalVSDenmark"
    },
    "apns":{
      "headers":{
        "apns-expiration":"1604750400"
      }
    },
    "android":{
      "ttl":"4500s"
    },
    "webpush":{
      "headers":{
        "TTL":"4500"
      }
    }
  }
}

第三步:擴充研究

期望撤銷推送
對於這種通話型別推送時效性的推送,如果撥打電話的方面提前結束通話了,但是通話推送請求已經發出了,這時候應該怎麼處理。
這種情況下希望能夠取消這個推送,於是研究了文件。
暫無解決方案
研究後得出結論,服務端無法實時獲取推送是否送達,可以在一天後獲取統計圖表,這個解決方案不使用。

功能實現

由於我的服務端設計採用的是官方SDK:admin_sdk
因此我修改傳輸模組如下:

	 //獲取AndroidConfig.Builder物件
    private static AndroidConfig.Builder androidConfigBuilder = AndroidConfig.builder();
    //獲取AndroidNotification.Builder物件
    private static AndroidNotification.Builder androidNotifiBuilder = AndroidNotification.builder();
   

    public static void testPush( String token,String title,String body
    		,String ring ,String ChannelID) throws IOException, FirebaseMessagingException {
   	 // See documentation on defining a message payload.
    	//獲取例項
        FirebaseApp firebaseApp = FirebaseApp.getInstance();
		//例項為空的情況
		if (firebaseApp == null) {
		    return;
		}
		// 這2個內容先不要寫需要和其他人協調後再做決定
//		androidNotifiBuilder.setIcon("https://www.shiku.co/images/favicon.png");// 設定訊息圖示
//		androidConfigBuilder.setRestrictedPackageName("io.telecomm.telecomm");
		androidNotifiBuilder.setColor("#55BEB7");// 設定訊息通知顏色
		androidNotifiBuilder.setTitle(title);// 設定訊息標題
		androidNotifiBuilder.setBody(body);// 設定訊息內容
		androidNotifiBuilder.setSound(ring);		//設定提示音
		androidNotifiBuilder.setChannelId(ChannelID); //設定通知通道
		AndroidNotification androidNotification = androidNotifiBuilder.build();
		androidConfigBuilder.setNotification(androidNotification);
		androidConfigBuilder.setTtl(300*1000);  			//設定通知的時效性300s
		AndroidConfig androidConfig = androidConfigBuilder.build();
		
		
		//構建訊息
		Message message = Message.builder()
				.setAndroidConfig(androidConfig)
		        .setToken(token)
		        .build();
        String response = FirebaseMessaging.getInstance().send(message);
        // Response is a message ID string.
    	System.out.println("Successfully sent message: " + response);
	}

關於重新推送這個需要用伺服器其他的訊息迴環來實現,這裡就不作說明了。

結語

測試結果可行,需要注意==.setTtl()方法裡填充的時間引數單位是ms==,有部分文章認為為s,但是在我使用的版本里(6.10.0)測試得出的結論是ms。
此外還有一處,超過失效的自動放棄的訊息,在FCM推送請求的反饋通路里依然認為是成功,因為對於FCM推送請求來說,向目標推送這個指令成功被FCM服務端接受了,而推送是否超時於此無關。
ψ(*`ー´)ψ開發完畢

相關文章