ฉันกำลังย้ายแอปของฉันจาก GCM ไปยัง FCM
เมื่อผู้ใช้ใหม่ติดตั้งแอปของฉันonTokenRefresh()
ระบบจะเรียกแอปโดยอัตโนมัติ ปัญหาคือผู้ใช้ยังไม่ได้เข้าสู่ระบบ (ไม่มีรหัสผู้ใช้)
ฉันจะทริกเกอร์onTokenRefresh()
หลังจากผู้ใช้เข้าสู่ระบบได้อย่างไร
ฉันกำลังย้ายแอปของฉันจาก GCM ไปยัง FCM
เมื่อผู้ใช้ใหม่ติดตั้งแอปของฉันonTokenRefresh()
ระบบจะเรียกแอปโดยอัตโนมัติ ปัญหาคือผู้ใช้ยังไม่ได้เข้าสู่ระบบ (ไม่มีรหัสผู้ใช้)
ฉันจะทริกเกอร์onTokenRefresh()
หลังจากผู้ใช้เข้าสู่ระบบได้อย่างไร
คำตอบ:
onTokenRefresh()
วิธีการที่เป็นไปได้เรียกว่าเมื่อใดก็ตามที่โทเค็นใหม่จะถูกสร้างขึ้น เมื่อติดตั้งแอปแล้วแอปจะถูกสร้างขึ้นทันที (ตามที่คุณพบ) นอกจากนี้ยังจะถูกเรียกเมื่อโทเค็นมีการเปลี่ยนแปลง
ตามFirebaseCloudMessaging
คู่มือ:
คุณสามารถกำหนดเป้าหมายการแจ้งเตือนไปยังอุปกรณ์เครื่องเดียวโดยเฉพาะ ในการเริ่มต้นแอปของคุณ FCM SDK จะสร้างโทเค็นการลงทะเบียนสำหรับอินสแตนซ์แอปไคลเอ็นต์
ลิงก์แหล่งที่มา: https://firebase.google.com/docs/notifications/android/console-device#access_the_registration_token
ซึ่งหมายความว่าการลงทะเบียนโทเค็นเป็นไปตามแอป ดูเหมือนว่าคุณต้องการใช้โทเค็นหลังจากผู้ใช้เข้าสู่ระบบสิ่งที่ฉันอยากแนะนำคือให้คุณบันทึกโทเค็นในonTokenRefresh()
วิธีการลงในที่จัดเก็บข้อมูลภายในหรือค่ากำหนดที่ใช้ร่วมกัน จากนั้นเรียกข้อมูลโทเค็นจากที่เก็บข้อมูลหลังจากผู้ใช้เข้าสู่ระบบและลงทะเบียนโทเค็นกับเซิร์ฟเวอร์ของคุณตามต้องการ
หากคุณต้องการบังคับด้วยตนเองonTokenRefresh()
คุณสามารถสร้าง IntentService และลบอินสแตนซ์โทเค็นได้ จากนั้นเมื่อคุณเรียก getToken onTokenRefresh()
เมธอดจะถูกเรียกอีกครั้ง
ตัวอย่างรหัส:
public class DeleteTokenService extends IntentService
{
public static final String TAG = DeleteTokenService.class.getSimpleName();
public DeleteTokenService()
{
super(TAG);
}
@Override
protected void onHandleIntent(Intent intent)
{
try
{
// Check for current token
String originalToken = getTokenFromPrefs();
Log.d(TAG, "Token before deletion: " + originalToken);
// Resets Instance ID and revokes all tokens.
FirebaseInstanceId.getInstance().deleteInstanceId();
// Clear current saved token
saveTokenToPrefs("");
// Check for success of empty token
String tokenCheck = getTokenFromPrefs();
Log.d(TAG, "Token deleted. Proof: " + tokenCheck);
// Now manually call onTokenRefresh()
Log.d(TAG, "Getting new token");
FirebaseInstanceId.getInstance().getToken();
}
catch (IOException e)
{
e.printStackTrace();
}
}
private void saveTokenToPrefs(String _token)
{
// Access Shared Preferences
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor editor = preferences.edit();
// Save to SharedPreferences
editor.putString("registration_id", _token);
editor.apply();
}
private String getTokenFromPrefs()
{
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
return preferences.getString("registration_id", null);
}
}
แก้ไข
FirebaseInstanceIdService
คลาสสาธารณะ FirebaseInstanceIdService ขยายบริการ
คลาสนี้เลิกใช้แล้ว ในการลบล้าง onNewToken ใน FirebaseMessagingService เมื่อดำเนินการแล้วบริการนี้สามารถลบออกได้อย่างปลอดภัย
onTokenRefresh () จะเลิก ใช้onNewToken()
ในMyFirebaseMessagingService
public class MyFirebaseMessagingService extends FirebaseMessagingService {
@Override
public void onNewToken(String s) {
super.onNewToken(s);
Log.e("NEW_TOKEN",s);
}
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
}
}
ลองนำไปใช้FirebaseInstanceIdService
เพื่อรับโทเค็นการรีเฟรช
เข้าถึงโทเค็นการลงทะเบียน:
คุณสามารถเข้าถึงค่าของโทเค็นโดยการขยายFirebaseInstanceIdService ตรวจสอบให้แน่ใจว่าคุณได้เพิ่มบริการลงในรายการของคุณแล้วโทรgetToken
ในบริบทของonTokenRefresh
และบันทึกค่าดังที่แสดง:
@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);
}
รหัสเต็ม:
import android.util.Log;
import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.FirebaseInstanceIdService;
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);
}
// [END refresh_token]
/**
* Persist token to third-party servers.
*
* 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.
}
}
แก้ไข:
คุณไม่ควรเริ่มFirebaseInstanceIdServiceด้วยตัวเอง
ระบบจะเรียกเมื่อระบบพิจารณาว่าต้องรีเฟรชโทเค็น แอปพลิเคชันควรเรียกใช้ getToken () และส่งโทเค็นไปยังเซิร์ฟเวอร์แอปพลิเคชันทั้งหมด
สิ่งนี้จะไม่ถูกเรียกบ่อยนัก แต่จำเป็นสำหรับการหมุนคีย์และเพื่อจัดการกับการเปลี่ยนแปลงรหัสอินสแตนซ์เนื่องจาก:
ระบบจะเค้นเหตุการณ์การรีเฟรชในอุปกรณ์ทั้งหมดเพื่อหลีกเลี่ยงการโหลดแอปพลิเคชันเซิร์ฟเวอร์มากเกินไปด้วยการอัปเดตโทเค็น
ลองวิธีด้านล่าง :
คุณจะเรียกFirebaseInstanceID.getToken ()ที่ใดก็ได้นอกเธรดหลักของคุณ (ไม่ว่าจะเป็นบริการ AsyncTask ฯลฯ ) จัดเก็บโทเค็นที่ส่งคืนไว้ในเครื่องและส่งไปยังเซิร์ฟเวอร์ของคุณ จากนั้นเมื่อใดก็ตามที่
onTokenRefresh()
ถูกเรียกคุณจะเรียก FirebaseInstanceID.getToken ()อีกครั้งรับโทเค็นใหม่และส่งไปยังเซิร์ฟเวอร์ (อาจรวมถึงโทเค็นเก่าด้วยเพื่อให้เซิร์ฟเวอร์ของคุณสามารถลบออกแทนที่ด้วยโทเค็นใหม่) .
onTokenRefresh()
โดนเรียก?
ฉันกำลังรักษาแฟล็กเดียวในการแชร์ pref ซึ่งระบุว่าโทเค็น gcm ถูกส่งไปยังเซิร์ฟเวอร์หรือไม่ ในหน้าจอ Splash ทุกครั้งที่ฉันโทรหาวิธีการหนึ่ง sendDevicetokenToServer วิธีนี้ตรวจสอบว่า ID ผู้ใช้ไม่ว่างเปล่าและสถานะการส่ง gcm จากนั้นส่งโทเค็นไปยังเซิร์ฟเวอร์
public static void sendRegistrationToServer(final Context context) {
if(Common.getBooleanPerf(context,Constants.isTokenSentToServer,false) ||
Common.getStringPref(context,Constants.userId,"").isEmpty()){
return;
}
String token = FirebaseInstanceId.getInstance().getToken();
String userId = Common.getUserId(context);
if(!userId.isEmpty()) {
HashMap<String, Object> reqJson = new HashMap<>();
reqJson.put("deviceToken", token);
ApiInterface apiService =
ApiClient.getClient().create(ApiInterface.class);
Call<JsonElement> call = apiService.updateDeviceToken(reqJson,Common.getUserId(context),Common.getAccessToken(context));
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(Call<JsonElement> call, Response<JsonElement> serverResponse) {
try {
JsonElement jsonElement = serverResponse.body();
JSONObject response = new JSONObject(jsonElement.toString());
if(context == null ){
return;
}
if(response.getString(Constants.statusCode).equalsIgnoreCase(Constants.responseStatusSuccess)) {
Common.saveBooleanPref(context,Constants.isTokenSentToServer,true);
}
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void onFailure(Call<JsonElement> call, Throwable throwable) {
Log.d("", "RetroFit2.0 :getAppVersion: " + "eroorrrrrrrrrrrr");
Log.e("eroooooooorr", throwable.toString());
}
});
}
}
ในคลาส MyFirebaseInstanceIDService
@Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d(TAG, "Refreshed token: " + refreshedToken);
// 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.
Common.saveBooleanPref(this,Constants.isTokenSentToServer,false);
Common.sendRegistrationToServer(this);
FirebaseMessaging.getInstance().subscribeToTopic("bloodRequest");
}
พวกมันมีวิธีง่ายๆ
https://developers.google.com/instance-id/guides/android-implementation#generate_a_token
หมายเหตุ: หากแอปของคุณใช้โทเค็นที่ถูกลบโดย deleteInstanceID แอปของคุณจะต้องสร้างโทเค็นทดแทน
แทนการลบรหัสอินสแตนซ์ให้ลบโทเค็นเท่านั้น:
String authorizedEntity = PROJECT_ID;
String scope = "GCM";
InstanceID.getInstance(context).deleteToken(authorizedEntity,scope);
สิ่งนี้อยู่ใน RxJava2 ในสถานการณ์สมมติเมื่อผู้ใช้รายหนึ่งออกจากระบบจากแอปของคุณและผู้ใช้รายอื่นเข้าสู่ระบบ (แอปเดียวกัน) เพื่อจัดระดับใหม่และโทรเข้าสู่ระบบ (หากอุปกรณ์ของผู้ใช้ไม่มีการเชื่อมต่ออินเทอร์เน็ตก่อนหน้านี้ในเวลาที่เริ่มกิจกรรมและเราจำเป็นต้องส่งโทเค็นใน เข้าสู่ระบบ api)
Single.fromCallable(() -> FirebaseInstanceId.getInstance().getToken())
.flatMap( token -> Retrofit.login(userName,password,token))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(simple -> {
if(simple.isSuccess){
loginedSuccessfully();
}
}, throwable -> Utils.longToast(context, throwable.getLocalizedMessage()));
เข้าสู่ระบบ
@FormUrlEncoded
@POST(Site.LOGIN)
Single<ResponseSimple> login(@Field("username") String username,
@Field("password") String pass,
@Field("token") String token
);
คำตอบนี้ไม่ได้ทำลายรหัสอินสแตนซ์ แต่สามารถรับรหัสปัจจุบันได้ นอกจากนี้ยังจัดเก็บรายการที่รีเฟรชไว้ในการตั้งค่าการแชร์
Strings.xml
<string name="pref_firebase_instance_id_key">pref_firebase_instance_id</string>
<string name="pref_firebase_instance_id_default_key">default</string>
Utility.java (คลาสใดก็ได้ที่คุณต้องการตั้งค่า / รับค่ากำหนด)
public static void setFirebaseInstanceId(Context context, String InstanceId) {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor;
editor = sharedPreferences.edit();
editor.putString(context.getString(R.string.pref_firebase_instance_id_key),InstanceId);
editor.apply();
}
public static String getFirebaseInstanceId(Context context) {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
String key = context.getString(R.string.pref_firebase_instance_id_key);
String default_value = context.getString(R.string.pref_firebase_instance_id_default_key);
return sharedPreferences.getString(key, default_value);
}
MyFirebaseInstanceIdService.java (ขยาย FirebaseInstanceIdService)
@Override
public void onCreate()
{
String CurrentToken = FirebaseInstanceId.getInstance().getToken();
//Log.d(this.getClass().getSimpleName(),"Inside Instance on onCreate");
String savedToken = Utility.getFirebaseInstanceId(getApplicationContext());
String defaultToken = getApplication().getString(R.string.pref_firebase_instance_id_default_key);
if(CurrentToken != null && !savedToken.equalsIgnoreCase(defaultToken))
//currentToken is null when app is first installed and token is not available
//also skip if token is already saved in preferences...
{
Utility.setFirebaseInstanceId(getApplicationContext(),CurrentToken);
}
super.onCreate();
}
@Override
public void onTokenRefresh() {
.... prev code
Utility.setFirebaseInstanceId(getApplicationContext(),refreshedToken);
....
}
ระบบonCreate
ไม่เรียกใช้Android 2.0 ขึ้นไปเมื่อเริ่มต้นโดยอัตโนมัติ (ที่มา ) แต่onStartCommand
ถูกแทนที่และใช้ แต่ใน FirebaseInstanceIdService จริงจะประกาศเป็นขั้นสุดท้ายและไม่สามารถแทนที่ได้ อย่างไรก็ตามเมื่อเราเริ่มให้บริการโดยใช้ startService () หากบริการกำลังทำงานอยู่ระบบจะใช้อินสแตนซ์เดิม (ซึ่งเป็นสิ่งที่ดี) onCreate () (กำหนดไว้ด้านบน) ของเราก็ถูกเรียกด้วยเช่นกัน!.
ใช้สิ่งนี้ในการเริ่มต้น MainActivity หรือจุดใดก็ตามที่คุณคิดว่าคุณต้องการรหัสอินสแตนซ์
MyFirebaseInstanceIdService myFirebaseInstanceIdService = new MyFirebaseInstanceIdService();
Intent intent= new Intent(getApplicationContext(),myFirebaseInstanceIdService.getClass());
//Log.d(this.getClass().getSimpleName(),"Starting MyFirebaseInstanceIdService");
startService(intent); //invoke onCreate
และในที่สุดก็,
Utility.getFirebaseInstanceId(getApplicationContext())
โปรดทราบว่าคุณสามารถปรับปรุงสิ่งนี้ได้มากขึ้นโดยพยายามย้ายรหัส startervice () ไปยังเมธอด getFirebaseInstanceId
[Service]
[IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
class MyFirebaseIIDService: FirebaseInstanceIdService
{
const string TAG = "MyFirebaseIIDService";
NotificationHub hub;
public override void OnTokenRefresh()
{
var refreshedToken = FirebaseInstanceId.Instance.Token;
Log.Debug(TAG, "FCM token: " + refreshedToken);
SendRegistrationToServer(refreshedToken);
}
void SendRegistrationToServer(string token)
{
// Register with Notification Hubs
hub = new NotificationHub(Constants.NotificationHubName,
Constants.ListenConnectionString, this);
Employee employee = JsonConvert.DeserializeObject<Employee>(Settings.CurrentUser);
//if user is not logged in
if (employee != null)
{
var tags = new List<string>() { employee.Email};
var regID = hub.Register(token, tags.ToArray()).RegistrationId;
Log.Debug(TAG, $"Successful registration of ID {regID}");
}
else
{
FirebaseInstanceId.GetInstance(Firebase.FirebaseApp.Instance).DeleteInstanceId();
hub.Unregister();
}
}
}
FirebaseInstanceIdService
คลาสนี้เลิกใช้แล้ว ในการลบล้าง onNewToken ใน FirebaseMessagingService เมื่อดำเนินการแล้วบริการนี้สามารถลบออกได้อย่างปลอดภัย
วิธีใหม่ในการทำเช่นนี้คือการลบล้างonNewToken
เมธอดจากFirebaseMessagingService
public class MyFirebaseMessagingService extends FirebaseMessagingService {
@Override
public void onNewToken(String s) {
super.onNewToken(s);
Log.e("NEW_TOKEN",s);
}
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
}
}
อย่าลืมเพิ่มบริการใน Manifest.xml
<service
android:name=".MyFirebaseMessagingService"
android:stopWithTask="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
ฉันจะอัปเดตอุปกรณ์ของฉันได้อย่างไร Token
อันดับแรกเมื่อฉันเข้าสู่ระบบฉันจะส่งโทเค็นอุปกรณ์แรกภายใต้คอลเล็กชันผู้ใช้และผู้ใช้ที่ล็อกอินปัจจุบัน
หลังจากนั้นฉันเพียงแค่แทนที่onNewToken(token:String)
ในของฉันFirebaseMessagingService()
และอัปเดตค่านั้นหากมีการสร้างโทเค็นใหม่สำหรับผู้ใช้นั้น
class MyFirebaseMessagingService: FirebaseMessagingService() {
override fun onMessageReceived(p0: RemoteMessage) {
super.onMessageReceived(p0)
}
override fun onNewToken(token: String) {
super.onNewToken(token)
val currentUser= FirebaseAuth.getInstance().currentUser?.uid
if(currentUser != null){
FirebaseFirestore.getInstance().collection("user").document(currentUser).update("deviceToken",token)
}
}
}
ทุกครั้งที่เปิดแอปแอปจะตรวจหาโทเค็นใหม่หากผู้ใช้ยังไม่ได้ลงชื่อเข้าใช้จะไม่อัปเดตโทเค็นหากผู้ใช้เข้าสู่ระบบแล้วคุณสามารถตรวจสอบ newToken