Closed jx37 closed 3 years ago
Going to have a look...
Hi,
I have the same problem on my side. The notifications does'nt works while the application is closed. Did you found any solution about that ? Thanks
Hi, I solved the problem . To work properly Android applications must include a special class called "BroadcastReceiver" and an "IntentService" class. Notifications are working when the app is totally closed only if this IntentService class is specified on the BroadcastReceiver class. Below the correct implementation:
[BroadcastReceiver(Permission = Constants.PERMISSION_GCM_INTENTS)]
[IntentFilter(new[] { PushNotificationService.PushNotificationReceived}, Priority = (int)IntentFilterPriority.LowPriority)]
[IntentFilter(new[] { Constants.INTENT_FROM_GCM_MESSAGE }, Categories = new[] { "packagename" })]
[IntentFilter(new[] { Constants.INTENT_FROM_GCM_REGISTRATION_CALLBACK }, Categories = new[] { "packagename" })]
[IntentFilter(new[] { Constants.INTENT_FROM_GCM_LIBRARY_RETRY }, Categories = new[] { "packagename" })]
public class PushGcmBroadcastReceiver : GcmBroadcastReceiverBase
//The SENDER_ID is your Google API Console App Project Number
public static string[] SenderIds = { "SENDER_ID" };
public static string[] Tags = {"android"};
const string ReceiveAction = "com.google.android.c2dm.intent.RECEIVE";
const string RegistrationAction = "com.google.android.c2dm.intent.REGISTRATION";
public static string RegistrationId { get; set; }
#endregion
#region Logic
public override void OnReceive(Context context, Intent intent)
{
var keys = intent.Extras;
if (intent.Action == ReceiveAction)
{
//Get values of toast parameters
var title = keys.ContainsKey("title") ? keys.GetString("title") : string.Empty;
var message = keys.ContainsKey("message") ? keys.GetString("message") : string.Empty;
var param = keys.ContainsKey("id") ? keys.GetString("id") : string.Empty;
CreateNotification(context, title, message, param);
}
else if (intent.Action == RegistrationAction)
{
var registrationId = keys.ContainsKey("registration_id") ? keys.GetString("registration_id") : string.Empty;
if(!string.IsNullOrEmpty(registrationId))
RegisterHub(registrationId);
else
UnRegisterHub();
}
}
private void CreateNotification(Context context, string title, string message, string param)
{
var notificationManager = (NotificationManager)context.GetSystemService(Context.NotificationService);
//Create an intent to show ui
var uiIntent = new Intent(context, typeof(MainView));
uiIntent.PutExtra("ID", param);
const int pendingIntentId = 0;
var pendingIntent = PendingIntent.GetActivity(context, pendingIntentId, uiIntent, PendingIntentFlags.OneShot);
// Instantiate the notification builder and enable sound:
var builder = new Notification.Builder(context)
.SetAutoCancel(true)
.SetContentIntent(pendingIntent)
.SetContentTitle(title)
.SetContentText(message)
.SetDefaults(NotificationDefaults.Sound)
.SetSmallIcon(Resource.Drawable.ic_launcher);
var notification = builder.Build();
// Publish the notification:
const int notificationId = 0;
if (notificationManager != null)
notificationManager.Notify(notificationId, notification);
}
#endregion
#region Register/Unregister Hub
private static void RegisterHub(string registrationId)
{
//Receive registration Id for sending GCM Push Notifications to
try
{
var notificationHub = PushNotificationService.Hub;
if (notificationHub == null)
return;
RegistrationId = registrationId;
//notificationHub.UnregisterAllAsync(registrationId);
notificationHub.UnregisterNativeAsync();
notificationHub.RegisterNativeAsync(registrationId, Tags);
}
catch (Exception ex)
{
Debug.WriteLine("An exception has occurred in RegisterHub: {0} - StackTrace: {1}", ex.Message,
ex.StackTrace);
}
}
private static void UnRegisterHub()
{
try
{
var notificationHub = PushNotificationService.Hub;
if (notificationHub != null)
//notificationHub.UnregisterAllAsync(_registrationId);
notificationHub.UnregisterNativeAsync();
}
catch (Exception ex)
{
Debug.WriteLine("Exception occurred in UnRegisterHub: {0} - StackTrace: {1}", ex.Message, ex.StackTrace);
}
}
#endregion
}
This is necessary because the IntentService class has the task to stay awake the app so that it listens for a possible push notification. In the IntentService class you must provide the method for NotificationHub registration and the method which makes the app waking up (void OnHandleIntent(Intent intent)) as follow:
[Service] public class PushNotificationService : GcmServiceBase {
public static NotificationHub Hub;
private static Context _context;
#endregion
// Use this constructor instead after publishing to the cloud
public static MobileServiceClient MobileService = new MobileServiceClient(Configuration.ApiBaseUri, Configuration.MobileServiceAppKey);
#endregion
#region ctor
public PushNotificationService()
: base(PushGcmBroadcastReceiver.SenderIds)
{
}
#endregion
#region GcmServiceBase implementation
public static void Initialize(Context context)
{
_context = context;
Hub = new NotificationHub("NotificationHubName", "AzureConnectionString");
}
public static void Register(Context context)
{
try
{
GcmClient.CheckDevice(context);
GcmClient.CheckManifest(context);
var registrationId = GcmClient.GetRegistrationId(context);
if (string.IsNullOrEmpty(registrationId))
{
// Makes this easier to call from our Activity
GcmClient.Register(context, PushGcmBroadcastReceiver.SenderIds);
}
registrationId = GcmClient.GetRegistrationId(context);
if (!string.IsNullOrEmpty(registrationId))
RegisterHub(registrationId);
}
catch (Exception ex)
{
Debug.WriteLine("Exception occurred in Register: {0} - StackTrace: {1}", ex.Message, ex.StackTrace);
}
}
protected override void OnRegistered(Context context, string registrationId)
{
try
{
RegisterHub(registrationId);
}
catch (Exception ex)
{
Console.WriteLine("Exception occurred in OnRegistered: {0} - StackTrace: {1}", ex.Message, ex.StackTrace);
}
}
private static void RegisterHub(string registrationId)
{
//Receive registration Id for sending GCM Push Notifications to
if (Hub == null)
return;
Hub.UnregisterAllAsync(registrationId);
Hub.RegisterNativeAsync(registrationId);
}
protected override void OnUnRegistered(Context context, string registrationId)
{
try
{
if (Hub != null)
Hub.UnregisterAllAsync(registrationId);
}
catch (Exception ex)
{
Console.WriteLine("Exception occurred in OnUnRegistered: {0} - StackTrace: {1}", ex.Message, ex.StackTrace);
}
}
protected override void OnMessage(Context context, Intent intent)
{
Debug.WriteLine("--------- Received Notification ---------");
//Push Notification arrived - print out the keys/values
if (intent == null || intent.Extras == null)
return;
var keys = intent.Extras;
//Get values of toast parameters
var title = keys.ContainsKey("title") ? keys.GetString("title") : string.Empty;
var message = keys.ContainsKey("message") ? keys.GetString("message") : string.Empty;
var param = keys.ContainsKey("id") ? keys.GetString("id") : string.Empty;
//Show push notification
CreateNotification(title, message, param);
}
protected override bool OnRecoverableError(Context context, string errorId)
{
//Some recoverable error happened
return base.OnRecoverableError(context, errorId);
}
protected override void OnError(Context context, string errorId)
{
//Some more serious error happened
}
#endregion
public void CreateNotification(string title, string desc, string param)
{
//Create notification
var notificationManager = GetSystemService(NotificationService) as NotificationManager;
//Create an intent to show ui
var uiIntent = new Intent(this, typeof(MainView));
uiIntent.PutExtra("newsID", param);
const int pendingIntentId = 0;
var pendingIntent = PendingIntent.GetActivity(this, pendingIntentId, uiIntent, PendingIntentFlags.OneShot);
// Instantiate the notification builder and enable sound:
var builder = new Notification.Builder(this)
.SetAutoCancel(true)
.SetContentIntent(pendingIntent)
.SetContentTitle(title)
.SetContentText(desc)
.SetDefaults(NotificationDefaults.Sound)
.SetSmallIcon(Resource.Drawable.ic_launcher);
var notification = builder.Build();
// Publish the notification:
const int notificationId = 0;
if (notificationManager != null)
notificationManager.Notify(notificationId, notification);
}
//This method is responsible to wake up application when is totally closed and to handle the received notification calling the broadcast receiver protected override void OnHandleIntent(Intent intent) { //base.OnHandleIntent(intent);
var pushIntent = new Intent(PushNotificationReceived);
SendOrderedBroadcast(pushIntent, null);
}
Thanks a lot, ill give it a try and ill get back to you if i have some issues.
jx37, i tried to make this setup works but i still have some problems. I'm not sure to see what is "PushNotificationReceived" used in OnHandleIntent and IntentFilter. Where and how is it defined ? Thanks a lot for your help
Hi dbeaupre , "PushNotificationReceived" is the Intent action name which is called when a push notification is received. If you take a look the same name is specified in action declaration before BroadcastReceiver class.
[IntentFilter(new[] { PushNotificationService.PushNotificationReceived}, Priority = (int)IntentFilterPriority.LowPriority)]
Anyway "PushNotificationReceived" is a costant string and you can define at the begin of the PushNotificationService class, like this:
public const string PushNotificationReceived = "PushNotificationReceived";
Hope this help.
Hi, tanks a lot for your help. When the app is running or in background I can receive notifications but when the app is closed i dont. Do i have to start the service somewhere ? Now i'm calling the Register and initialize sub on OnCreate of my main activity, is this ok ? Thanks
Hi jx37, I'm involved in the same problem. I've tried to start from your initial code and apply your solution but I get a lot of errors. For instance, I cannot inherit from GcmBroadcastReceiverBase because this class just doesn't exist (instead, exists the generic one GcmBroadcastReceiverBase
Anyway, could you please share all your working code (or, better, un updated solution to download), just for reference? Thanks
I've solved the problem. You can find my solution here: https://github.com/moonClimber/AzureHubNotification_XamarinAndroid
Hi, I’m developing an app that receive push notification from Azure Mobile Service in Xamarin-Android. When I start the application I register my device (Nexus 4) to my Azure Notification Hub. Push Notification still received only when app is running or is in background, but not when the app is closed or I delete it from task manager (N.B I don’t force to quit it from settings). Now I have downloaded the example from Github at [1] and I customize that with my Google Project Sender ID, my Notification Hub ID and my Azure Mobile Service Connection String, but neither this working when the app is totally closed. Here [2] the zip containing the test solution.
Hope you can help me.
[1] https://github.com/SaschaDittmann/Xamarin.NotificationHub/tree/master/samples [2] http://1drv.ms/1xPlgL5
Best Regards.