Firebase (FCM) cách nhận mã thông báo


97

Đây là lần đầu tiên tôi sử dụng FCM.

Tôi tải xuống một mẫu từ firebase / quickstart-android và cài đặt FCM Quickstart. Nhưng tôi không thể nhận được bất kỳ mã thông báo nào từ nhật ký thậm chí nhấn vào nút ĐĂNG NHẬP TOKEN trong ứng dụng.

Sau đó, tôi cố gắng gửi tin nhắn bằng bảng điều khiển Firebase và đặt để nhắm mục tiêu tên gói ứng dụng của mình. Tôi nhận được tin nhắn đến.

Tôi muốn biết FCM có thể được sử dụng không? GCM mọi thứ đều ổn.

Giải pháp:

Bởi vì tôi không phải là nhà phát triển Android, chỉ là một nhà phát triển phụ trợ. Vì vậy, tôi phải mất một thời gian để giải quyết nó. Theo tôi, có một số lỗi trong ứng dụng mẫu.

nhập mô tả hình ảnh ở đây

Mã :

RegisterIntentService.java

public class RegistrationIntentService extends IntentService {

    private static final String TAG = "RegIntentService";


    public RegistrationIntentService() {
        super(TAG);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        String token = FirebaseInstanceId.getInstance().getToken();
        Log.i(TAG, "FCM Registration Token: " + token);
    }
}

MyFirebaseInstanceIDService.java

public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {

    private static final String TAG = "MyFirebaseIIDService";

    /**
     * Called if InstanceID token is updated. This may occur if the security of
     * the previous token had been compromised. Note that this is called when the InstanceID token
     * is initially generated so this is where you would retrieve the token.
     */
    // [START refresh_token]
    @Override
    public void onTokenRefresh() {
        // Get updated InstanceID token.
//        String refreshedToken = FirebaseInstanceId.getInstance().getToken();
//        Log.d(TAG, "Refreshed token: " + refreshedToken);
//
//        // TODO: Implement this method to send any registration to your app's servers.
//        sendRegistrationToServer(refreshedToken);
//
        Intent intent = new Intent(this, RegistrationIntentService.class);
        startService(intent);
    }
    // [END refresh_token]

    /**
     * Persist token to third-party servers.
     * <p>
     * Modify this method to associate the user's FCM InstanceID token with any server-side account
     * maintained by your application.
     *
     * @param token The new token.
     */
    private void sendRegistrationToServer(String token) {
        // Add custom implementation, as needed.
    }
}

Thêm điều này vào MainActivity.java.

 Intent intent = new Intent(this, RegistrationIntentService.class);
        startService(intent);

Sau khi làm ở trên , bạn nhận được Mã thông báo trong Logcat. Nhưng cuối cùng, tôi tìm thấy một cách thuận tiện để lấy nó. Chỉ cần sử dụng chế độ gỡ lỗi để cài đặt ứng dụng mẫu và bạn có thể nhận được mã thông báo khi cài đặt lần đầu.

Nhưng không hiểu sao khi cài đặt nó không in được log. Có thể liên quan đến hệ thống di động.

Và tại sao tôi không thể nhận được Thông báo. FirebaseMessagingService.onMessageReceive đã không gọi sendNotification


nếu bản ghi được hit, nó sẽ hiển thị các mã thông báo với nó trong ứng dụng mẫu
Shubhank

Không, ứng dụng mẫu cho biết. Nó sẽ chỉ hiển thị mã thông báo trong logcat nếu tôi nhấn nút. Nhưng tôi thấy không có gì trong logcat @ Shubhank.
wyx

bỏ ghi chú dòng này String refreshedToken = FirebaseInstanceId.getInstance().getToken(); Log.d(TAG, "Refreshed token: " + refreshedToken);
Gaurav

Câu trả lời:


127

NHANH NHẤT VÀ TỐT NHẤT CHO LOẠI KHUYẾN MÃI

