Firebase (FCM) วิธีรับโทเค็น


98

นี่เป็นครั้งแรกของฉันที่ใช้ FCM

ฉันดาวน์โหลดตัวอย่างจากfirebase / quickstart-androidและติดตั้ง FCM Quickstart แต่ฉันไม่สามารถรับโทเค็นจากบันทึกได้แม้แต่กดปุ่มLOG TOKENในแอป

จากนั้นฉันพยายามส่งข้อความด้วยคอนโซล Firebase และตั้งเป้าหมายชื่อแพ็กเกจแอปของฉัน ฉันได้รับข้อความเข้า

อยากทราบว่า FCM ใช้ได้ไหม GCM ทุกอย่างโอเค

วิธีการแก้:

เนื่องจากฉันไม่ใช่นักพัฒนา Android เป็นเพียงนักพัฒนาแบ็กเอนด์ ฉันจึงต้องใช้เวลาพอสมควรในการแก้ไข ในความคิดของฉันมีข้อบกพร่องบางอย่างในแอปตัวอย่าง

ป้อนคำอธิบายภาพที่นี่

รหัส:

RegistrationIntentService.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.
    }
}

เพิ่มสิ่งนี้ใน MainActivity.java

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

หลังจากทำด้านบน, คุณจะได้รับ Token ใน Logcat แต่ในที่สุดฉันก็พบวิธีที่สะดวกที่จะได้รับ เพียงใช้โหมดดีบักเพื่อติดตั้งแอปตัวอย่างและคุณจะได้รับโทเค็นเมื่อติดตั้งครั้งแรก

แต่ฉันไม่รู้ว่าทำไมมันไม่สามารถพิมพ์บันทึกเมื่อฉันติดตั้งได้ อาจจะเกี่ยวข้องกับระบบมือถือ

แล้วทำไมฉันไม่ได้รับการแจ้งเตือน FirebaseMessagingService.onMessageReceivedไม่ได้เรียกsendNotification


หากบันทึกถูกตีมันจะแสดงโทเค็นพร้อมกับมันในแอพตัวอย่าง
Shubhank

ไม่แอปตัวอย่างกล่าวมันจะแสดงโทเค็นใน logcat ก็ต่อเมื่อฉันกดปุ่ม แต่ฉันไม่พบอะไรเลยใน logcat @ Shubhank
wyx

ไม่ใส่ข้อคิดเห็นบรรทัดนี้ String refreshedToken = FirebaseInstanceId.getInstance().getToken(); Log.d(TAG, "Refreshed token: " + refreshedToken);
Gaurav

คำตอบ:


129

เร็วที่สุดและดีสำหรับ PROTOTYPE

