Các phương pháp hay nhất để quản lý việc đăng ký FCM

Nếu sử dụng FCM API để 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ó 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 để 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ệ.

Thông tin đăng ký cũ và đã hết hạn

Thông tin đăng ký cũ được liên kết với các thiết bị không hoạt động 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 Các lần gửi thông báo và phân phát chủ đề cho những thông tin đăng ký cũ này khó có thể được phân phối.

Có một số lý do khiến thông tin đăng ký có thể trở nên lỗi thời. Ví dụ: thiết bị được liên kết với thông tin đăng ký có thể bị mất, bị hỏng hoặc bị cất vào kho và bị quên.

Đối với Android, khi một thông tin đăng ký không hoạt động trong 270 ngày, FCM sẽ coi thông tin đó là đã hết hạn và thu gom rác. Sau khi thông tin đăng ký hết hạn, FCM sẽ đánh dấu thông tin đó là không hợp lệ và từ chối gửi đến thông tin đó. Xin lưu ý rằng chính dịch vụCài đặt Firebase (FIS) quản lý Mã cài đặt Firebase (FID), chứ không phải FCM. 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ở sau khi thông tin đăng ký của thiết bị đã được thu gom rác, ứng dụng khách sẽ đăng ký lại với FCM bằng FID được truy xuất từ FIS. Xin lưu ý rằng FID có thể thay đổi; hãy xem bài viết Quản lý các 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ụ: APNs), 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ì thông tin đăng ký mới và xoá thông tin đăng ký cũ.

Các phương pháp hay cơ bản

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 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ã cài đặt Firebase (FID) từ FCM và lưu trữ trên máy chủ ứng dụng. 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 khách 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 đó mỗi khi tải thông tin đăng ký lên.
  • Duy trì thông tin đăng ký mới và xoá thông tin đăng ký cũ. Ngoài việc xoá những thông tin đă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 thông tin đăng ký đã trở nên cũ và chủ động xoá những thông tin đó. 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ã cài đặt Firebase

Khi khởi động ứng dụng lần đầu, SDK FCM sẽ đăng ký thực thể ứng dụng với FCM và trả về Mã cài đặt Firebase (FID). Đây là mã nhận dạng mà bạn phải đưa vào các yêu cầu gửi có mục tiêu từ API hoặc sử dụng cho gói thuê bao 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 mỗi khi tải FID 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 lần gần đây nhất thực thể ứng dụng được mở và đồng bộ hoá thành công với phần phụ trợ FCM.

Tuỳ thuộc vào việc bạn bật hay tắt tính năng tự động khởi chạy (bao gồm cả trường hợp không được hỗ trợ), bạn nên xử lý thông tin đăng ký và bản cập nhật như sau:

  • (Nên dùng) Khi bật tính năng tự động khởi chạy: SDK sẽ tự động duy trì thông tin đăng ký mới và theo dõi các thay đổi. Hàm callback được gọi thường xuyên trên các lần đồng bộ hoá định kỳ trong quá trình khởi động ứng dụng, cũng như khi FID thay đổi.onRegistered() Chỉ cần triển khai hàm callback này để tải FID lên máy chủ và lưu dấu thời gian hiện tại.
  • Khi tắt tính năng tự động khởi chạy: Hàm onRegistered() callback sẽ không tự động được gọi khi khởi động. Để theo dõi thông tin đăng ký và duy trì thông tin đăng ký mới, hãy gọi register() khi khởi động ứng dụng; ví dụ: trên Android, trong `onCreate()` của hoạt động chính. onCreate(). Lệnh gọi thành công sẽ kích hoạt quy trình đăng ký FCM bằng FID và phân phối FID đó đến hàm callback onRegistered(), 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ể sử dụng Cloud Firestore để lưu trữ FID trong một tập hợp có tên là fcmRegistrations. Mỗi mã tài liệu trong tập hợp tương ứng với một mã người dùng và tài liệu lưu trữ FID 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:

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)
}

Mỗi khi Mã cài đặt Firebase được đăng ký hoặc cập nhật thành công, the onRegistered() callback sẽ được gọi. Bạn nên triển khai hàm callback 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 các thực thể tắt tính năng tự động khởi chạy, 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à phân phố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ì thông tin đăng ký mới và xoá thông tin đăng ký cũ

Không phải lúc nào cũng xác định được thông tin đăng ký mới hay cũ. Để 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 thông tin đăng ký là cũ. Theo mặc định, FCM coi một thông tin đăng ký là cũ nếu thực thể ứng dụng của thông tin đó chưa kết nối trong một tháng. Mọi thông tin đăng ký 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 thông tin đăng ký.