Giải pháp nhanh chóng là lưu trữ nó trong sharedPrefs và thêm logic này vào onCreatephương thức trong MainActivity hoặc lớp đang mở rộng Ứng dụng của bạn.

FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(this, instanceIdResult -> {
    String newToken = instanceIdResult.getToken();
    Log.e("newToken", newToken);
    getActivity().getPreferences(Context.MODE_PRIVATE).edit().putString("fb", newToken).apply();
});

Log.d("newToken", getActivity().getPreferences(Context.MODE_PRIVATE).getString("fb", "empty :("));

CÁCH LÀM SẠCH HƠN

Một lựa chọn tốt hơn là tạo một dịch vụ và giữ bên trong một logic tương tự. Đầu tiên tạo Dịch vụ mới

public class MyFirebaseMessagingService extends FirebaseMessagingService {

    @Override
    public void onNewToken(String s) {
        super.onNewToken(s);
        Log.e("newToken", s);
        getSharedPreferences("_", MODE_PRIVATE).edit().putString("fb", s).apply();
    }

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);
    }

    public static String getToken(Context context) {
        return context.getSharedPreferences("_", MODE_PRIVATE).getString("fb", "empty");
    }
}

Và sau đó thêm nó vào tệp AndroidManifest

<service
        android:name=".MyFirebaseMessagingService"
        android:stopWithTask="false">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
</service>

Cuối cùng, bạn có thể sử dụng một phương thức tĩnh từ Dịch vụ của mình MyFirebaseMessagingService.getToken(Context);

NHANH NHẤT NHƯNG KHÔNG ĐƯỢC

Log.d("Firebase", "token "+ FirebaseInstanceId.getInstance().getToken());

Nó vẫn hoạt động khi bạn đang sử dụng thư viện firebase cũ hơn phiên bản 17.xx


6
Nhưng cách tiếp cận thứ hai chỉ hoạt động cho đến khi các tùy chọn được chia sẻ bị xóa. Điều gì sẽ xảy ra nếu dữ liệu ứng dụng bị xóa và giá trị chuỗi đó bị mất? Android không gọi "onNewtoken ()" vì không có mã thông báo mới . Nhưng sau đó làm thế nào để chúng tôi yêu cầu mã thông báo? Ở mọi nơi nó nói "chỉ sử dụng onNewToken ()" nhưng phương thức đó chỉ chạy khi có mã thông báo mới . Giả sử rằng phương thức đó đã chạy, nhưng chúng tôi không bận tâm đến việc lưu trữ mã thông báo. Sau đó, chúng tôi thực hiện kiểm tra và thấy rằng mã thông báo chưa được đặt, sau đó thì sao? Làm cách nào để kích hoạt FCM cho tôi biết lại mã thông báo?
JeneralJames


1
Bạn có thể sử dụng FirebaseInstanceId.getInstance().getInstanceId()thay vì FirebaseInstanceId.getInstance().getToken(), hãy xem câu trả lời này
Vadim Kotov

@JeneralJames nếu người dùng xóa dữ liệu ứng dụng thì onNewTokensẽ luôn được kích hoạt, từ tài liệu tại đây firebase.google.com/docs/cloud-messaging/android/…
sarah

26

Nhóm đằng sau Firebase Android SDK thay đổi API một chút. Tôi đã triển khai logic "Mã thông báo tới Máy chủ" như sau:

Trong phiên bản FirebaseMessagingService của tôi:

public class FirebaseCloudMessagingService extends FirebaseMessagingService {

    ...

    @Override
    public void onNewToken(String token) {
        // sending token to server here
    }

    ...

}

Hãy nhớ rằng mã thông báo dành cho mỗi thiết bị và nó có thể được cập nhật bởi Firebase bất kể logic đăng nhập của bạn là gì. Vì vậy, nếu bạn có chức năng Đăng nhập và Đăng xuất, bạn phải xem xét các trường hợp bổ sung:

  1. Khi người dùng mới đăng nhập, bạn cần liên kết mã thông báo với người dùng mới (gửi nó đến máy chủ). Vì mã thông báo có thể được cập nhật trong phiên của người dùng cũ và máy chủ không biết mã thông báo của người dùng mới.
  2. Khi người dùng đăng xuất, bạn cần hủy liên kết mã thông báo. Bởi vì người dùng sẽ không nhận được thông báo / tin nhắn nữa.

