Open brminnick opened 8 years ago
Still it won't give me push notifications in the background
Nevermind, I missed
<receiver android:name=".AlarmReceiver">
Hi brminnick,
weird - I am not seeing any dependency from the plug-in itself; my guess is, in your implementation of CrossPushNotificationListener, you have created the Dependency on Forms.
IMHO: The tutorial (Adding Push Notification Post to your Xamarin Forms Application) is correct.
In my code, I don't do anything but to notify the user; my registration with azure happens when the user logs in to the system.. by that time, Forms is already initialized.
@alexbleks I ran into the same issue but don't really understand how you fixed it...
Why should adding <receiver android:name=".AlarmReceiver">
help?
Haven't added it yet. My [Application]
-Class is exactly like in the tutorial described... what did I miss?
UPDATE: fixed the crash (I had some Forms-specific code in my IPushNotificationListener.OnMessage). The Application
-Class is terminated if I kill the app. Whats the best way to restart it in the background? Your solution?
public xxxxx (IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
}
public static Context AppContext;
public override void OnCreate ()
{
base.OnCreate ();
AppContext = this.ApplicationContext;
//TODO: Initialize CrossPushNotification Plugin
//TODO: Replace string parameter with your Android SENDER ID
//TODO: Specify the listener class implementing IPushNotificationListener interface in the Initialize generic
CrossPushNotification.Initialize<CrossPushNotificationListener>("xxxxx");
//This service will keep your app receiving push even when closed.
StartPushService();
}
public static void StartPushService()
{
AppContext.StartService(new Intent(AppContext, typeof(PushNotificationService)));
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Kitkat)
{
PendingIntent pintent = PendingIntent.GetService(AppContext, 0, new Intent(AppContext, typeof(PushNotificationService)), 0);
AlarmManager alarm = (AlarmManager)AppContext.GetSystemService(Context.AlarmService);
alarm.Cancel(pintent);
}
}
public static void StopPushService()
{
AppContext.StopService(new Intent(AppContext, typeof(PushNotificationService)));
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Kitkat)
{
PendingIntent pintent = PendingIntent.GetService(AppContext, 0, new Intent(AppContext, typeof(PushNotificationService)), 0);
AlarmManager alarm = (AlarmManager)AppContext.GetSystemService(Context.AlarmService);
alarm.Cancel(pintent);
}
}
@MKahmen, Here's where your code is breaking, which is the same bug that I hit:
[Application]
file, and then it load the MainActivity.cs
file.
[Application]
before MainActivity
[Application]
file, the code is initializing the CrossPushNotification
classCrossPushNotification
, it calls the Xamarin.Forms DependencyService: DependencyService.Get<IAzureNotificationHubService>();
We cannot call the Xamarin.Forms Dependency Service in the [Application]
file, because Xamarin.Forms hasn't yet been initialized; we can only use the Xamarin.Forms Dependency Service after we've initialized Xamarin.Forms, global::Xamarin.Forms.Forms.Init(this, bundle);
.
Because Xamarin.Forms is initialized in the MainActivity
, we cannot use the Dependency Service in the [Application]
file.
using System.Threading.Tasks;
using PushNotification.Plugin;
using PushNotification.Plugin.Abstractions;
using Xamarin.Forms;
using Newtonsoft.Json.Linq;
namespace MondayPundayApp
{
public class CrossPushNotificationListener : IPushNotificationListener
{
IAzureNotificationHubService _azureNotificationHubService;
public CrossPushNotificationListener()
{
// This is where the code breaks when you send a Push Notification to an Android App that is not currently running.
//You cannot call the Xamarin.Forms Dependency Service before Xamarin.Forms has been initialized in the MainActivity
_azureNotificationHubService = DependencyService.Get<IAzureNotificationHubService>();
}
public async void OnRegistered(string Token, DeviceType deviceType)
{
await _azureNotificationHubService.RegisterNativeAsync(Token);
}
public async void OnUnregistered(DeviceType deviceType)
{
await _azureNotificationHubService.UnregisterNativeAsync();
}
public void OnError(string message, DeviceType deviceType)
{
}
public void OnMessage(JObject values, DeviceType deviceType)
{
App.pushNotificationReceived = true;
}
public bool ShouldShowNotification()
{
return true;
}
}
public interface IAzureNotificationHubService
{
Task RegisterNativeAsync(string deviceId);
Task UnregisterNativeAsync();
}
}
@brminnick Thank you for your explanation. Still one feature missing: If I kill my app (or restart the phone), I won't receive messages.
Do you have a solution / an example for an implementation which will run PushService after restart, killing, ...?
I thought, it is already included in StartPushService()
but if I kill the app, it won't show the notification...
This is how I got it working: Its important to add the receiver in the manifest
public override void OnCreate()
{
base.OnCreate();
RegisterActivityLifecycleCallbacks(this);
AppContext = this.ApplicationContext;
//A great place to initialize Xamarin.Insights and Dependency Services!
CrossPushNotification.Initialize<CrossPushNotificationListener>("THE_ID");
CrossPushNotification.Current.Register ();
StartPushService();
}
public static void StartPushService()
{
AppContext.StartService(new Intent(AppContext, typeof(PushNotificationService)));
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Kitkat)
{
PendingIntent pintent = PendingIntent.GetService(AppContext, 0, new Intent(AppContext, typeof(PushNotificationService)), 0);
AlarmManager alarm = (AlarmManager)AppContext.GetSystemService(Context.AlarmService);
alarm.Cancel(pintent);
}
}
<permission android:name="com.appid.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="com.appid.permission.C2D_MESSAGE" />
<application android:debuggable="false" android:icon="@drawable/icon" android:label="MyApp">
<receiver android:name="com.appid.AlarmReceiver"></receiver>
<receiver android:name="com.google.android.gms.gcm.GcmReceiver" 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="com.appid" />
</intent-filter>
</receiver>
@alexbleks Thank you for your reply. I still don't understand the relationship between your manifest/receiver and the Service/Application-class.
Xamarin doc says:
Our goal is that 99% of our users should never need to manually modify AndroidManifest.xml.
Is there a way to program this receiver around this PushService? I just don't like to change the Manifest if it's not 100% necessary.
Regards
Update: Seems like CrossPushNotification.Initialize can take an instant of listener; I had a problem of playing audio before because of the whole dependency issue; but now, I can pass the audio service from Initialize to use.
Is there any progress? I tried your suggestions but only fixed the crash. When the app is closed, no push notifications are received. I tried adding into the manifest file but didn't help.
Anything else I could do?
sry for pushing this topic again but it drives me totally crazy.... I attached a small logcat data snippet where you can see the app starting but when I'm closing the app (swiping it) in android, the process seems to crash. Is that the usual behavior? In any case, the service is not working anymore, until I reopen the app....
Any idea how to debug this? Should there be more entries in logcat? push.txt
Ok, just figured out that the service is still running in the background. but push is not received or at least highlighted...
ok finally I found the bug in my code and now it's working like a charm. Problem was the (un-)registration process with my cloud server. Auth token was not sent correctly to the server after receiving a new one from google. Now everything works fine even in background.
Hi Guys, does this work with Firebase?
I receive the notification on Android but there is no title content, only shows the app name on top?
@CR4567 can you provide a sample project that is working? It's been a nightmare, I've tried a lot of things but I still can't receive notifications if my app is closed.
Thanks.
Install the nuget package in all your projects if using PCL.
You need to register the device, either create a popup or button which calls:
private void YesButtonPush_Clicked(object sender, EventArgs e) { labelPush.Text = "You will receive push notifications"; CrossPushNotification.Current.Register(); }
Just make sure place this code in your MainApplication as below, to receive notifications in background:
`
[Application]
public class MainApplication : Application, Application.IActivityLifecycleCallbacks
{
public static Context AppContext;
public MainApplication(IntPtr handle, JniHandleOwnership transer)
: base(handle, transer)
{
}
public override void OnCreate() { base.OnCreate(); RegisterActivityLifecycleCallbacks(this); //A great place to initialize Xamarin.Insights and Dependency Services!
AppContext = this.ApplicationContext;
//TODO: Replace string parameter with your Android SENDER ID
CrossPushNotification.Initialize<CrossPushNotificationListener>("your sender ID");
//This service will keep your app receiving push even when closed.
StartPushService();
}
public static void StartPushService()
{
AppContext.StartService(new Intent(AppContext, typeof(PushNotificationService)));
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Kitkat)
{
PendingIntent pintent = PendingIntent.GetService(AppContext, 0, new Intent(AppContext, typeof(PushNotificationService)), 0);
AlarmManager alarm = (AlarmManager)AppContext.GetSystemService(Context.AlarmService);
alarm.Cancel(pintent);
}
}
public static void StopPushService()
{
AppContext.StopService(new Intent(AppContext, typeof(PushNotificationService)));
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Kitkat)
{
PendingIntent pintent = PendingIntent.GetService(AppContext, 0, new Intent(AppContext, typeof(PushNotificationService)), 0);
AlarmManager alarm = (AlarmManager)AppContext.GetSystemService(Context.AlarmService);
alarm.Cancel(pintent);
}
}
}`
@iManchaDev is completely right. Same did the trick for me. @lucascc26 Something you should also check, if you want to use some code in the shared project, in the "onMessage" method, you have to delete any forms related code. Forms is not loaded at this point and will crash when a message is incoming. You will notice a "app crashed" message every time.
Hope this helps. If not, please give us a little more information about how you implemented the service and what's exactly your problem.
@iManchaDev @CR4567 thanks for the reply! My implementation looks like this:
Forms project - App ` public class App : Application { public static void RegisterSpecific<RegisterType, RegisterImplementation>() where RegisterType : class where RegisterImplementation : class, RegisterType { FreshMvvm.FreshIOC.Container.Register<RegisterType, RegisterImplementation>(); }
protected override void OnStart()
{
CrossPushNotification.Current.Register();
}
}
`
Forms project - CrossPushNotificationListener: ` public class CrossPushNotificationListener : IPushNotificationListener { private IAzureClient _azureClient;
public CrossPushNotificationListener()
{
_azureClient = FreshMvvm.FreshIOC.Container.Resolve<IAzureClient>();
}
public void OnMessage(JObject values, DeviceType deviceType)
{
}
public void OnRegistered(string token, DeviceType deviceType)
{
_azureClient.Register(token);
}
public void OnUnregistered(DeviceType deviceType)
{
_azureClient.Unregister();
}
public void OnError(string message, DeviceType deviceType)
{
}
public bool ShouldShowNotification()
{
return true;
}
}
`
Android project - AzureClient ` public class AzureClient : IAzureClient { private NotificationHub _hub;
public AzureClient()
{
var cs = ConnectionString.CreateUsingSharedAccessKeyWithListenAccess(new Java.Net.URI(Keys.HUB_URL), Keys.HUB_LISTEN_SECRET);
_hub = new NotificationHub(Keys.HUB_NAME, cs, Application.Context);
}
public void Register(string token)
{
Register(token, new string[0]);
}
public void Register(string token, string[] tags)
{
_hub.Register(token, tags);
}
public void Unregister()
{
_hub.Unregister();
}
}
`
Android project - PushNotificationAppStarter ` [Application] public class PushNotificationAppStarter : Application, Application.IActivityLifecycleCallbacks { public static Context AppContext;
public PushNotificationAppStarter(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
}
public override void OnCreate()
{
base.OnCreate();
RegisterActivityLifecycleCallbacks(this);
AppContext = this.ApplicationContext;
App.RegisterSpecific<IKeyboardHelper, AndroidKeyboardHelper>();
App.RegisterSpecific<IAzureClient, AzureClient>();
CrossPushNotification.Initialize<CrossPushNotificationListener>(Keys.GCM_SENDER_ID);
StartPushService();
}
public override void OnTerminate()
{
base.OnTerminate();
UnregisterActivityLifecycleCallbacks(this);
}
public static void StartPushService()
{
AppContext.StartService(new Intent(AppContext, typeof(PushNotificationService)));
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Kitkat)
{
PendingIntent pintent = PendingIntent.GetService(AppContext, 0, new Intent(AppContext, typeof(PushNotificationService)), 0);
AlarmManager alarm = (AlarmManager)AppContext.GetSystemService(Context.AlarmService);
alarm.Cancel(pintent);
}
}
public static void StopPushService()
{
AppContext.StopService(new Intent(AppContext, typeof(PushNotificationService)));
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Kitkat)
{
PendingIntent pintent = PendingIntent.GetService(AppContext, 0, new Intent(AppContext, typeof(PushNotificationService)), 0);
AlarmManager alarm = (AlarmManager)AppContext.GetSystemService(Context.AlarmService);
alarm.Cancel(pintent);
}
}
public void OnActivityCreated(Activity activity, Bundle savedInstanceState)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivityDestroyed(Activity activity)
{
}
public void OnActivityPaused(Activity activity)
{
}
public void OnActivityResumed(Activity activity)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivitySaveInstanceState(Activity activity, Bundle outState)
{
}
public void OnActivityStarted(Activity activity)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivityStopped(Activity activity)
{
}
}
`
And this is the payload I'm sending through Azure's Test Send
{ "notification" : { "body" : "Body", "title" : "Title", "icon" : "a_valid_icon" }, "data":{ "message":"Notification Hub test notification" } }
Or
{ "data":{ "message":"Notification Hub test notification" } }
Everything works while my app is running in foreground or in background. The problem is that I stop receiving notifications when the app is closed by swiping it from the recent apps list.
Am I missing something?
@lucascc26
If you're debugging app, this happens sometimes when app is terminated.
Try release mode and see if it works.
@iManchaDev I've tried in release mode and even signing and distributing my apk in ad hoc mode.
for me your code looks correct. Can't see an issue. Did you check what's happening to your service when you close your app and after you're receiving a notification?
PS: I don't use the Azure service so I'm not sure about that part but still looks good to me.
How can I check if my service is still running after closing the app?
there is an option in the developer settings of android... I guess it was something like service statistics...
There's nothing related to my app in there, even when the app is running. :( Do I need to change anything in my manifest.xml file?
? but that's weird... there should be something with your app name... in manifest file you only need the typical stuff, Permissions for Internet, NetworkState etc... but nothing special for the problem of the closed app.
Sorry, I was looking at the wrong place. The service keeps running while the app is running, but it's gone when I close the app.
It worked!!!! The problem was on my phone (ASUS Zenfone 3). It has something called Auto-start manager, which disables background services by default. I just needed to change that.
Thanks a lot!
:-D oh, nice. Tough problem :-) But good you found it.
@MKahmen I know it's been a while since your last post here, but did you ever find a solution?
Even when I add the manifest part in, I still cannot receive notifications when the app is not running / sleeping.
@lanceking Make sure you implement the code in your MainApplication.cs file rather than MainActivity.cs
@lanceking I decided to implement my own code based on Xamarin.iOS and Xamarin.Android examples. I had to implement custom notification styles anyways. Sorry, but can't help anymore.
@lanceking @MKahmen I recommend creating your own implementation too, because the Push Notification Plugin doesn't provide much added-value.
The Xamarin Evolve app implements Push for both iOS and Android and it's what I reference when implementing push notifications now: https://github.com/xamarinhq/app-evolve
Thanks @brminnick @MKahmen @iManchaDev ! I finally got things working.
My issue was due to it being a debug build. Pushed an AdHoc Release build and things worked fine. If I run into more issues, I'll def. refer to the Evolve app (great app btw, not sure why I didn't think to reference it first).
Hi, @iManchaDev and @CR4567 I know this an old issue but I haven't been able to make it work, I've done as you guys say setting a MainApplications.cs with the [Application] tag but I still can't get the message sent through FCM Console not sure why, I'm using the senderID given by the console and it's the same, and I do get the register ID of the device using
CrossPushNotification.Current.Register();
when application starts, all this even when the App is running, not sure what I'm doing wrong can you guys give me a little hand?
In advance thanks for help given. Side note: I have the same package name on the FCM Console and on android manifest
@William-H-M You may want to see my reply on the following thread:
https://github.com/rdelrosario/xamarin-plugins/issues/110
I appreciate what the developers of this plugin have provided free of charge to all users, however with lack of support at times I had to make a decision going forward and haven't looked back.
Good Luck
Hi @iManchaDev thanks for that It'll be great if you give anything about it from where to start or if you got a quick example of it, it will be of a lot of help, while that I'll check it out and see if I can get it work. Thanks!
Hi
I am getting notification and bind it with text on activity but not able to get notification using notification builder in notification panel.
tl;dr The Xamarin.Forms'
DependancyService
prevents Android apps from receiving push notifications when not running or backgrounded.I recommend updating the tutorial on the Push Notification Plugin's GitHub page to help prevent confusion from other developers in the future: Adding Push Notification Post to your Xamarin Forms Application. I followed this tutorial to implement the Push Notification Plugin, and it lead me to this road block: my Android app could not receive push notifications when it was not running or backgrounded.
After following this step-by-step tutorial to setup the Push Notification Plugin on Xamarin.Forms, the iOS push notifications work flawlessly and the Android devices receive push notifications when the app is running or backgrounded. But on Android, if I force-close the app so that it is no longer running (e.g. press the Recent Apps button, and swipe away my app), and then send a push notification, the device shows this error message: “Unfortunately, [App Name] has stopped” (screen shot below).
The error below was appearing because I did not call the
CrossPushNotification.Initialize<CrossPushNotificationListener>(Keys_Constants.GOOGLE_APIs_ID);
method inside[Application] OnCreate()
as is recommended on the Push Notification Plugin's GitHub page.But, the reason why I didn’t/couldn’t include this method in
[Application] OnCreate()
was becauseCrossPushNotificationListener
requires the Xamarin.Forms’DependencyService
, which is impossible in[Application] OnCreate()
because theDependencyService
hasn’t been initialized yet;global::Xamarin.Forms.Forms.Init(this, bundle);
is called in Android'sMainActivity
which hasn’t been yet instantiated when the code is executing the[Application]
class.The remedy was to break apart my cross-platform implementation of the
CrossPushNotificationListener
into a platform-specificNotificationListener
that now live in the platform-specific PCL (code below).I recommend updating the tutorial on the GitHub page to implement this plugin for Xamarin.Forms. The tutorial has the user create a
CrossPushNotificationListener
class that uses Xamarin.Forms’DependencyService
. This tutorial works flawlessly to receive push notifications on iOS, but on Android, it will only allow the device to receive push notifications while the app is running or backgrounded.Error When Sending a Push Notification to a App That Is Not Running and Not Backgrounded (Before implementing the fix)
Updated Platform-Specific Notification Listener for Android
[Application] File
AndroidPushNotificationListener.cs
AzureNotificationHubService_Android.cs