วิธีแก้ปัญหาอย่างรวดเร็วคือการจัดเก็บไว้ใน sharedPrefs และเพิ่มตรรกะนี้ลงonCreateในเมธอดใน MainActivity หรือคลาสของคุณซึ่งขยาย Application

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 :("));

วิธีทำความสะอาด

ตัวเลือกที่ดีกว่าคือการสร้างบริการและใช้ตรรกะที่คล้ายกัน ขั้นแรกให้สร้างบริการใหม่

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

จากนั้นเพิ่มลงในไฟล์ AndroidManifest

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

สุดท้ายคุณสามารถใช้วิธีการคงที่จากบริการของคุณ MyFirebaseMessagingService.getToken(Context);

เร็วที่สุด แต่เลิกใช้แล้ว

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

ยังคงใช้งานได้เมื่อคุณใช้ไลบรารี firebase รุ่นเก่ากว่าเวอร์ชัน 17.xx


6
แต่แนวทางที่สองจะใช้ได้จนกว่าจะล้างค่ากำหนดที่ใช้ร่วมกันเท่านั้น จะเกิดอะไรขึ้นหากล้างข้อมูลแอปและค่าสตริงนั้นหายไป Android ไม่เรียก "onNewtoken ()" เนื่องจากไม่มีโทเค็นใหม่ แต่แล้วเราจะขอโทเค็นได้อย่างไร? ทุกที่จะบอกว่า "just use onNewToken ()" แต่วิธีนั้นจะทำงานเมื่อมีโทเค็นใหม่ สมมติว่าเมธอดนั้นทำงานแล้ว แต่เราไม่ได้กังวลในการจัดเก็บโทเค็น หลังจากนั้นเราทำการตรวจสอบและดูว่าไม่ได้ตั้งค่าโทเค็นแล้วจะเป็นอย่างไร ฉันจะทริกเกอร์ FCM เพื่อบอกโทเค็นอีกครั้งได้อย่างไร
JeneralJames


1
คุณสามารถใช้FirebaseInstanceId.getInstance().getInstanceId()แทนได้FirebaseInstanceId.getInstance().getToken()ดูคำตอบนี้
Vadim Kotov

@JeneralJames หากผู้ใช้ล้างข้อมูลแอปonNewTokenจะถูกทริกเกอร์เสมอจากเอกสารในที่นี้firebase.google.com/docs/cloud-messaging/android/…
sarah

26

ทีมที่อยู่เบื้องหลัง Firebase Android SDK เปลี่ยน API เล็กน้อย ฉันได้ใช้ตรรกะ "Token to Server" ดังนี้:

ในอินสแตนซ์ของ FirebaseMessagingService ของฉัน:

public class FirebaseCloudMessagingService extends FirebaseMessagingService {

    ...

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

    ...

}

โปรดทราบว่าโทเค็นนั้นขึ้นอยู่กับอุปกรณ์และ Firebase สามารถอัปเดตได้โดยไม่คำนึงถึงตรรกะการเข้าสู่ระบบของคุณ ดังนั้นหากคุณมีฟังก์ชันการเข้าสู่ระบบและออกจากระบบคุณต้องพิจารณากรณีพิเศษ:

  1. เมื่อผู้ใช้ใหม่เข้าสู่ระบบคุณต้องผูกโทเค็นกับผู้ใช้ใหม่ (ส่งไปที่เซิร์ฟเวอร์) เนื่องจากโทเค็นอาจได้รับการอัปเดตในระหว่างเซสชันของผู้ใช้เก่าและเซิร์ฟเวอร์ไม่ทราบโทเค็นของผู้ใช้ใหม่
  2. เมื่อผู้ใช้ออกจากระบบคุณจะต้องเลิกผูกโทเค็น เนื่องจากผู้ใช้ไม่ควรรับการแจ้งเตือน / ข้อความอีกต่อไป

เมื่อใช้ API ใหม่คุณจะได้รับโทเค็นดังนี้:

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

โชคดี!


การพยายามรับค่าภายนอก OnSuccess กำลังให้ค่า null
DragonFire

ฟังก์ชันการเข้าสู่ระบบ / ออกจากระบบไม่มีส่วนเกี่ยวข้องกับข้อความ Push นี่เป็นกรณีการใช้งานทางธุรกิจเฉพาะ ตัวอย่างเช่นคุณอาจต้องการกำหนดเป้าหมายผู้ใช้ที่ออกจากระบบด้วยการแจ้งเตือนทางการตลาด / โปรโมชันเพื่อให้พวกเขากลับเข้าสู่ระบบแอปซึ่งในกรณีนี้คุณจะต้องใช้โทเค็น FCM แต่คำตอบนั้นถูกต้องในแง่ของการรับโทเค็น
milosmns

@milosmns คุณพูดถูกในแง่ของการแจ้งเตือนการตลาด / โปรโมชั่น ยังคงมีความจำเป็นสำหรับการบ่งชี้สถานะโทเค็น วิธีแก้ปัญหาง่ายๆคือการจัดเก็บโทเค็นที่ไม่ถูกผูกไว้ในตารางประวัติบางประเภทแล้วใช้โทเค็นที่ผ่านมาเหล่านั้นเพื่อกระตุ้นให้ใช้เพื่อกลับเข้าสู่ระบบ
rzaaeeff

ฉันไม่แน่ใจว่าจริงๆแล้วคุณจะใช้โทเค็นเดิมซ้ำได้นานแค่ไหนและเมื่อไหร่ที่โทเค็นจะใช้งานไม่ได้ นี่เป็นสิ่งที่ควรค่าแก่การตรวจสอบเนื่องจากฉันเดาว่าคุณจะต้องล้างประวัติ / แคช / ตารางการคงอยู่นี้เมื่อโทเค็นไม่ถูกต้อง
milosmns

@milosmns ใน Firebaseland โทเค็นไม่หมดอายุ แต่จะได้รับการต่ออายุ เมื่อคุณทริกเกอร์กิจกรรมที่เกี่ยวข้องกับโทเค็นด้วย FCM API โทเค็นที่ระบุจะได้รับการตรวจสอบ หากโทเค็นไม่ถูกต้องคุณจะได้รับข้อผิดพลาด: MissingRegistration หรือ error: InvalidRegistration คุณสามารถค้นหารหัสข้อผิดพลาดเพิ่มเติมได้ที่นี่: firebase.google.com/docs/cloud-messaging/...
rzaaeeff

24

ข้อมูลสำคัญ.

หากบริการ Google Play หยุดทำงานหรือไม่ทำงาน fcm return token = null

หากบริการการเล่นทำงานอย่างถูกต้องFirebaseInstanceId.getInstance().getToken()วิธีการส่งคืนtoken

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

ใช่ แต่สิ่งนี้เกิดขึ้นบ่อยมาก
Hoang Duc Tuan

โทเค็นถูกแคช (เป็นไปได้มากที่สุดในเมม) หลังจากที่ดึงข้อมูลมาแล้วหนึ่งครั้ง นั่นหมายความว่าคุณต้องดึงข้อมูลครั้งเดียวหรือให้ Firebase ออกโทเค็นใหม่ให้คุณอีกครั้ง ดูวิธีดึงข้อมูลด้วยตนเองได้ที่นี่stackoverflow.com/a/51630819/2102748
milosmns

13

ตามเอกสาร

ย้ายแอปไคลเอ็นต์ GCM ไปยัง FCM

onTokenRefresh()

เรียกเฉพาะเมื่อมีการอัปเดตโทเค็น InstanceID

ดังนั้นจะโทรเฉพาะในครั้งแรกเมื่อคุณติดตั้งแอปลงในอุปกรณ์ของคุณ

ดังนั้นฉันขอแนะนำให้ถอนการติดตั้งแอปของคุณด้วยตนเองแล้วลองเรียกใช้อีกครั้ง

แน่นอนคุณจะได้รับTOKEN


2
ไม่ติดตั้งใหม่ถอนการติดตั้งด้วยตนเองจากนั้นเรียกใช้โครงการ
Gaurav

ไม่ใส่ข้อคิดเห็นบรรทัดนี้ String refreshedToken = FirebaseInstanceId.getInstance().getToken(); Log.d(TAG, "Refreshed token: " + refreshedToken);
Gaurav

1
@Gaurav ฉันจะรับโทเค็นหลังจากล็อกอินครั้งที่สองได้อย่างไร onTokenRefreshไม่โทรหาแต่ละล็อกอิน ฉันจะรับโทเค็นในหน้าจอเข้าสู่ระบบได้อย่างไร?
delavega66

3
@ de_la_vega_66 คุณต้องจัดเก็บโทเค็นของคุณเมื่อเข้าสู่ระบบครั้งแรก
Gaurav

บริการของคุณที่ขยาย FirebaseInstanceIdService และมีวิธีการโทรกลับ onTokenRefresh () ต้องลงทะเบียนในไฟล์ Manifest: <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

ลองทำตามนี้ ทำไมคุณถึงใช้RegistrationIntentService?

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

    private void registerToken(String token) {

    }
}