Sử dụng API mới, bạn có thể nhận được mã thông báo như sau:

FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
        @Override
        public void onSuccess(InstanceIdResult instanceIdResult) {
            String token = instanceIdResult.getToken();
            // send it to server
        }
    });

Chúc may mắn!


Cố gắng lấy giá trị bên ngoài OnSuccess sẽ cho ra giá trị rỗng.
DragonFire

Chức năng đăng nhập / đăng xuất không liên quan gì đến Thông điệp đẩy, đây là một trường hợp sử dụng kinh doanh cụ thể. Ví dụ: bạn có thể muốn nhắm mục tiêu người dùng đã đăng xuất bằng một số thông báo tiếp thị / quảng cáo để khiến họ đăng nhập lại vào ứng dụng, trong trường hợp này, bạn sẽ cần mã thông báo FCM. Nhưng câu trả lời là chính xác về mặt nhận mã thông báo.
milosmns

@milosmns, bạn đã đúng về thông báo tiếp thị / quảng cáo. Vẫn cần một dấu hiệu về trạng thái mã thông báo. Giải pháp đơn giản sẽ là lưu trữ các mã thông báo chưa bị ràng buộc trong một số loại bảng lịch sử và sau đó sử dụng các mã thông báo trong quá khứ đó để khuyến khích sử dụng để đăng nhập lại.
rzaaeeff

Tôi không chắc thực sự là bạn có thể sử dụng lại cùng một mã thông báo trong bao lâu và chính xác thì khi nào nó bị vô hiệu. Điều này đáng để điều tra, vì tôi đoán bạn cần phải xóa bảng lịch sử / bộ nhớ cache / sự tồn tại này khi các mã thông báo trở nên không hợp lệ.
milosmns

@milosmns, trong Firebaseland, mã thông báo không hết hạn mà được gia hạn. Khi bạn kích hoạt bất kỳ hoạt động nào liên quan đến mã thông báo với API FCM, mã thông báo đã cung cấp sẽ được xác thực. Nếu mã thông báo không hợp lệ, bạn sẽ nhận được lỗi: MissingRegistration hoặc lỗi: InvalidRegistration. Bạn có thể tìm thêm mã lỗi tại đây: firebase.google.com/docs/cloud-messaging/…
rzaaeeff

24

Thông tin quan trọng.

nếu dịch vụ google play bị treo hoặc không chạy, thì fcm return token = null

Nếu dịch vụ phát hoạt động bình thường thì FirebaseInstanceId.getInstance().getToken()phương thức trả vềtoken

Log.d("FCMToken", "token "+ FirebaseInstanceId.getInstance().getToken());

Có, Nhưng điều này xảy ra rất thường xuyên
Hoàng Đức Tuấn

Mã thông báo được lưu vào bộ nhớ đệm (rất có thể là trong bản ghi nhớ) sau khi nó được tìm nạp một lần. Vì vậy, điều này có nghĩa là bạn cần tìm nạp nó một lần hoặc yêu cầu Firebase cấp lại một mã thông báo khác cho bạn bằng cách nào đó. Xem tại đây để biết cách tìm nạp thủ công stackoverflow.com/a/51630819/2102748
milosmns

13

Theo doc

Di chuyển ứng dụng khách GCM sang FCM

onTokenRefresh()

chỉ Được gọi nếu mã thông báo InstanceID được cập nhật

Vì vậy, nó sẽ chỉ gọi lần đầu tiên khi bạn cài đặt ứng dụng vào thiết bị của mình.

Vì vậy, tôi khuyên bạn hãy gỡ cài đặt ứng dụng của bạn theo cách thủ công và thử chạy lại

chắc chắn bạn sẽ nhận được TOKEN


