這篇文章將完成把 Android 裝置註冊到 Azure 通知中樞的程式碼。
前置準備
在這篇文章中,你需要事先準備
- 完成 【Expo Android 推播整合 02】 專案建置:設定 Firebase、Azure 中的所有設定和安裝。
- Ajax 套件,ex:這篇範例是使用 Axios。
前導知識
什麼是 APNS 與 FCM?
- APNs(Apple Push Notification Service):Apple 提供的推播服務,用來將通知送到 Apple 裝置,需先申請 Apple 開發者帳號才能取得。
- FCM(Firebase Cloud Messaging):Google 提供的推播服務,使用 Firebase SDK 取得。FCM 提供兩種 API:
- Legacy API:舊版 API,用 server key 傳送請求,較簡單但功能有限,已經在 2024/06 被淘汰。
- FCM v1(HTTP v1 API):新版 API,使用 OAuth 2.0 認證,支援多平台設定與更高安全性,Google 推薦使用。
Azure 推播通知運作方式

圖片來自 Azure 文件
- 裝置向 APNS(Apple)或 FCM(Google)索取推播識別碼,這將作為接收 Azure 的通道。
- Azure 使用識別碼,註冊到 Azure 上。
- 後端把通知送到通知中樞。
- 通知中樞轉給平台 APNS(Apple)或 FCM(Google),由平台推送到裝置。
使用 REST API 註冊 Azure
其實整段程式碼很簡單,但可以使用 REST API 執行的教學藏在 C# 範例裡,我也是先找到很多提供整合的老舊套件,才發現原來 Azure 本身就有提供註冊方法。
1. 取得推播識別碼
安裝 react-native-firebase/messaging,根據 文件中 messaging 提供的 getToken 方法 取得 FCMtoken
。
npm i @react-native-firebase/messaging
通常裝置每次取得的 FCMtoken
是相同的,但在以下情境時會改變:
- 重安裝 App。
- 更換 Google 帳號。
- 使用者清除 App 資料。
- 裝置不活躍超過 9 個月:Google 2024/06 起自動刪除閒置 9 個月的
FCMtoken
,所以不活躍裝置在 9 個月後又開始活動也會更新FCMtoken
。
import { useEffect } from 'react';
import messaging from '@react-native-firebase/messaging';
export default function HomeScreen() {
useEffect(() => {
const setupPush = async () => {
try {
const token = await messaging().getToken();
console.log(`FCM token: ${token}`);
} catch (err) {
console.log(`初始化推播錯誤 ${JSON.stringify(err)}`)
}
}
setupPush();
}, []);
return (...略)
}
2. 準備註冊需要的參數
我們會使用 建立 Azure 註冊 create-registration 這支 API。還記得我們在上一篇文章中有設定 Azure 通知中樞 FCM(v1)金鑰嗎?這支 API 會將剛才產生的 FCM token 註冊到其中。成功註冊的裝置會得到 registerId
等資訊,這未來能用於修改和刪除,建議存到後端。
這是我們註冊需要準備的資料:
namespace
:Notification Hub 所屬的命名空間(Namespace)NotificationHub
:實際 Notification Hub 名稱,是你註冊裝置與推播的實際目標SAStoken
:Shared Access Signature
namespace
和 NotificationHub
已經在上一篇文章建立通知中樞時設定好了,本文裡兩個 value 都用 AnnNotify
。
SAS token
SAStoken
將由以下參數組成,程式碼在 官方文件 有附。
targetUri
:https://${HUB_NAMESPACE}.servicebus.windows.net/${HUB_NAME}
。sharedKey
:’Access Policies 中 DefaultListenSharedAccessSignature 的金鑰值’。ruleId
:’DefaultListenSharedAccessSignature’。因為共用存取簽章安全性考量,建議FullSharedAccess
只在後端使用,前端不要用呦。expiresInMins
:過期時間(產生後幾分鐘失效),SAStoken
失效不影響已經成功的 Azure 註冊。其實建議設定短時間,並且由後端產生較安全,但前端還是可以自己先產出測試。