Tuỳ thuộc vào trường hợp sử dụng, một tháng có thể quá ngắn hoặc quá dài. Vì vậy, bạn phải 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

Hãy nhớ 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 thông tin đăng ký đã biết là không hợp lệ hoặc đã hết hạn khỏi hệ thống của bạn. Với API HTTP v1, các 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 mục tiêu đến các thông tin đă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 là hợp lệ và bạn nhận được một trong các phản hồi này cho thông tin đăng ký được nhắm mục tiêu, thì bạn có thể xoá bản ghi của thông tin đăng ký này, vì thông tin đó sẽ không bao giờ hợp lệ nữa. Ví dụ: để xoá thông tin đă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 trả về phản hồi không hợp lệ nếu thông tin đăng ký cho thiết bị Android đã hết hạn sau 270 ngày không hoạt động hoặc nếu ứng dụng khách đã 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 cũ theo định nghĩa của riêng bạn, bạn có thể chủ động xoá thông tin đăng ký cũ.

Cập nhật thông tin đăng ký thường xuyên

Bất kể thông tin đă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 phải luôn cập nhật dấu thời gian đăng ký trong cơ sở dữ liệu 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:

Đối với các ứng dụng khách sử dụng API FID, bạn không cần lên lịch cho các công việc nền định kỳ trong ứng dụng khách để truy xuất hoặc làm mới thông tin đăng ký. SDK sẽ tự động xử lý các lần làm mới trong quá trình tự động khởi chạy, thường xuyên phân phối FID hiện tại chính xác đến hàm callback onRegistered() trên các lần đồng bộ hoá định kỳ trong quá trình khởi động ứng dụng.

Để cập nhật máy chủ, hãy triển khai các chiến lược tải lên khi khởi động được trình bày chi tiết trong bài viết Truy xuất và lưu trữ Mã cài đặt Firebase IDs:

  • Đã 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 trên các lần đồng bộ hoá định kỳ trong quá trình khởi động ứng dụng.
  • Đã tắt tính năng tự động khởi chạy hoặc không được hỗ trợ: Gọi register() khi khởi động ứng dụng (ví dụ: trên Android, trong onCreate()) của hoạt động chính) để buộc trình tự đăng ký và kích hoạt việc phân phối FID đến hàm callback onRegistered() 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 các lần 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ã thông báo đă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ách sẽ không tự động quản lý các lần làm mới trên các lần đồng bộ hoá định kỳ. Vì vậy, bạn nên 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 theo định kỳ. 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ặc getToken() cho Android), sau đó gửi mã thông báo hiện tại đến máy chủ ứng dụng để lưu trữ (kèm theo dấu thời gian). Đây có thể là công việc hằng tháng được định cấu hình để bao gồm tất cả ứng dụng khách 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.

Để 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 Giải pháp 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 theo đị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 thiết bị 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á thông tin đăng ký 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 của thông tin đăng ký của thiết bị nằm trong khoảng thời gian cũ. 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 cũ đã xác định, chẳng hạn như const EXPIRATION_TIME = 1000 * 60 * 60 * 24 * 30; sau đó xoá thông tin đă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(); });
});
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ý các thông tin đăng ký cũ khỏi chủ đề

Nếu sử dụng chủ đề, bạn cũng có thể muốn huỷ đăng ký các thông tin đăng ký cũ khỏi các chủ đề mà chúng đã đăng ký. Việc này bao gồm 2 bước:

  1. Ứng dụng của bạn phải đăng ký lại các chủ đề mỗi khi Mã 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 ứng dụng hoạt động trở lại.
  2. 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 cũ 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ối liên kết giữa Mã cài đặt Firebase và chủ đề khỏi FCM phần phụ trợ.

Lợi ích của 2 bước này là các lần phân phát của bạn sẽ diễn ra nhanh hơn vì có ít thông tin đăng ký cũ hơn để phân phát và các thực thể ứ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 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 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ê phân phối của bạn có thể đáng kể theo thời gian.

Trước khi nhắm mục tiêu thông báo đến một thực thể ứng dụng, 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 thông tin đăng ký đ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ã 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 thiết bị Android, API Dữ liệu FCM có báo cáo tỷ lệ cao về lỗi phân phối thông báo do droppedDeviceInactive không?

Để biết thêm thông tin về việc phân phối, hãy xem bài viết Tìm hiểu về việc phân phối thông báo.