2
không cài đặt lại, gỡ bỏ cài đặt nó bằng tay sau đó chạy dự án,
Gaurav

bỏ ghi chú dòng này String refreshedToken = FirebaseInstanceId.getInstance().getToken(); Log.d(TAG, "Refreshed token: " + refreshedToken);
Gaurav

1
@Gaurav, Làm cách nào để nhận mã thông báo sau lần đăng nhập thứ hai? onTokenRefreshkhông gọi mỗi lần đăng nhập. làm cách nào để lấy mã thông báo trong màn hình đăng nhập?
delavega66

3
@ de_la_vega_66, Bạn phải lưu trữ mã thông báo của mình trong lần đăng nhập đầu tiên
Gaurav

Dịch vụ mở rộng FirebaseInstanceIdService của bạn và có phương thức gọi lại onTokenRefresh () PHẢI được đăng ký trong tệp kê khai: <service android: name = "com.mypackage.name.MyInstanceIdService" android: export = "true"> <intent-filter> <action android: name = "com.google.firebase.INSTANCE_ID_EVENT" /> </intent-filter> </service>
Kirill Karmazin

9

Thử đi. Tại sao bạn đang sử dụng RegistrationIntentService?

public class FirebaseInstanceIDService extends FirebaseInstanceIdService {    
    @Override
    public void onTokenRefresh() {    
        String token = FirebaseInstanceId.getInstance().getToken();    
        registerToken(token);
    }

    private void registerToken(String token) {

    }
}

8

Dòng này sẽ giúp bạn nhận được mã thông báo FCM firebase.

String token = FirebaseInstanceId.getInstance().getToken();
Log.d("MYTAG", "This is your Firebase token" + token);

Thực hiện Log.d để in nó ra màn hình Android.


Nó trả về null
Kishan Solanki

7

Thay vì điều này:

    // [START refresh_token]
    @Override
    public void onTokenRefresh() {
//        Get updated InstanceID token.
//        String refreshedToken = FirebaseInstanceId.getInstance().getToken();
//        Log.d(TAG, "Refreshed token: " + refreshedToken);
//
//        TODO: Implement this method to send any registration to your app's servers.
//        sendRegistrationToServer(refreshedToken);
//
        Intent intent = new Intent(this, RegistrationIntentService.class);
        startService(intent);
    }
    // [END refresh_token]

Làm cái này:

    // [START refresh_token]
    @Override
    public void onTokenRefresh() {
        // Get updated InstanceID token.
        String refreshedToken = FirebaseInstanceId.getInstance().getToken();
//        Log.d(TAG, "Refreshed token: " + refreshedToken);

        // Implement this method to send token to your app's server
       sendRegistrationToServer(refreshedToken);

    }
    // [END refresh_token]

Và một điều nữa:

Bạn cần gọi sendRegistrationToServer()phương thức sẽ cập nhật mã thông báo trên máy chủ, nếu bạn đang gửi thông báo đẩy từ máy chủ.

CẬP NHẬT:

Mã thông báo Firebase mới được tạo ( onTokenRefresh()được gọi) khi:

  • Ứng dụng xóa ID phiên bản
  • Ứng dụng được khôi phục trên thiết bị mới
  • Người dùng gỡ cài đặt / cài đặt lại ứng dụng
  • Người dùng xóa dữ liệu ứng dụng.

Tôi đã phải xóa Instance ID FirebaseInstanceId.getInstance () deleteInstanceId () nhưng có một LỖI DỊCH VỤ.
Hardik9850

2
Bạn cần chạy FirebaseInstanceId.getInstance().deleteInstanceId()trong một Chủ đề khác
rockar06

5

Đồng thời, đừng quên bao gồm điều này trong tệp kê khai của bạn để nhận mã thông báo id

<service
    android:name=".MyFirebaseInstanceIDService">
    <intent-filter>
        <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
    </intent-filter>
</service>

5

Phương pháp getToken()này không được dùng nữa. Bạn có thể sử dụng getInstanceId()thay thế.