8

บรรทัดนี้จะทำให้คุณได้รับโทเค็น Firebase FCM

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

ทำ Log.d เพื่อพิมพ์ออกไปยังจอภาพ Android


ส่งคืนค่าว่าง
Kishan Solanki

7

แทนสิ่งนี้:

    // [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]

ทำเช่นนี้:

    // [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]

และอีกสิ่งหนึ่ง:

คุณต้องเรียกsendRegistrationToServer()วิธีการซึ่งจะอัปเดตโทเค็นบนเซิร์ฟเวอร์หากคุณส่งการแจ้งเตือนแบบพุชจากเซิร์ฟเวอร์

อัพเดท:

โทเค็น Firebase ใหม่ถูกสร้างขึ้น ( onTokenRefresh()ถูกเรียก) เมื่อ:

  • แอปลบรหัสอินสแตนซ์
  • แอปได้รับการกู้คืนบนอุปกรณ์ใหม่
  • ผู้ใช้ถอนการติดตั้ง / ติดตั้งแอปใหม่
  • ผู้ใช้ล้างข้อมูลแอป

ฉันต้องลบรหัสอินสแตนซ์ FirebaseInstanceId.getInstance () deleteInstanceId () แต่ได้รับข้อผิดพลาดในการให้บริการ
Hardik9850

