Firebase Android:生成独立于设备的用户唯一Token问题求助
解决Firebase Auth注册时同一设备用户Token重复的问题
嘿,我完全懂你的困扰——你现在碰到的核心问题是混淆了两种不同的Token:你之前用的FirebaseInstanceId(现在已经被官方弃用)生成的是设备级的FCM推送令牌,它是绑定设备而非用户的,所以同一设备上不管注册多少用户,这个Token都会一样。而你需要的是和用户绑定的、能用来给特定用户发通知的关联方案,毕竟一个用户可能在多台设备登录。
正确的解决方案思路
要实现给特定用户发定时通知,你需要做的是:
- 获取当前设备的FCM推送令牌(取代旧的InstanceId)
- 将这个令牌与用户的UID绑定,存储到Firestore数据库中(比如给用户文档加一个数组,存储该用户所有设备的令牌)
- 后续发送通知时,根据用户UID从数据库取出对应的所有令牌,调用FCM API发送即可
修改后的代码示例
首先确保你已经引入了Firebase Messaging的依赖,然后把注册逻辑改成这样:
mAuth.createUserWithEmailAndPassword(email, pswd) .addOnSuccessListener(new OnSuccessListener<AuthResult>() { @Override public void onSuccess(AuthResult authResult) { final FirebaseUser mFirebaseUser = authResult.getUser(); if (mFirebaseUser == null) { Toast.makeText(getApplicationContext(), "Une erreur inconnue s'est produite", Toast.LENGTH_SHORT).show(); return; } String uid = mFirebaseUser.getUid(); Log.d(TAG, "UID DU USER: " + uid); // 获取FCM推送令牌(取代废弃的FirebaseInstanceId) FirebaseMessaging.getInstance().getToken() .addOnCompleteListener(new OnCompleteListener<String>() { @Override public void onComplete(@NonNull Task<String> task) { if (!task.isSuccessful()) { Log.w(TAG, "获取FCM令牌失败", task.getException()); Toast.makeText(getApplicationContext(), "获取通知令牌失败", Toast.LENGTH_SHORT).show(); return; } // 获取到的设备级FCM令牌 String fcmToken = task.getResult(); Log.d(TAG, "FCM令牌: " + fcmToken); // 准备用户数据,注意这几个关键点: // 1. 绝对不要存储明文密码!Firebase Auth已经帮你安全管理密码了 // 2. 用数组存储令牌,支持用户多设备登录时都能收到通知 Map<String, Object> userdata = new HashMap<>(); userdata.put("uid", uid); userdata.put("fln", fln); userdata.put("email", email); userdata.put("fcmTokens", Arrays.asList(fcmToken)); // 更新本地SharedPreferences SharedPreferences.Editor editor = prefEnreg.edit(); editor.putString("FULLNAME", fln); editor.putString("tok", fcmToken); editor.apply(); progressBar.setVisibility(View.VISIBLE); register.setVisibility(View.GONE); // 存储到Firestore,用merge避免覆盖用户后续添加的其他设备令牌 db.collection("Users2").document(uid) .set(userdata, SetOptions.merge()) .addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { progressBar.setVisibility(View.GONE); register.setVisibility(View.VISIBLE); if (task.isSuccessful()) { Toast.makeText(getApplicationContext(), "Register User", Toast.LENGTH_SHORT).show(); Intent intent13 = new Intent(MainActivity.this, FriendList.class); startActivity(intent13); // 清空输入框 mail.setText(""); phone.setText(""); fllname.setText(""); passwd.setText(""); } else { Toast.makeText(getApplicationContext(), "存储用户数据失败: " + task.getException().getMessage(), Toast.LENGTH_SHORT).show(); } } }); } }); } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Toast.makeText(getApplicationContext(), "注册失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); } });
额外的重要注意事项
- 不要存储明文密码:你的原代码里把用户密码存在Firestore里,这是严重的安全漏洞,Firebase Auth已经提供了安全的密码管理机制,绝对不要自己存储明文密码。
- FCM令牌可能刷新:设备令牌会在应用卸载重装、系统更新、应用数据清除等场景下刷新,建议在用户每次登录时,都检查当前令牌是否已经在用户的
fcmTokens数组中,如果不在就添加进去,避免通知无法送达。 - Auth ID Token的用途:你之前调用的
getIdToken(true)获取的是Firebase Auth的身份验证令牌,这个Token用于验证用户身份(比如调用你的后端API时),不能用来发送FCM通知,发送通知必须用FCM推送令牌。 - 定时通知的实现:当你需要给特定用户发定时通知时,只需从Firestore中取出该用户的
fcmTokens数组,遍历每个令牌,调用FCM的发送通知API即可。
内容的提问来源于stack exchange,提问作者Rolanddev
相关产品推荐
相关产品推荐

