Nếu sử dụng API FCM để tạo yêu cầu gửi theo phương thức lập trình, thì theo thời gian, bạn có thể thấy rằng mình đ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ó thông tin đăng ký cũ. 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 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 bạn có thể thực hiện để đả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ệ.
Thông tin đăng ký cũ và hết hạn
Các lượt đăng ký không còn hiệu lực được liên kết với những 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. Tin nhắn gửi và phân phối chủ đề cho những lượt đăng ký cũ này khó có thể được gửi.
Có một số lý do khiến quá trình đăng ký có thể trở nên lỗi thời. Ví dụ: thiết bị mà thông tin đăng ký được liên kết có thể bị mất, bị phá huỷ hoặc được cất vào kho và bị quên.
Đối với Android, khi một lượt đăng ký không hoạt động trong 270 ngày, FCMsẽ coi lượt đăng ký đó là đã hết hạn và thu thập rác. Sau khi hết hạn, FCM sẽ đánh dấu lượt đăng ký là không hợp lệ và từ chối gửi đến lượt đăng ký đó. Xin lưu ý rằng chính dịch vụ Cài đặt Firebase (FIS) chứ không phải FCM quản lý các Mã nhận dạng lượt cài đặt Firebase (FID). Trong trường hợp hiếm gặp là một thiết bị kết nối lại và ứng dụng được mở sau khi quá trình đăng ký của ứng dụng đã được thu gom rác, ứng dụng khách sẽ đăng ký lại bằng FCM bằng cách sử dụng FID được truy xuất từ FIS. Xin lưu ý rằng FID có thể thay đổi; hãy xem phần Quản lý lượt cài đặt Firebase để biết thông tin chi tiết về thời điểm FID được cấp lại.
Đố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ụ: APN), dịch vụ này không có thời gian hết hạn dựa trên thời gian không hoạt động là 270 ngày. Bạn nên chủ động duy trì trạng thái đăng ký mới nhất và xoá các lượt đăng ký cũ.
Các phương pháp cơ bản hay nhất
Bạn nên tuân theo một số phương pháp cơ bản trong mọi ứng dụng sử dụng API FCM để tạo yêu cầu gửi theo phương thức lập trình. Các phương pháp hay nhất chính là:
- Truy xuất mã nhận dạng lượt cài đặt Firebase (FID) từ FCM và lưu trữ mã nhận dạng đó trên máy chủ ứng dụng của bạn. Một vai trò quan trọng của máy chủ là theo dõi FID đã đăng ký của từng ứng dụng và duy trì danh sách FID đang hoạt động được cập nhật. Bạn nên triển khai dấu thời gian đăng ký trong cơ sở dữ liệu và cập nhật dấu thời gian này bất cứ khi nào bạn tải một bản đăng ký lên.
- Duy trì trạng thái đăng ký mới nhất và xoá các thông tin đăng ký cũ. Ngoài việc xoá những lượt đăng ký 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 lượt đăng ký đã trở nên cũ và chủ động xoá chúng. 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ã nhận dạng lượt cài đặt Firebase
Khi khởi động ứng dụng lần đầu, SDK FCM sẽ đăng ký phiên bản ứng dụng với FCM và trả về một Mã nhận dạng lượt cài đặt Firebase (FID). Đây là giá trị nhận dạng mà bạn phải thêm vào các yêu cầu gửi có mục tiêu từ API hoặc sử dụng cho các lượt đăng ký chủ đề.
Bạn nên lưu FID vào máy chủ ứng dụng cùng với dấu thời gian bất cứ khi nào FID được tải lên. Bằng cách cập nhật dấu thời gian trên mọi yêu cầu tải lên, máy chủ của bạn sẽ biết thời điểm phiên bản ứng dụng được mở gần đây nhất và đồng bộ hoá thành công với phần phụ trợ FCM.
Tuỳ thuộc vào việc tính năng khởi tạo tự động được bật hay tắt (kể cả khi không được hỗ trợ), bạn nên xử lý việc đăng ký và cập nhật như sau:
- (Nên dùng) Khi bật tính năng tự động khởi tạo: SDK sẽ tự động duy trì trạng thái đăng ký mới nhất và theo dõi các thay đổi. Lệnh gọi lại
onRegistered()được gọi thường xuyên trong quá trình đồng bộ hoá định kỳ khi khởi động ứng dụng, cũng như khi xảy ra thay đổi về FID. Bạn chỉ cần triển khai lệnh gọi lại này để tải FID lên máy chủ và lưu dấu thời gian hiện tại. - Khi tính năng tự động khởi tạo bị tắt: Lệnh gọi lại
onRegistered()sẽ không tự động được gọi khi bắt đầu. Để theo dõi các lượt đăng ký và luôn cập nhật các lượt đăng ký đó, hãy gọiregister()khi khởi động ứng dụng; ví dụ: trên Android, trongonCreate()của hoạt động chính. Một lệnh gọi thành công sẽ kích hoạt quy trình đăng ký FCM bằng cách sử dụng FID và gửi FID đó đến lệnh gọi lạionRegistered(), cho phép ứng dụng của bạn tải FID lên và cập nhật dấu thời gian trên máy chủ.
Ví dụ: lưu trữ FID và dấu thời gian trong Cloud Firestore
Ví dụ: bạn có thể dùng Cloud Firestore để lưu trữ FID trong một tập hợp có tên là fcmRegistrations. 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ữ FID hiện tại cùng dấu thời gian cập nhật gần đây nhất. Dùng hàm set như trong ví dụ này về Kotlin:
private fun sendRegistrationToServer(installationId: String?) {
// If you're running your own server, call API to send registration details and today's date for the user
// Example shown uses Firestore
// Add FID and timestamp to Firestore for this user
val deviceFid = hashMapOf(
"installationId" to installationId,
"timestamp" to FieldValue.serverTimestamp(),
)
// Get user ID from Firebase Auth or your own server
Firebase.firestore.collection("fcmRegistrations").document("myuserid")
.set(deviceFid)
}
Bất cứ khi nào một Mã nhận dạng lượt cài đặt Firebase được đăng ký hoặc cập nhật thành công, lệnh gọi lại onRegistered() sẽ được gọi. Bạn nên triển khai lệnh gọi lại này để tải FID lên và cập nhật dấu thời gian:
override fun onRegistered(installationId: String) {
Log.d(TAG, "Registered installation ID: $installationId")
// Send the Firebase Installation ID (FID) to your app server. Your app
// server should save the FID and update the timestamp upon receipt.
sendRegistrationToServer(installationId)
}
Đối với những trường hợp bạn tắt tính năng tự động khởi tạo, hãy gọi register() khi khởi động ứng dụng (ví dụ: trong onCreate()) để kích hoạt quy trình đăng ký và gửi FID thông qua onRegistered():
// Trigger manual registration if auto-initialization is turned off.
FirebaseMessaging.getInstance().register()
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
// The registration callback onRegistered() will be invoked with the current FID.
} else {
Log.w(TAG, "Failed to register with Firebase Cloud Messaging", task.exception)
}
}
Duy trì trạng thái đăng ký mới và xoá các trạng thái đăng ký cũ
Việc xác định xem một lượt đăng ký là mới hay cũ 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 cho thời điểm bạn coi các lượt đăng ký là cũ. Theo mặc định, FCM coi một lượt đăng ký là cũ nếu phiên bản ứng dụng của lượt đăng ký đó chưa kết nối trong một tháng. Mọi hoạt động đăng ký cũ hơn một tháng đều có khả năng là một thiết bị không hoạt động; nếu không, một thiết bị đang hoạt động sẽ làm mới hoạt động đăng ký của thiết bị đó.
Tuỳ thuộc vào trường hợp sử dụng của bạn, một tháng có thể 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 các phản hồi không hợp lệ từ phần phụ trợ FCM
Đảm bảo phát hiện các phản hồi không hợp lệ từ FCM và phản hồi bằng cách xoá mọi lượt đăng ký không hợp lệ hoặc đã hết hạn khỏi hệ thống của bạn. Với HTTP v1 API, những thông báo lỗi này có thể cho biết rằng yêu cầu gửi của bạn nhắm đến các lượt đăng ký 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 hợp lệ và bạn nhận được một trong những phản hồi này cho một lượt đăng ký có mục tiêu, thì bạn có thể xoá bản ghi của lượt đăng ký này vì lượt đăng ký đó sẽ không bao giờ hợp lệ nữa. Ví dụ: để xoá các lượt đăng ký 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:
// Firebase Installation ID comes from the client FCM SDKs
const firebaseInstallationId = 'YOUR_FIREBASE_INSTALLATION_ID';
const message = {
data: {
// Information you want to send inside of notification
},
fid: firebaseInstallationId
};
// Send message to device with provided Firebase Installation ID
getMessaging().send(message)
.then((response) => {
// Response is a message ID string.
})
.catch((error) => {
// Delete registration 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 registration for the user
// Example shown uses Firestore
// Get user ID from Firebase Auth or your own server
Firebase.firestore.collection("fcmRegistrations").document(user.uid).delete()
}
});
FCM sẽ trả về một phản hồi không hợp lệ nếu quá trình đăng ký cho một 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 độ cũ chính xác hơn theo định nghĩa của riêng bạn, bạn có thể chủ động xoá các lượt đăng ký cũ.
Thường xuyên cập nhật thông tin đăng ký
Bất kể việc đăng ký của bạn dựa trên FID hay mã thông báo đăng ký cũ, máy chủ của bạn luôn phải cập nhật dấu thời gian đăng ký trong cơ sở dữ liệu của bạn trên mọi yêu cầu tải lên. Dấu thời gian này đóng vai trò là tín hiệu cho quá trình cài đặt ứng dụng, cho phép ứng dụng khách mở ứng dụng thành công và đồng bộ hoá với phần phụ trợ FCM. Tuỳ thuộc vào API mà bạn đang sử dụng, hãy triển khai chiến lược phù hợp:
API Mã nhận dạng lượt cài đặt Firebase (nên dùng)
Đối với các ứng dụng khách sử dụng FID API, bạn không cần lên lịch các công việc định kỳ trên nền để truy xuất hoặc làm mới thông tin đăng ký trong ứng dụng khách. SDK sẽ tự động xử lý các hoạt động làm mới trong quá trình tự động khởi tạo, thường xuyên gửi FID hiện tại chính xác đến lệnh gọi lại onRegistered() của bạn trong quá trình đồng bộ hoá định kỳ khi khởi động ứng dụng.
Để máy chủ của bạn luôn được cập nhật, hãy triển khai các chiến lược tải lên khi khởi động như được trình bày chi tiết trong phần Truy xuất và lưu trữ mã nhận dạng lượt cài đặt Firebase:
- Đã bật tính năng tự động khởi chạy: SDK sẽ tự động đảm bảo rằng FID mới nhất được gửi đến máy chủ của bạn trong quá trình đồng bộ hoá định kỳ khi ứng dụng khởi động.
- Đã tắt hoặc không được hỗ trợ tính năng tự động khởi tạo: Gọi
register()khi khởi động ứng dụng (ví dụ: trên Android, trongonCreate()của hoạt động chính) để buộc trình tự đăng ký và kích hoạt việc gửi FID đến lệnh gọi lạionRegistered()của bạn.
Các chiến lược này đảm bảo máy chủ của bạn luôn có FID đang hoạt động mới nhất và có thể tự động khôi phục sau khi tải lên không thành công, giúp ứng dụng có khả năng phục hồi cao.
Các API mã đăng ký không dùng nữa
Nếu bạn đang sử dụng mã thông báo đăng ký cũ, thì SDK ứng dụng không tự động quản lý các lượt làm mới trong quá trình đồng bộ hoá định kỳ. Do đó, 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ủ của mình. Bạn cần phải:
- Thêm logic ứng dụng vào ứng dụng khách để truy xuất mã thông báo hiện tại bằ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 của bạn để lưu trữ (kèm theo 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ả các mã thông báo hoặc ứng dụng. - Thêm logic máy chủ để cập nhật dấu thời gian của mã thông báo theo các khoảng thời gian đều đặn, bất kể mã thông báo có thay đổi hay không.
Để xem ví dụ về logic Android để cập nhật mã thông báo cũ bằng WorkManager, hãy xem bài viết Quản lý mã thông báo Gửi thông báo qua đám mây trên blog Firebase.
Dù 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 là mỗi tháng một lần sẽ cân bằng tốt giữa mức tiêu thụ pin và việc phát hiện các 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ị chuyển sang trạng thái không hoạt động sẽ làm mới thông tin đăng ký khi hoạt động trở lại. Không có lợi ích gì khi làm mới thường xuyên hơn hằng tuần.
Xoá các lượt đăng ký không còn hiệu lực
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 đăng ký của thiết bị nằm trong khoảng thời gian cũ của bạn. Ví dụ: bạn có thể triển khai Cloud Functions for Firebase để chạy quy trình 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 cũ được xác định, chẳng hạn như const
EXPIRATION_TIME = 1000 * 60 * 60 * 24 * 30;, rồi xoá các lượt đăng ký cũ:
exports.pruneRegistrations = functions.pubsub.schedule('every 24 hours').onRun(async (context) => {
// Get all documents where the timestamp exceeds is not within the past month
const staleRegistrationsResult = await admin.firestore().collection('fcmRegistrations')
.where("timestamp", "<", Date.now() - EXPIRATION_TIME)
.get();
// Delete devices with stale registrations
staleRegistrationsResult.forEach(function(doc) { doc.ref.delete(); });
});
Huỷ đăng ký các lượt đăng ký không còn hiệu lực khỏi các chủ đề
Nếu sử dụng các chủ đề, bạn cũng nên huỷ đăng ký các lượt đăng ký không còn hiệu lực khỏi các chủ đề mà chúng đã đăng ký. Việc này bao gồm hai bước:
- Ứng dụng của bạn phải đăng ký lại các chủ đề bất cứ khi nào mã nhận dạng lượt cài đặt Firebase (FID) thay đổi. Điều này cho phép các gói thuê bao tự động xuất hiện lại khi một ứng dụng hoạt động trở lại.
- Nếu một phiên bản ứng dụng không hoạt động trong một tháng (hoặc khoảng thời gian không hoạt động do bạn đặt), bạn nên huỷ đăng ký phiên bản đó khỏi các chủ đề bằng Firebase Admin SDK để xoá mối liên kết giữa Firebase Installation ID và chủ đề khỏi phần phụ trợ FCM.
Lợi ích của hai bước này là các fanout sẽ diễn ra nhanh hơn vì có ít lượt đăng ký cũ hơn để fanout, đồng thời các phiên bản ứng dụng cũ 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 gửi tin nhắn, tốt nhất là bạn chỉ nên gửi tin nhắn đến các phiên bản ứng dụng đang được sử dụng. Đ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ó nhiều người đăng ký; nếu một phần trong số những người đăng ký đó thực sự không hoạt động, thì tác động đến số liệu thống kê về việc gửi thông báo có thể trở nên đáng kể theo thời gian.
Trước khi nhắm đến một phiên bản ứng dụng, hãy cân nhắc:
- Google Analytics, dữ liệu được ghi lại trong BigQuery hoặc các tín hiệu theo dõi khác có cho biết lượt đăng ký đang hoạt động không?
- Có phải các lần giao hàng trước đó đều không thành công trong một khoảng thời gian không?
- Mã nhận dạng lượt cài đặt Firebase có được cập nhật trên máy chủ của bạn trong tháng qua không?
- Đối với các thiết bị Android, FCM Data API có báo cáo tỷ lệ thất bại cao khi gửi thông báo do
droppedDeviceInactivekhông?
Để biết thêm thông tin về việc gửi, hãy xem bài viết Tìm hiểu về việc gửi tin nhắn.