2
คุณต้องทำงานFirebaseInstanceId.getInstance().deleteInstanceId()ในเธรดอื่น
rockar06

6

ในขณะเดียวกันอย่าลืมรวมสิ่งนี้ไว้ในไฟล์ manifest ของคุณเพื่อรับรหัสโทเค็น

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

5

วิธีgetToken()นี้เลิกใช้แล้ว คุณสามารถใช้getInstanceId()แทน

หากคุณต้องการจัดการผลลัพธ์เมื่อร้องขอให้instanceId(token)ตรวจสอบรหัสนี้

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

ในfirebase-messaging:17.1.0และใหม่กว่า FirebaseInstanceIdService จะเลิกคุณจะได้รับonNewTokenในFirebaseMessagingServiceระดับตามที่อธิบายไว้ในhttps://stackoverflow.com/a/51475096/1351469

แต่ถ้าคุณต้องการรับโทเค็นเมื่อใดก็ได้ตอนนี้คุณสามารถทำได้ดังนี้:

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

สามารถส่งคืนได้หรือไม่ดังนั้นจึงสามารถใช้ฟังก์ชันเดียวกันในหลาย ๆ ที่ได้หรือเราต้องคัดลอกและวางเนื่องจากลักษณะของ
DragonFire

3

หากใช้ฟังก์ชัน auth ของ firebase คุณสามารถรับโทเค็นโดยใช้สิ่งนี้:

//------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();
                      // ...
                }
            }
        });

ทำงานได้ดีหากผู้ใช้เข้าสู่ระบบ getCurrentUser ()



1

สำหรับผู้ที่มาที่นี่ถึงตอนนี้FirebaseInstanceIdServiceเลิกใช้แล้วให้ใช้แทน:

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

และประกาศใน 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();

            }
        });

0

FirebaseInstanceId.getInstance().getInstanceId()จะเลิก จากเอกสาร firebaseคุณสามารถดึงโทเค็นการลงทะเบียนปัจจุบันโดยใช้รหัสต่อไปนี้:

FirebaseMessaging.getInstance().getToken()
    .addOnCompleteListener(new OnCompleteListener<String>() {
        @Override
        public void onComplete(@NonNull Task<String> task) {
          if (!task.isSuccessful()) {
            Log.w(TAG, "Fetching FCM registration token failed", task.getException());
            return;
          }

          // Get new FCM registration token
          String token = task.getResult();

          // Log and toast
          String msg = getString(R.string.msg_token_fmt, token);
          Log.d(TAG, msg);
          Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
        }
    });

-1

คุณสามารถใช้สิ่งต่อไปนี้ใน Firebase (FCM) เพื่อรับโทเค็น:

FirebaseInstanceId.getInstance().getToken();

2
getToken () เมธอดเลิกใช้งานแล้ว! คำตอบที่ดีที่สุดตอนนี้มาจาก @rzaaeeff
Damiii

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

รหัสนั้นคือการรับรหัส Android ของอุปกรณ์ไม่ใช่โทเค็น firebase
Syed Afeef
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.