Nếu sử dụng các API FCM để tạo yêu cầu gửi theo phương thức lập trình, bạn có thể thấy rằng theo thời gian, bạn đang lãng phí tài nguyên bằng cách gửi thông báo đến các thiết bị không hoạt động có mã thông báo đăng ký đã lỗi thời. Tình huống này có thể ảnh hưởng đến dữ liệu phân phối thông báo được báo cáo trong bảng điều khiển của Firebase hoặc dữ liệu được xuất sang BigQuery, cho thấy tỷ lệ phân phối giảm đáng kể (nhưng không thực sự hợp lệ). Hướng dẫn này thảo luận về một số biện pháp mà bạn có thể thực hiện để giúp đảm bảo việc nhắm mục tiêu thông báo hiệu quả và báo cáo phân phối hợp lệ.
Mã thông báo đăng ký đã lỗi thời và hết hạn
Mã thông báo đăng ký đã lỗi thời là mã thông báo được liên kết với các thiết bị không hoạt động và chưa kết nối với FCM trong hơn một tháng. Theo thời gian, thiết bị ngày càng ít có khả năng kết nối lại với FCM Việc gửi thông báo và phân phát chủ đề cho các mã thông báo đã lỗi thời này khó có thể được phân phối.
Có một số lý do khiến mã thông báo có thể trở nên lỗi thời. Ví dụ: thiết bị được liên kết với mã thông báo có thể bị mất, bị hỏng hoặc bị cất giữ và quên mất.
Đối với Android, khi mã thông báo đã lỗi thời không hoạt động trong 270 ngày, FCM sẽ coi mã thông báo đó là hết hạn. Sau khi mã thông báo hết hạn, FCM đánh dấu mã thông báo đó là không hợp lệ và từ chối gửi đến mã thông báo đó. Tuy nhiên, FCM sẽ cấp một mã thông báo mới cho thực thể ứng dụng trong trường hợp hiếm gặp là thiết bị kết nối lại và ứng dụng được mở.
Đối với các nền tảng khác như iOS, FCM dựa vào dịch vụ đẩy cơ bản (ví dụ: APNs), dịch vụ này không có thời gian hết hạn mã thông báo dựa trên thời gian không hoạt động là 270 ngày. Vì vậy, bạn nên chủ động duy trì tính mới của mã thông báo và xoá mã thông báo đăng ký đã lỗi thời.
Các phương pháp hay cơ bản
Có một số phương pháp cơ bản mà bạn nên tuân theo trong mọi ứng dụng sử dụng FCM API để tạo yêu cầu gửi theo phương thức lập trình. Các phương pháp hay chính là:
- Truy xuất mã thông báo đăng ký từ FCM và lưu trữ trên máy chủ. Một vai trò quan trọng của máy chủ là theo dõi mã thông báo của từng ứng dụng và duy trì danh sách mã thông báo đang hoạt động được cập nhật. Bạn nên triển khai dấu thời gian mã thông báo trong mã và máy chủ, đồng thời cập nhật dấu thời gian này theo khoảng thời gian đều đặn.
- Duy trì tính mới của mã thông báo và xoá mã thông báo đã lỗi thời. Ngoài việc xoá các mã thông báo mà FCM không còn coi là hợp lệ, bạn có thể muốn theo dõi các dấu hiệu khác cho thấy mã thông báo đã trở nên lỗi thời và chủ động xoá các mã thông báo đó. Hướng dẫn này thảo luận về một số lựa chọn để bạn đạt được mục tiêu này.
Truy xuất và lưu trữ mã thông báo đăng ký
Khi khởi động ứng dụng lần đầu, FCM SDK sẽ tạo mã thông báo đăng ký cho thực thể ứng dụng. Đây là mã thông báo mà bạn phải đưa vào các yêu cầu gửi được nhắm mục tiêu từ API hoặc thêm vào gói thuê bao chủ đề để nhắm mục tiêu đến các chủ đề.
Bạn nên để ứng dụng truy xuất mã thông báo này khi khởi động lần đầu và lưu vào máy chủ ứng dụng cùng với dấu thời gian. Dấu thời gian này phải được triển khai bằng mã và máy chủ của bạn, vì FCM SDK không cung cấp dấu thời gian này cho bạn.
Ngoài ra, bạn cần lưu mã thông báo vào máy chủ và cập nhật dấu thời gian bất cứ khi nào mã thông báo thay đổi, chẳng hạn như khi:
- Ứng dụng được khôi phục trên một thiết bị mới
- Người dùng gỡ cài đặt hoặc cài đặt lại ứng dụng
- Người dùng xoá dữ liệu ứng dụng
- Ứng dụng hoạt động trở lại sau khi FCM hết hạn mã thông báo hiện có
Ví dụ: lưu trữ mã thông báo và dấu thời gian trong Cloud Firestore
Ví dụ: bạn có thể sử dụng Cloud Firestore để lưu trữ mã thông báo trong một bộ sưu tập
có tên là fcmTokens. Mỗi mã nhận dạng tài liệu trong bộ sưu tập tương ứng với một mã nhận dạng người dùng và tài liệu lưu trữ mã thông báo đăng ký hiện tại và dấu thời gian được cập nhật gần đây nhất. Sử dụng hàm set như trong ví dụ về Kotlin này:
/**
* Persist token to third-party servers.
*
* Modify this method to associate the user's FCM registration token with any server-side account
* maintained by your application.
*
* @param token The new token.
*/
private fun sendTokenToServer(token: String?) {
// If you're running your own server, call API to send token and today's date for the user
// Example shown below with Firestore
// Add token and timestamp to Firestore for this user
val deviceToken = hashMapOf(
"token" to token,
"timestamp" to FieldValue.serverTimestamp(),
)
// Get user ID from Firebase Auth or your own server
Firebase.firestore.collection("fcmTokens").document("myuserid")
.set(deviceToken)
}
Bất cứ khi nào một mã thông báo được truy xuất, mã thông báo đó sẽ được lưu trữ trong Cloud Firestore bằng cách gọi
sendTokenToServer:
/**
* Called if the FCM registration token is updated. This may occur if the security of
* the previous token had been compromised. Note that this is called when the
* FCM registration token is initially generated so this is where you would retrieve the token.
*/
override fun onNewToken(token: String) {
Log.d(TAG, "Refreshed token: $token")
// If you want to send messages to this application instance or
// manage this apps subscriptions on the server side, send the
// FCM registration token to your app server.
sendTokenToServer(token)
}
var token = Firebase.messaging.token.await()
// Check whether the retrieved token matches the one on your server for this user's device
val preferences = this.getPreferences(Context.MODE_PRIVATE)
val tokenStored = preferences.getString("deviceToken", "")
lifecycleScope.launch {
if (tokenStored == "" || tokenStored != token)
{
// If you have your own server, call API to send the above token and Date() for this user's device
// Example shown below with Firestore
// Add token and timestamp to Firestore for this user
val deviceToken = hashMapOf(
"token" to token,
"timestamp" to FieldValue.serverTimestamp(),
)
// Get user ID from Firebase Auth or your own server
Firebase.firestore.collection("fcmTokens").document("myuserid")
.set(deviceToken).await()
}
}
Duy trì tính mới của mã thông báo và xoá mã thông báo đã lỗi thời
Việc xác định xem mã thông báo còn mới hay đã lỗi thời không phải lúc nào cũng đơn giản. Để bao gồm tất cả các trường hợp, bạn nên áp dụng một ngưỡng để xác định thời điểm coi mã thông báo là lỗi thời. Theo mặc định, FCM coi mã thông báo là lỗi thời nếu thực thể ứng dụng của mã thông báo đó chưa kết nối trong một tháng. Mọi mã thông báo cũ hơn một tháng đều có khả năng là thiết bị không hoạt động; nếu không, thiết bị đang hoạt động sẽ làm mới mã thông báo của mình.
Tuỳ thuộc vào trường hợp sử dụng, một tháng có thể là quá ngắn hoặc quá dài, vì vậy, bạn phải tự xác định tiêu chí phù hợp với mình.
Phát hiện phản hồi mã thông báo không hợp lệ từ phần phụ trợ FCM
Hãy nhớ phát hiện phản hồi mã thông báo không hợp lệ từ FCM và phản hồi bằng cách xoá mọi mã thông báo đăng ký đã biết là không hợp lệ hoặc đã hết hạn khỏi hệ thống. Với HTTP v1 API, các thông báo lỗi này có thể cho biết yêu cầu gửi của bạn nhắm mục tiêu đến các mã thông báo không hợp lệ hoặc đã hết hạn:
UNREGISTERED(HTTP 404)INVALID_ARGUMENT(HTTP 400)
Nếu bạn chắc chắn rằng tải trọng thông báo là hợp lệ và bạn nhận được một trong các phản hồi này cho mã thông báo được nhắm mục tiêu, thì bạn có thể xoá bản ghi của mã thông báo này, vì mã thông báo này sẽ không bao giờ hợp lệ nữa. Ví dụ: để xoá mã thông báo không hợp lệ khỏi Cloud Firestore, bạn có thể triển khai và chạy một hàm như sau:
// Registration token comes from the client FCM SDKs
const registrationToken = 'YOUR_REGISTRATION_TOKEN';
const message = {
data: {
// Information you want to send inside of notification
},
token: registrationToken
};
// Send message to device with provided registration token
getMessaging().send(message)
.then((response) => {
// Response is a message ID string.
})
.catch((error) => {
// Delete token for user if error code is UNREGISTERED or INVALID_ARGUMENT.
if (error.errorCode == "messaging/registration-token-not-registered") {
// If you're running your own server, call API to delete the
token for the user
// Example shown below with Firestore
// Get user ID from Firebase Auth or your own server
Firebase.firestore.collection("fcmTokens").document(user.uid).delete()
}
});
FCM trả về phản hồi mã thông báo không hợp lệ nếu mã thông báo cho thiết bị Android đã hết hạn sau 270 ngày không hoạt động hoặc nếu một ứng dụng đã huỷ đăng ký một cách rõ ràng. Nếu cần theo dõi chính xác hơn tình trạng lỗi thời theo định nghĩa của riêng bạn, bạn có thể chủ động xoá mã thông báo đăng ký đã lỗi thời.
Cập nhật mã thông báo thường xuyên
Bạn nên định kỳ truy xuất và cập nhật tất cả mã thông báo đăng ký trên máy chủ. Bạn cần phải:
- Thêm logic ứng dụng vào ứng dụng để truy xuất mã thông báo hiện tại bằng cách sử dụng lệnh gọi API
thích hợp (chẳng hạn như
token(completion):cho nền tảng Apple hoặcgetToken()cho Android), sau đó gửi mã thông báo hiện tại đến máy chủ ứng dụng để lưu trữ (có dấu thời gian). Đây có thể là một công việc hằng tháng được định cấu hình để bao gồm tất cả ứng dụng hoặc mã thông báo. - Thêm logic máy chủ để cập nhật dấu thời gian của mã thông báo theo khoảng thời gian đều đặn, bất kể mã thông báo có thay đổi hay không.
Để biết ví dụ về logic Android để cập nhật mã thông báo bằng WorkManager, hãy xem Quản lý mã thông báo Gửi thông báo qua đám mây trên blog Firebase.
Bất kể bạn tuân theo mẫu thời gian nào, hãy nhớ cập nhật mã thông báo định kỳ. Tần suất cập nhật một lần mỗi tháng giúp cân bằng tốt giữa tác động đến pin và việc phát hiện mã thông báo đăng ký không hoạt động. Bằng cách làm mới này, bạn cũng đảm bảo rằng mọi thiết bị không hoạt động sẽ làm mới thông tin đăng ký khi hoạt động trở lại. Việc làm mới thường xuyên hơn hằng tuần không mang lại lợi ích gì.
Xoá mã thông báo đăng ký đã lỗi thời
Trước khi gửi thông báo đến một thiết bị, hãy đảm bảo rằng dấu thời gian của mã thông báo đăng ký của thiết bị nằm trong khoảng thời gian lỗi thời. Ví dụ: bạn
có thể triển khai Cloud Functions for Firebase để chạy kiểm tra hằng ngày nhằm đảm bảo rằng
dấu thời gian nằm trong khoảng thời gian lỗi thời đã xác định, chẳng hạn như const
EXPIRATION_TIME = 1000 * 60 * 60 * 24 * 30; sau đó xoá mã thông báo đã lỗi thời:
exports.pruneTokens = functions.pubsub.schedule('every 24 hours').onRun(async (context) => {
// Get all documents where the timestamp exceeds is not within the past month
const staleTokensResult = await admin.firestore().collection('fcmTokens')
.where("timestamp", "<", Date.now() - EXPIRATION_TIME)
.get();
// Delete devices with stale tokens
staleTokensResult.forEach(function(doc) { doc.ref.delete(); });
});
Huỷ đăng ký mã thông báo đã lỗi thời khỏi các chủ đề
Nếu sử dụng chủ đề, bạn cũng có thể muốn huỷ đăng ký mã thông báo đã lỗi thời khỏi các chủ đề mà mã thông báo đó đã đăng ký. Việc này bao gồm 2 bước:
- Ứng dụng của bạn phải đăng ký lại các chủ đề mỗi tháng một lần và bất cứ khi nào mã thông báo đăng ký thay đổi. Điều này tạo thành một giải pháp tự khắc phục, trong đó các gói thuê bao sẽ tự động xuất hiện lại khi một ứng dụng hoạt động trở lại.
- Nếu một thực thể ứng dụng không hoạt động trong một tháng (hoặc khoảng thời gian lỗi thời của riêng bạn), bạn nên huỷ đăng ký thực thể đó khỏi các chủ đề bằng Firebase Admin SDK để xoá mã thông báo khỏi việc ánh xạ chủ đề từ phần phụ trợ FCM.
Lợi ích của 2 bước này là các hoạt động phân phát của bạn sẽ diễn ra nhanh hơn vì có ít mã thông báo đã lỗi thời hơn để phân phát và các thực thể ứng dụng đã lỗi thời sẽ tự động đăng ký lại khi hoạt động trở lại.
Đo lường mức độ thành công của việc phân phối
Để có được bức tranh chính xác nhất về việc phân phối thông báo, tốt nhất là bạn chỉ nên gửi thông báo đến các thực thể ứng dụng được sử dụng tích cực. Điều này đặc biệt quan trọng nếu bạn thường xuyên gửi thông báo đến các chủ đề có số lượng lớn người đăng ký; nếu một phần người đăng ký đó thực sự không hoạt động, thì tác động đến số liệu thống kê phân phối có thể rất đáng kể theo thời gian.
Trước khi nhắm mục tiêu thông báo đến một mã thông báo, hãy cân nhắc:
- Google Analytics, dữ liệu được thu thập trong BigQuery hoặc các tín hiệu theo dõi khác có cho biết mã thông báo đang hoạt động không?
- Các lần thử phân phối trước đó có liên tục không thành công trong một khoảng thời gian không?
- Mã thông báo đăng ký có được cập nhật trên máy chủ của bạn trong tháng qua không?
- Đối với thiết bị Android, FCM Data API
có báo cáo tỷ lệ thất bại cao trong việc phân phối thông báo do
droppedDeviceInactivekhông?
Để biết thêm thông tin về việc phân phối, hãy xem Tìm hiểu về việc phân phối thông báo.