我正在使用FCM在我的应用中提供通知。一切都运作良好,但现在我意识到,当我使用Android Studio(而非GooglePlay)安装我的应用程序时,首次运行时令牌为空。当我关闭我的应用程序并重新启动它时,令牌不再为空。造成这个问题的原因是什么,我该如何避免呢?
InstanceIDService:
public class InstanceIDService extends FirebaseInstanceIdService {
@Override
public void onTokenRefresh() {
String token = FirebaseInstanceId.getInstance().getToken();
registerToken(token);
}
private void registerToken(String token) {
OkHttpClient client = new OkHttpClient();
RequestBody body = new FormBody.Builder()
.add("Token",token)
.build();
Request request = new Request.Builder()
.url("url_to_registration_script")
.post(body)
.build();
try {
client.newCall(request).execute();
} catch (IOException e) {
e.printStackTrace();
}
}
}
在MainActivity中:
FirebaseMessaging.getInstance().subscribeToTopic("topic");
String token = FirebaseInstanceId.getInstance().getToken();
Log.d("TOKEN", token);
首次安装并启动应用时,上次日志返回null
注册脚本:
<?php
if (isset($_POST["Token"])) {
$_uv_Token=$_POST["Token"];
$conn = mysqli_connect("localhost","user","pass","db") or die("Error connecting");
$q="INSERT INTO users (Token) VALUES ( '$_uv_Token') "
." ON DUPLICATE KEY UPDATE Token = '$_uv_Token';";
mysqli_query($conn,$q) or die(mysqli_error($conn));
mysqli_close($conn);
}
?>
答案 0 :(得分:29)
在第一个应用启动时异步提取令牌。在访问令牌之前,您必须等待onTokenRefresh()
中的FirebaseInstanceIdService
被调用。
答案 1 :(得分:7)
从模拟器中卸载应用程序并再次运行,以便再次调用onTokenRefreshed方法。
要检查您是否已经注册,您只想知道FCM TOken
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
在MyFirebaseMessagingService类的任何位置(在oncreate方法中)添加以上行,只需添加Toast或记录refreshedToken。
答案 2 :(得分:5)
只需替换:
String token = instanceID.getToken();
使用:
String token = instanceID.getToken($SENDER_ID, "FCM");
它会起作用。
答案 3 :(得分:3)
我遇到了同样的问题。我查看了很多SO帖子和其他论坛,我发现了一个适合我的解决方案。 FCM文档说使用此方法获取令牌。
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
我发现了一个在线发帖(我道歉,我不记得哪一个。我刚才发现它)使用了这种方法:
String refreshedToken = FirebaseInstanceId.getInstance().getToken() (String authorizedEntity, String scope);
FCM文档将第一种方法描述为:
返回默认Firebase项目的主令牌。
第二个被描述为:
返回一个令牌,该令牌授权实体代表由Instance ID标识的应用程序执行操作。 这类似于OAuth2令牌,但它适用于应用程序实例而不是用户。 例如,要获取可用于通过FirebaseMessaging向应用程序发送消息的令牌,请设置为发件人ID,并设置为“FCM”。
我一直在研究为什么第一个方法调用需要更长的时间来返回一个令牌,但我还没有找到答案。希望这会有所帮助。
答案 4 :(得分:2)
即使我有同样的问题。我给了Log语句在我的启动器活动的onCreate中打印令牌。卸载应用程序后刷新令牌需要一些时间。这就是为什么你得到null。你必须等待一点才能刷新令牌。
答案 5 :(得分:2)
有时可能会出现网络问题,即使互联网工作正常......
检查你的android项目中Manifest文件中定义的app.use(enforce.HTTPS(true));
类。
答案 6 :(得分:1)
我刚刚陷入同样的问题,这就是我修复它的方式。在活动的onCreate()
方法中的某处调用块。我想将令牌发送到我的Parse服务器,因此您必须根据需要进行更改。
This is我跟踪的样本。
private void subscribeUserToParse() {
String deviceToken = FirebaseInstanceId.getInstance().getToken();
if (TextUtils.isEmpty(deviceToken)) {
Intent intent = new Intent(this, MyFirebaseInstanceIDService.class);
startService(intent);
return;
}
User user = UserUtil.retrieveUserFromDB(mRealm);
String objectId = user.getParseObjectId();
if (!TextUtils.isEmpty(objectId)) {
ParseUtils.subscribeWithUsersObjectId(objectId, deviceToken);
}
}
答案 7 :(得分:1)
编写正确代码后我遇到的最大问题是: - 不是build-gradle中最新版本的google play服务, 因此,请始终使用firebase中显示的google-play-services版本来设置对话框
答案 8 :(得分:1)
我在Android 4.2设备中遇到了同样的问题。 因此,要解决问题,首先,检查清单中的服务是否具有以下优先级:
<service
android:name=".other.MyFirebaseInstanceIDService"
android:exported="false">
<intent-filter android:priority="1000">
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
其次,使用广播意图通知您更改了令牌的MainActivity:
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
@Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
final Intent intent = new Intent("tokenReceiver");
final LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(this);
intent.putExtra("token",refreshedToken);
broadcastManager.sendBroadcast(intent);
}
然后在MainActivity中,在onCreate中添加:
@Override
protected void onCreate(Bundle savedInstanceState) {
...
LocalBroadcastManager.getInstance(this).registerReceiver(tokenReceiver,
new IntentFilter("tokenReceiver"));
}
并在MainActivity中添加一个新的BroadcastReceiver:
BroadcastReceiver tokenReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String token = intent.getStringExtra("token");
if(token != null)
{
Log.e("firebase", String.valueOf(token));
// send token to your server
}
}
};
答案 9 :(得分:0)
由于{strong>不推荐使用getToken()
方法,因此必须用侦听器替换。
只需替换 String token = FirebaseInstanceId.getInstance().getToken();
:
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();
// 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();
}
});
您可以在此处找到Google的官方文档:https://firebase.google.com/docs/cloud-messaging/android/client
一个不错的中型帖子也会对您有所帮助:https://medium.com/@cdmunoz/fcm-getinstance-gettoken-in-android-is-now-deprecated-how-to-fix-it-3922a94f4fa4