Plugin.FirebasePushNotifications
Plugin.FirebasePushNotifications copied to clipboard
How I made it working on Android with custom icon and background notification. Source code example
I hope it will be helpful to someone.
I added custom notification param OPEN_URL
Notification Service:
public class PushNotificationService : IPushNotificationService
{
private readonly IFirebasePushNotification _firebasePushNotification;
private readonly INotificationPermissions _notificationPermissions;
private readonly IPushNotificationsApiClient _pushNotificationsApiClient;
public PushNotificationService(
IFirebasePushNotification firebasePushNotification,
INotificationPermissions notificationPermissions,
IPushNotificationsApiClient pushNotificationsApiClient)
{
_firebasePushNotification = firebasePushNotification;
_notificationPermissions = notificationPermissions;
_pushNotificationsApiClient = pushNotificationsApiClient;
}
public async Task StartAsync()
{
AuthorizationStatus authorizationStatus = await _notificationPermissions.GetAuthorizationStatusAsync();
if (authorizationStatus != AuthorizationStatus.Granted)
{
await _notificationPermissions.RequestPermissionAsync();
}
if (authorizationStatus == AuthorizationStatus.Granted)
{
await _firebasePushNotification.RegisterForPushNotificationsAsync();
_firebasePushNotification.TokenRefreshed += FirebasePushNotificationOnTokenRefreshed;
await _pushNotificationsApiClient.MobileSubscribeAsync(_firebasePushNotification.Token);
}
}
private void FirebasePushNotificationOnTokenRefreshed(object sender, FirebasePushNotificationTokenEventArgs e)
{
_= Task.Run(() => _pushNotificationsApiClient.MobileSubscribeAsync(_firebasePushNotification.Token));
}
}
FirebaseService inside Platforms/Android folder
[Service(DirectBootAware = true, Exported = true, Enabled = true)]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
[IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
public class FirebaseService : FirebaseMessagingService
{
public override ComponentName StartService(Intent service)
{
Log.Info("GCM", $"MyFirebaseService started from intent {service}");
return base.StartService(service);
}
public override void OnMessageReceived(RemoteMessage message)
{
base.OnMessageReceived(message);
var notification = message.GetNotification();
Log.Info("FirebaseService: ", "OnMessageReceived");
SendNotification(notification.Body, notification.Title, message.Data);
}
private void SendNotification(string messageBody, string title, IDictionary<string, string> data)
{
var notificationId = Int32.Parse(DateTime.Now.ToString("MMddHHmmsss"));
var intent = new Intent(this, typeof(MainActivity));
intent.AddFlags(ActivityFlags.ClearTop);
intent.AddFlags(ActivityFlags.SingleTop);
foreach (var key in data.Keys)
{
string value = data[key];
intent.PutExtra(key, value);
}
PendingIntent pendingIntent = PendingIntent.GetActivity(this, notificationId, intent, PendingIntentFlags.OneShot | PendingIntentFlags.Immutable);
NotificationManager notificationManager = (NotificationManager)GetSystemService(Context.NotificationService);
Int64 timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds();
var notificationBuilder = new NotificationCompat.Builder(this, MainActivity.NotificationChannelId.ToString())
.SetContentTitle(title)
.SetSmallIcon(AtlasMobile.Resource.Drawable.my_logo_white)
.SetContentText(messageBody)
.SetWhen(timestamp)
.SetContentIntent(pendingIntent)
.SetAutoCancel(true)
.SetShowWhen(true)
.SetPriority(NotificationCompat.PriorityHigh);
notificationManager.Notify(notificationId, notificationBuilder.Build());
}
}
MainActivity:
[IntentFilter(new[] { "Open_URI" }, Label = "Open_URI", Categories = new []{"android.intent.category.DEFAULT"})]
[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
public class MainActivity : MauiAppCompatActivity
{
public static int NotificationChannelId = 1152;
public static string NotificationChannelName = "Push Notifications";
public static string NotificationChannelDescription = "Receive notifications";
public override void OnConfigurationChanged(Configuration newConfig)
{
base.OnConfigurationChanged(newConfig);
GrialKit.NotifyConfigurationChanged(newConfig);
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
if (ContextCompat.CheckSelfPermission(this, Android.Manifest.Permission.PostNotifications) == Permission.Granted && IsPlayServicesAvailable())
{
CreateNotificationChannel();
}
}
public Boolean IsPlayServicesAvailable()
{
Int32 resultCode = GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.Success)
{
if (GoogleApiAvailability.Instance.IsUserResolvableError(resultCode))
{
Log.Error("MAIN", GoogleApiAvailability.Instance.GetErrorString(resultCode));
}
else
{
Log.Error("MAIN", "Device not supported.");
Finish();
}
return false;
}
return true;
}
protected override void OnNewIntent(Intent intent)
{
base.OnNewIntent(intent);
if (intent != null && intent.Extras != null)
{
foreach (var key in intent.Extras.KeySet())
{
if (key == "Open_URI")
{
string idValue = intent.Extras.GetString(key);
if (Preferences.ContainsKey("Open_URI"))
Preferences.Remove("Open_URI");
Preferences.Set("Open_URI", idValue);
}
}
}
}
public void CreateNotificationChannel()
{
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
#pragma warning disable CA1416
var notificationChannel = new NotificationChannel(NotificationChannelId.ToString(), NotificationChannelName, NotificationImportance.High)
{
Description = NotificationChannelDescription
};
notificationManager.CreateNotificationChannel(notificationChannel);
#pragma warning restore CA1416
}
}
}
AndroidManifest.xml application tag:
<application
android:allowBackup="true"
android:icon="@mipmap/appicon"
android:roundIcon="@mipmap/appicon_round"
android:supportsRtl="true"
android:usesCleartextTraffic="true">
<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>
<meta-data android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/my_logo_white"/>
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="@string/default_notification_channel_id"/>
</application>
Notification message from Server:
Random rnd = new Random();
int month = rnd.Next(1, 2000);
return new Message
{
Token = token,
Notification = new Notification
{
Body = body,
Title = title,
},
Android = new AndroidConfig
{
Notification = new AndroidNotification
{
ClickAction = "Open_URI",
}
},
Apns = new ApnsConfig
{
Aps = new Aps
{
Category = "General"
}
},
Data = new Dictionary<string, string>
{
{"Open_URI", month.ToString()}
}
};
Cool, thanks for sharing.
Can I ask why you‘re sending a new local notification (notificationManager.Notify) when you receive a push notification? Cant you send the notification icon as property of the notification message?
One point to remark: The plugin has built-in logic to create/update/delete notification channels at app startup. The sample app makes use of this feature.