Thanks for reaching out.
Please note that since I’m working from the demo project you provided, this code is meant as reference, you may need to adapt it to your actual project.
Your GetToken() method is async void and gets called in the page constructor without being awaited. The result is:
- Page constructor runs
GetToken()(but doesn’t wait for it to finish) - User enters email/password and taps login
-
UpdateDevice()runs immediately - FCM token is still empty -> first API call goes out with
push_id: "" - A short moment later,
GetToken()completes and saves the token - Any later API call sends the correct token
Why the JSONs look different:
- First call -> new device record (no
id) - Second call -> updates existing record (has
id)
Here's my suggested approach:
- Ensure the FCM token is ready before login
File: EmailPMAPage.xaml.cs
protected async override void OnAppearing()
{
base.OnAppearing();
// Make sure FCM token is ready
await EnsureFCMTokenIsReadyAsync();
Task.Run(async delegate { await new DeviceInfoService().CheckServerVersionAsync(); });
Task.Run(async delegate { await ViewModel.RefreshScreen(); });
ViewModel.CallBackDisplayEndpoints += HandlerCallBackDisplayEndpoints;
if(BindingContext is LoginPMAViewModel vm)
{
await vm.InitializeAsync();
}
}
private async Task EnsureFCMTokenIsReadyAsync()
{
try
{
var existingToken = Settings.GetProperty(Settings.PushDevicetoken);
if (!string.IsNullOrEmpty(existingToken)) return;
await CrossFirebaseCloudMessaging.Current.CheckIfValidAsync();
var fcmToken = await CrossFirebaseCloudMessaging.Current.GetTokenAsync();
if (!string.IsNullOrEmpty(fcmToken))
{
Settings.SetProperty(Settings.PushDevicetoken, fcmToken);
Console.WriteLine($"FCM token retrieved: {fcmToken.Substring(0, 10)}...");
}
}
catch (Exception e)
{
Console.WriteLine($"FCM token exception: {e.Message}");
Debug.WriteLine(e);
}
}
- Update the
UpdateDevice()method
File: LoginPMAViewModel.cs
public static async Task UpdateDeviceAsync()
{
try
{
var pushDevicetoken = Settings.GetProperty(Settings.PushDevicetoken) ?? string.Empty;
if (string.IsNullOrEmpty(pushDevicetoken)) return;
var result = await UpdateDeviceTokenAsync(pushDevicetoken);
Console.WriteLine($"Device update result: {result}");
}
catch (Exception ex)
{
Console.WriteLine($"UpdateDevice error: {ex.Message}");
}
}
And make sure calls in Login() use await UpdateDeviceAsync() instead of UpdateDevice():
// When policies invalid
if (!isPolicyDocumentsValid) await UpdateDeviceAsync();
// Successful login
else
{
await UpdateTimeZone(result.User);
await UpdateDeviceAsync();
Settings.SetProperty(Settings.SleepTime, DateTime.UtcNow.Ticks.ToString());
}
// When result is null
else
{
await UpdateDeviceAsync();
var master = MainService.HomePage.Value as DashboardMasterPage;
}
Hope this helps! If my answer was helpful - kindly follow the instructions here so others with the same problem can benefit as well.