下面是我的MainActivity代码:
using System;
using Android.App;
using Android.Content.PM;
using Android.Runtime;
using Android.OS;
using static Firebase.Messaging.RemoteMessage;
using Android.Gms.Common;
using Android.Nfc;
using Android.Util;
using Android.Content;
using Firebase.Messaging;
using NoticationDemo.Droid;
using System.Collections.Generic;
using Xamarin.Forms;
using AndroidX.Core.App;
namespace NoticationDemo.Droid
{
[Activity(
Label = "NoticationDemo",
Icon = "@mipmap/icon",
Theme = "@style/MainTheme",
MainLauncher = true,
LaunchMode = LaunchMode.SingleTop,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize )]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
static readonly string TAG = "MainActivity";
public bool isNotification = false;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
isNotification = false;
IsPlayServicesAvailable();
//background mode or killed mode
CreateNotificationFromIntent(Intent);
if (!isNotification)
{
LoadApplication(new App("No Notification"));
}
}
public bool IsPlayServicesAvailable()
{
int resultcode = GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(this);
if (resultcode != ConnectionResult.Success)
{
if (GoogleApiAvailability.Instance.IsUserResolvableError(resultcode))
{
Console.WriteLine($"Error:{GoogleApiAvailability.Instance.GetErrorString(resultcode)}");
}
else
{
Console.WriteLine("Error: play services not supported!");
}
return false;
}
else
{
Console.WriteLine("Play services available");
return true;
}
}
protected override void OnNewIntent(Intent intent)
{
//foreground mode
CreateNotificationFromIntent(intent);
}
void CreateNotificationFromIntent(Intent intent)
{
if (intent.Extras != null)
{
foreach (var key in intent.Extras.KeySet())
{
var notificationName = intent.Extras.GetString("NotificationName");
var NotificatioKey = intent.Extras.GetString("NotificationKey");
Console.WriteLine("NotificationName:>>" + notificationName);
Console.WriteLine("NotificatioKey:>>" + NotificatioKey);
if (NotificatioKey == "Superman")
{
if (notificationName?.Length > 0)
{
isNotification = true;
LoadApplication(new App(notificationName));
}
}
}
}
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}
[Service(Enabled = true, Exported = true)]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
public class FirebaseNotificationService : FirebaseMessagingService
{
public override void OnNewToken(string token)
{
base.OnNewToken(token);
Console.WriteLine($"Token received:>> {token}");
SendRegistrationTokenToMainPRoject(token);
}
public override void OnMessageReceived(RemoteMessage message)
{
base.OnMessageReceived(message);
try
{
string body = System.Net.WebUtility.UrlDecode(message.GetNotification().Body.ToString()).Replace("'", "'");
string header = System.Net.WebUtility.UrlDecode(message.GetNotification().Title.ToString()).Replace("'", "'");
SendNotificatios(body, header, message.Data);
}
catch (Exception ex)
{
Console.WriteLine("Error:>>" + ex);
}
}
public void SendNotificatios(string body, string Header, IDictionary<string, string> data)
{
var intent = new Intent(this, typeof(MainActivity));
intent.AddFlags(ActivityFlags.ClearTop);
foreach (var key in data.Keys)
{
intent.PutExtra(key, data[key]);
}
var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.Mutable);
if (Build.VERSION.SdkInt < BuildVersionCodes.O)
{
var notificationBuilder = new NotificationCompat.Builder(this)
.SetContentTitle(Header)
.SetContentText(body)
.SetSmallIcon(Resource.Mipmap.icon)
.SetAutoCancel(true)
.SetContentIntent(pendingIntent);
var notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
notificationManager.Notify(new Random().Next(), notificationBuilder.Build());
}
else
{
var notificationBuilder = new NotificationCompat.Builder(this, Utils.CHANNEL_ID)
.SetContentTitle(Header)
.SetContentText(body)
.SetSmallIcon(Resource.Mipmap.icon)
.SetAutoCancel(true)
.SetContentIntent(pendingIntent);
var notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
NotificationChannel channel = new NotificationChannel(Utils.CHANNEL_ID, "FCM Notifications", NotificationImportance.Default);
notificationManager.CreateNotificationChannel(channel);
notificationManager.Notify(new Random().Next(), notificationBuilder.Build());
}
}
void SendRegistrationTokenToMainPRoject(string token)
{
try
{
//Send Refresh to you FCM Server Here
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
AndroidManifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.noticationdemo">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33" />
<application android:label="NoticationDemo.Android" android:theme="@style/MainTheme">
<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver" android:exported="false" />
<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="${applicationId}" />
</intent-filter>
</receiver>
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>
Utils.cs
public class Utils
{
public static readonly string CHANNEL_ID = "CB_FCM_CHANNEL";
public static readonly int NOTIFICATION_ID = 100;
}
通知负载:
{
"to" : "device token",
"notification" : {
"body" : "Hi1",
"title": "Notification1"
},
"data" : {
"NotificationName": "notification1",
"NotificationKey" : "test"
}
}
我正在从通知中读取NotificationName,并将其作为参数传递给App.xaml.cs,并将其显示在主页的UI 上。
public App(string notificationName)
{
InitializeComponent();
MainPage = new MainPage(notificationName);
}
public partial class MainPage : ContentPage
{
public MainPage(string notificationName)
{
InitializeComponent();
notificationname_label.Text = notificationName;
}
}
我的问题是,对于在前台模式下接收的所有通知,始终显示前台模式下的第一个通知。
例如:我在前台模式下收到了Notification1。如果我点击它,通知 1 数据将被读取并显示在 UI 上。同样,如果我收到新通知“通知 2”,如果我点击该通知,则通知 1 数据将再次显示在 UI 上。始终在前台模式下读取第一个通知数据。在后台模式下没有这样的问题。
这是我的 demo 和 postman Collection 来重现此问题。
如何重现此问题:
your device token
部分。参考博客:
更新
我在
MessagingCenter.Send
内添加了CreateNotificationFromIntent
,如下所示:
void CreateNotificationFromIntent(Intent intent)
{
if (intent.Extras != null)
{
foreach (var key in intent.Extras.KeySet())
{
var notificationName = intent.Extras.GetString("NotificationName");
var NotificationKey = intent.Extras.GetString("NotificationKey");
Console.WriteLine("NotificationName:>>" + notificationName);
Console.WriteLine("NotificationKey:>>" + NotificationKey);
if (NotificationKey == "test")
{
if (notificationName?.Length > 0)
{
isNotification = true;
MessagingCenter.Send<Xamarin.Forms.Application, string>(Xamarin.Forms.Application.Current, "NotificationName", notificationName);
LoadApplication(new App(notificationName));
}
}
}
}
}
用
MainPage
部分更新了MessagingCenter.Subscribe
内容。
public partial class MainPage : ContentPage
{
public MainPage(string notificationName)
{
InitializeComponent();
//notificationname_label.Text = notificationName;
MessagingCenter.Subscribe<Xamarin.Forms.Application, string>(this, "NotificationName", async (sender, arg) =>
{
notificationname_label.Text = arg;
});
}
}
但是当点击通知时,通知名称不会显示在用户界面上。当我通过添加断点进行调试时,
MessagingCenter.Send
和MessagingCenter.Subscribe
无限次调用,但通知名称在主页UI上不可见。
我的问题是,对于在前台模式下接收的所有通知,始终显示前台模式下的第一个通知。
这是因为您通过
notificationname_label.Text = notificationName;
在 MainPage 的构造函数中设置了 UI 标签。当应用程序在前台运行时,只有在 MainPage 第一次初始化时才会调用 App.cs 和 MainPage 的构造函数。
所以你可以参考关于使用INotificationManager辅助类接收通知的官方文档。
此外,您还可以使用 MessagingCenter 来完成此操作。这是一个关于使用MessagingCenter通知UI通知已更新的案例。
更新:
如果您使用
MessagingCenter
,您可以在收到新通知名称时发送它。并在 MainPage 的构造函数中订阅它:
发送新的通知名称:
MessagingCenter.Send<Xamarin.Forms.Application, string>(Xamarin.Forms.Application.Current, "NotificationName","the new notification name you want to send")
接收新通知名称:
public MainPage()
{
InitializeComponent();
// Subscribe to a message (which the ViewModel has also subscribed to) to display an alert
MessagingCenter.Subscribe<Xamarin.Forms.Application, string>(Xamarin.Forms.Application.Current, "NotificationName", async (sender, arg) =>
{
notificationname_label.Text = arg;
});
}
更多信息,您可以参考使用MessagingCenter通知UI通知已更新以及MessagingCenter官方示例。