Nếu bạn muốn xử lý kết quả khi yêu cầu instanceId(token), hãy kiểm tra mã này.

FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(instanceIdResult -> {
        if (instanceIdResult != null) {
            String token = instanceIdResult.getToken();
            if (!TextUtils.isEmpty(token)) {
                Log.d(TAG, "retrieve token successful : " + token);
            }
        } else{
            Log.w(TAG, "instanceIdResult should not be null..");
        }
    }).addOnFailureListener(e -> {
        //do something with e
    }).addOnCanceledListener(() -> {
        //request has canceled
    }).addOnCompleteListener(task -> Log.v(TAG, "task result : " + task.getResult().getToken()));

4

Trong firebase-messaging:17.1.0và mới hơn, FirebaseInstanceIdService không còn được dùng nữa, bạn có thể tải onNewTokenvề FirebaseMessagingServicelớp này như được giải thích trên https://stackoverflow.com/a/51475096/1351469

Nhưng nếu bạn muốn chỉ nhận mã thông báo bất kỳ lúc nào, thì bây giờ bạn có thể làm như sau:

FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener( this.getActivity(),  new OnSuccessListener<InstanceIdResult>() {
  @Override
  public void onSuccess(InstanceIdResult instanceIdResult) {
    String newToken = instanceIdResult.getToken();
    Log.e("newToken",newToken);
  }
});

Điều này có thể được trả lại, vì vậy các chức năng tương tự có thể được sử dụng ở nhiều nơi hoặc chúng ta phải sao chép và dán vì bản chất không đồng bộ của căn cứ hỏa lực
DragonFire

3

Nếu đang sử dụng một số chức năng xác thực của firebase, bạn có thể lấy mã thông báo bằng cách sử dụng sau:

//------GET USER TOKEN-------
FirebaseUser mUser = FirebaseAuth.getInstance().getCurrentUser();
mUser.getToken(true)
        .addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
            public void onComplete(@NonNull Task<GetTokenResult> task) {
                if (task.isSuccessful()) {
                    String idToken = task.getResult().getToken();
                      // ...
                }
            }
        });

Hoạt động tốt nếu người dùng đã đăng nhập. getCurrentUser ()


2

thử đi

FirebaseInstanceId.getInstance().instanceId.addOnSuccessListener(OnSuccessListener<InstanceIdResult> { instanceIdResult ->
             fcm_token = instanceIdResult.token}

1

đối với những người đến đây, đến nay FirebaseInstanceIdServicekhông còn được dùng nữa, hãy sử dụng thay thế:

public class MyFirebaseMessagingService extends FirebaseMessagingService {
    @Override
    public void onNewToken(String token) {
        Log.d("MY_TOKEN", "Refreshed token: " + token);

        // If you want to send messages to this application instance or
        // manage this apps subscriptions on the server side, send the
        // Instance ID token to your app server.
        // sendRegistrationToServer(token);
    }
}

và khai báo trong AndroidManifest

<application... >

<service android:name=".fcm.MyFirebaseMessagingService">
    <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>
</application>

1
FirebaseInstanceId.getInstance().getInstanceId().addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
            @Override
            public void onComplete(@NonNull Task<InstanceIdResult> task) {
                if (!task.isSuccessful()) {
                    Log.w(TAG, "getInstanceId failed", task.getException());
                    return;
                }

                // Get new Instance ID token
                String **token** = task.getResult().getToken();

            }
        });

-1

Bạn có thể sử dụng cách sau trong Firebase (FCM) để nhận mã thông báo:

FirebaseInstanceId.getInstance().getToken();

2
Phương thức getToken () không được dùng nữa! Câu trả lời hay nhất bây giờ là từ @rzaaeeff.
Damiii

-9
Settings.Secure.getString(getContentResolver(),
                     Settings.Secure.ANDROID_ID);

Mã đó là để lấy ID android của thiết bị, không phải mã thông báo firebase.
Syed Afeef
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.