我們可以新增一個 hook 專門用來放註冊程式碼,直接從 官方文件 中複製貼上吧!
// hooks/useAzureRegistration.tsx
import axios from 'axios'
import CryptoJS from 'crypto-js'
const HUB_NAME = '通知中樞名稱'
const HUB_NAMESPACE = '通知中樞命名空間'
const SHARED_ACCESS_KEY =
'Access Policies 中 DefaultListenSharedAccessSignature 的金鑰值'
const SHARED_ACCESS_KEY_NAME = 'DefaultListenSharedAccessSignature' // 切記前端不要使用 FullSharedAccess
const registerDeviceToAzure = async (fcmToken: string): Promise<void> => {
const baseUri = `https://${HUB_NAMESPACE}.servicebus.windows.net/${HUB_NAME}`
const apiVersion = '2015-01'
const targetUri = `${baseUri}`
// 生產 SAS token,設定 30 分鐘失效
const sasToken = getSelfSignedToken(
targetUri,
SHARED_ACCESS_KEY,
SHARED_ACCESS_KEY_NAME,
30
)
}
// SAS token 工具
const getSelfSignedToken = function (
targetUri: string,
sharedKey: string,
ruleId: string,
expiresInMins: number
) {
targetUri = encodeURIComponent(targetUri.toLowerCase()).toLowerCase()
// Set expiration in seconds
var expireOnDate = new Date()
expireOnDate.setMinutes(expireOnDate.getMinutes() + expiresInMins)
var expires =
Date.UTC(
expireOnDate.getUTCFullYear(),
expireOnDate.getUTCMonth(),
expireOnDate.getUTCDate(),
expireOnDate.getUTCHours(),
expireOnDate.getUTCMinutes(),
expireOnDate.getUTCSeconds()
) / 1000
var tosign = targetUri + '\n' + expires
// using CryptoJS
var signature = CryptoJS.HmacSHA256(tosign, sharedKey)
var base64signature = signature.toString(CryptoJS.enc.Base64)
var base64UriEncoded = encodeURIComponent(base64signature)
// construct autorization string
var token =
'SharedAccessSignature sr=' +
targetUri +
'&sig=' +
base64UriEncoded +
'&se=' +
expires +
'&skn=' +
ruleId
// console.log("signature:" + token);
return token
}
export default registerDeviceToAzure
3. 註冊 Azure 通知中樞
回到 建立 Azure 註冊 create-registration 這支 API,不同系統裝置有不同註冊範本。這篇文章以 Android 為主,使用 Firebase,所以我的註冊範本 xmlBody
使用 FcmV1TemplateRegistration
的範例,其他系統可以再替換。
另外可以選擇使用以下標籤:
Tags
:推播時可針對標籤推播,如果要設定只推給 Android 用戶,可使用<Tags>Android</Tags>
。想推給某特定用戶,也可以自訂每個裝置有不同 Id,使用 Id 註冊。ExpirationTime
:註冊有效時間。Azure 通知中樞的付費方案與可註冊數量有關,尤其是在開發者測試期間會反覆重新安裝(本文第 1 個步驟有提到FCMtoken
更新機制),如果不設定有效時間,會累積大量新註冊。雖然有 刪除註冊 API,但一次只能刪一個註冊。
// hooks/useAzureRegistration.tsx
const registerDeviceToAzure = async (fcmToken: string): Promise<void> => {
const baseUri = `https://${HUB_NAMESPACE}.servicebus.windows.net/${HUB_NAME}`;
const apiVersion = '2015-01';
const targetUri = `${baseUri}`;
// 生產 SAS token,設定 30 分鐘失效
const sasToken = getSelfSignedToken(targetUri, SHARED_ACCESS_KEY, SHARED_ACCESS_KEY_NAME, 30);
// Azure 註冊的過期時間設定為 30 天
const expirationDate = new Date();
expirationDate.setDate(expirationDate.getDate() + 30);
const isoString = expirationDate.toISOString().replace(/\.\d{3}Z$/, '+08:00');
// FcmV1TemplateRegistration 註冊範本
const xmlBody = `
<entry xmlns="http://www.w3.org/2005/Atom">
<content type="application/xml">
<FcmV1RegistrationDescription xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/netservices/2010/10/servicebus/connect">
<Tags>...</Tags>
<FcmV1RegistrationId>${fcmToken}</FcmV1RegistrationId>
<ExpirationTime>${isoString}</ExpirationTime>
</FcmV1RegistrationDescription>
</content>
</entry>
`;
try {
const response = await axios.post(`${baseUri}/registrations?api-version=${apiVersion}`, xmlBody, {
headers: {
'Authorization': sasToken,
'Content-Type': 'application/atom+xml'
}
});
// 解析 response 返回註冊頁面顯示
console.log('📡 Azure 註冊成功:', {
status: response.status,
registrationId: response.data?.match(/<title[^>]*>(.*?)<\/title>/)?.[1] ?? '不明',
});
} catch (error: any) {
console.error('❌ Azure 註冊失敗:', error);
return `註冊失敗:${error.message}`;
}
};
// SAS token 工具
const getSelfSignedToken = function (targetUri: string, sharedKey: string, ruleId: string,
expiresInMins: number) {
...略
};
export default registerDeviceToAzure;
完工!🎉🎉接下來幾篇會介紹
- 要求裝置開啟通知授權
- 打包與 Android Studio 偵錯
- 測試發送
相同文章發布於我的部落格