在 Spring Boot 應用程序中使用 Firebase 雲消息傳遞
一、簡介
在本快速教程中,我們將展示如何使用 Google 的 Firebase 雲消息傳遞向 Web 和移動應用程序發送推送通知。
2.什麼是FCM?
Firebase Cloud Messaging,簡稱 FCM,是一種基於雲的消息傳遞服務,提供以下功能:
- 可靠地將消息發送到移動或 Web 應用程序,這裡稱為“客戶端”
- 使用主題或基於訂閱的尋址向所有或特定客戶端發送消息
- 在服務器應用程序中接收來自客戶端的消息
以下是該技術的一些實際應用示例:
- 發送包含特定產品獨家優惠的有針對性的消息
- 通知給定應用程序的所有用戶新功能可用
- 即時消息/聊天應用程序
- 直接通知給定客戶
3. 應用架構
基於 FCM 的應用程序的典型架構由服務器、客戶端和 FCM 本身組成:
在本教程中,我們將重點關注此類應用程序的服務器端。在我們的例子中,這個服務器將是一個基於 Spring Boot 的服務,它公開了一個 REST API。這個 API 允許我們探索向我們(希望如此)龐大的用戶群發送通知的不同方式:
- 向主題發布通知
- 向特定客戶端發布通知
- 向多個主題發布通知
這種應用程序的核心是客戶端、主題和訂閱的概念。
3.1.話題
topic
是一個命名實體,充當共享某些屬性的通知的中心。例如,金融應用程序可以為其交易的每種資產使用一個主題。同樣,體育應用程序可以為每支球隊甚至特定比賽使用一個主題。
3.2.客戶
客戶端是我們安裝在給定移動設備上或在瀏覽器上運行的應用程序的實例。為接收通知,客戶端使用適當的 SDK API 調用將自己註冊到我們的 Firebase 項目。
成功註冊後,客戶端會從 Firebase 獲得一個唯一的註冊令牌。通常,此令牌會發送到服務器端,因此可用於直接通知。
3.3.訂閱
訂閱表示客戶端和主題之間的關聯。服務器應用程序使用採用一個或多個客戶端註冊令牌和主題名稱的 API 調用來創建新訂閱。
4. Firebase 項目設置
Firebase 項目充當我們將在應用程序中使用的雲資源的容器。 Google 提供了一個免費的初始層,允許開發人員試驗可用的服務,並且只需為超出可用配額的部分付費。
因此,要使用 FCM,我們的第一步是使用Firebase 的控制台創建一個新項目。登錄後,我們將獲得 Firebase 的主頁:
在這裡,我們可以選擇添加新項目或選擇現有項目。讓我們選擇前者。這將啟動一個嚮導,該嚮導將收集創建新項目所需的信息。
首先,我們必須命名我們的項目:
請注意,在通知的名稱下,有一個帶有為此項目生成的內部 ID 的按鈕。通常,不需要更改它,但如果我們出於某種原因不喜歡它,我們可以單擊它並使用不同的。另請注意,雖然項目 ID 是唯一的,但項目名稱不是唯一的,這可能有點令人困惑。
在下一步中,我們可以選擇將分析添加到我們的項目中。我們將禁用此選項,因為本教程不需要它。如果需要,我們可以稍後啟用它。
單擊“創建項目”後,Firebase 會將我們重定向到新創建的項目管理頁面。
5. 生成服務賬號
為了讓服務器端應用程序對 Firebase 服務進行 API 調用,我們需要生成一個新的服務帳戶並獲取其憑據。我們可以通過訪問項目設置頁面並選擇“服務帳戶”選項卡來做到這一點:
任何新項目都以管理服務帳戶開始,該帳戶基本上可以在該項目中執行任何操作。在這裡,我們將使用它進行測試,但實際應用程序應該創建一個權限有限的專用服務帳戶。這樣做需要一些 IAM(Google 的身份和訪問管理)知識,並且超出了本教程的範圍。
我們現在必須單擊“生成新私鑰”按鈕來下載包含調用 Firebase API 所需數據的 JSON 文件。不用說,我們必須將此文件存儲在安全位置。
6.Maven 依賴
現在我們已經準備好 Firebase 項目,是時候編寫發送通知的服務器組件了。除了 MVC 應用程序的常規 Spring Boot 啟動器之外,我們還必須添加firebase-admin
依賴項:
<dependency>
<groupId>com.google.firebase</groupId>
<artifactId>firebase-admin</artifactId>
<version>9.1.1</version>
</dependency>
此依賴項的最新版本可在Maven Central上獲得。
7. Firebase 消息配置
FirebaseMessaging
類是主要外觀,我們將通過它使用 FCM 發送消息。由於此類是線程安全的,我們將在@Configuration
類中使用@Bean
方法來創建它的單個實例並使其可用於我們的控制器:
@Bean
FirebaseMessaging firebaseMessaging(FirebaseApp firebaseApp) {
return FirebaseMessaging.getInstance(firebaseApp);
}
很簡單,但現在我們必須提供一個FirebaseApp
。或者,我們可以使用getInstance()
的無參數變體,它可以完成工作但不允許我們更改任何默認參數。
為了解決這個問題,讓我們創建另一個@Bean
方法來創建一個自定義的FirebaseApp
實例:
@Bean
FirebaseApp firebaseApp(GoogleCredentials credentials) {
FirebaseOptions options = FirebaseOptions.builder()
.setCredentials(credentials)
.build();
return FirebaseApp.initializeApp(options);
}
在這裡,唯一的定制是使用特定的GoogleCredentials
對象。 FirebaseOptions
的構建器允許我們調整 Firebase 客戶端的其他方面:
- 超時
- HTTP 請求工廠
- 特定服務的自定義端點
- 線程工廠
最後一項配置是憑據本身。我們將創建另一個@Bean
,它使用通過配置屬性提供的服務帳戶或使用默認憑證鏈創建GoogleCredentials
實例:
@Bean
GoogleCredentials googleCredentials() {
if (firebaseProperties.getServiceAccount() != null) {
try (InputStream is = firebaseProperties.getServiceAccount().getInputStream()) {
return GoogleCredentials.fromStream(is);
}
}
else {
// Use standard credentials chain. Useful when running inside GKE
return GoogleCredentials.getApplicationDefault();
}
}
這種方法簡化了在我們可能有多個服務帳戶文件的本地機器上的測試。我們可以使用標準的GOOGLE_APPLICATION_CREDENTIALS
環境變量來指向正確的文件,但更改它有點麻煩。
8. 向主題發送消息
向主題發送消息需要兩個步驟:構建Message
對象並使用FirebaseMessaging
的方法之一發送它。 Message
實例是使用熟悉的構建器模式創建的:
Message msg = Message.builder()
.setTopic(topic)
.putData("body", "some data")
.build();
一旦我們有了Message
實例,我們就可以使用send()
來請求它的傳遞:
String id = fcm.send(msg);
在這裡, fcm
是我們注入到控制器類中的FirebaseMessaging
實例。 send
() 返回一個值,該值是 FCM 生成的消息標識符。我們可以將此標識符用於跟踪或記錄目的。
send()
也有一個異步版本sendAsync()
,它返回一個ApiFuture
對象。此類擴展了 Java 的Future
,因此我們可以輕鬆地將其與反應式框架(如 Project Reactor)一起使用。
9. 向特定客戶端發送消息
正如我們之前提到的,每個客戶端都有一個與之關聯的唯一訂閱令牌。在構建Message
而不是主題名稱時,我們使用此標記作為其“地址”:
Message msg = Message.builder()
.setToken(registrationToken)
.putData("body", "some data")
.build();
對於我們想要向多個客戶端發送相同消息的用例,我們可以使用MulticastMessage
和sendMulticast().
它們的工作方式與單播版本相同,但允許我們在一次調用中將消息發送給多達 500 個客戶端:
MulticastMessage msg = MulticastMessage.builder()
.addAllTokens(message.getRegistrationTokens())
.putData("body", "some data")
.build();
BatchResponse response = fcm.sendMulticast(msg);
返回的BatchResponse
包含生成的消息標識符以及與給定客戶端的傳遞相關的任何錯誤。
10. 向多個主題發送消息
FCM 允許我們指定條件來定義消息的目標受眾。 condition
是一種邏輯表達式,它根據客戶訂閱(或未訂閱)的主題來選擇客戶。例如,給定三個主題(T1、T2 和 T3),此表達式的目標設備是 T1 或 T2 但不是 T3 的訂閱者:
('T1' in topics || 'T2' in topics) && !('T3' in topics)
此處, topics
變量表示給定客戶端已訂閱的所有主題。我們現在可以使用構建器中可用的setCondition()
方法構建一條發送給滿足此條件的客戶端的消息:
Message msg = Message.builder()
.setCondition("('T1' in topics || 'T2' in topics) && !('T3' in topics)")
.putData("body", "some data")
.build();
String id = fcm.send(msg);
11. 為客戶訂閱主題
我們使用subscribeToTopic() (
或其異步變體subscribeToTopicAsync()
方法來創建將客戶端與主題相關聯的訂閱。該方法接受客戶端註冊令牌列表和主題名稱作為參數:
fcm.subscribeToTopic(registrationTokens, topic);
請注意,與其他消息傳遞系統相比,返回值沒有創建訂閱的標識符。如果我們想跟踪給定客戶訂閱了哪些主題,我們必須自己做。
要取消訂閱客戶端,我們使用unsubscribeFromTopic():
fcm.subscribeToTopic(List.of(registrationToken), topic);
12.結論
在本教程中,我們展示瞭如何使用 Google 的 Firebase 雲消息服務向 Web 和移動應用程序發送通知消息。
與往常一樣,完整代碼可在 GitHub 上獲得。