Redth / PushSharp

A server-side library for sending Push Notifications to iOS (iPhone/iPad APNS), Android (C2DM and GCM - Google Cloud Message), Windows Phone, Windows 8, Amazon, Blackberry, and (soon) FirefoxOS devices!
Other
4.39k stars 1.52k forks source link

Apple service : OnDeviceSubscriptionExpired #51

Closed alaa9jo closed 11 years ago

alaa9jo commented 11 years ago

I've noticed when I send push notifications to Apple devices the library usually call OnNotificationSent event and this is normal,but here is the annoying part,the library sometimes call another event after it: OnDeviceSubscriptionExpired,and the notification parameter is null/nothing

1) Why would the library call [OnNotificationSent] though the device may have uninstalled the application ?

2) Notification parameter is really important,why it wouldn't always be returned when event OnDeviceSubscriptionExpired is called?

**My case: I noticed that apple devices that have 2 or more of my applications MAY send to my server the same device token,if a user uninstalled application X and kept Application Y and both uses the same device token how Am I suppose to remove the device (in Database) from the notifications list for application x without removing it from the notification list of application Y ? I need a flag/key or something (like application ID for instance),I've already handled this case by adding the application ID within customitems of apple notification object,I expected to read the notification object in OnDeviceSubscriptionExpired and from there I can remove the device from the list/DB using deviceinfo(devicetoken) and app ID (in customitems of notification object),but now since this method is called and notification object is null I don't know how Am I suppose to handle the case,I hope you got my point :)

P.S: Sorry for my english ^^;

Redth commented 11 years ago

Hey there,

APNS has two connections / parts to it, that are both independent of each other and not self-aware of each other. The first is the connection to send notifications, and the second is the feedback service which lets you know which applications no longer want to receive notifications (meaning you sent them a notification after they either turned them off or uninstalled the app).

So to answer your questions:

  1. APNS calls this because in reality it was sent as far as the current thread / connection knows. Apple doesn't give us immediate feedback as to whether or not an application has unsubscribed from notifications, so even apple thinks the message was sent ok in this case (and it may have been, but the device may have rejected it once it received it).
  2. There is no way for us to know which notification caused the feedback service to tell us to stop sending notifications to a device token. Apple does not give us this information, and since feedback does not come to us right after sending the notification, there is no way for us to know at that point in time.

Hope that explains things a bit better for you!

alaa9jo commented 11 years ago

Thanks for your response,Redth.

Hmm,this surely won't help me to solve the case I mentioned earlier,but as far as I know when you connect to apple feedback service you should use an application certificate,correct? if I can somehow know the certificate name (for example xyzProductionCertificate.p12) the library has used to report about a device I can figure out the application the user has uninstalled/disabled it's notifications and remove the device from the list,is that possible?

In other words,I'm thinking if it's possible for OnDeviceSubscriptionExpired to return the certificate name,that would surely help me alot,unless there is a better idea :)

Redth commented 11 years ago

@alaa9jo I would suggest in this case using a separate instance of PushService for each of your apps. You should probably avoid calling StartAppleService on the same instance of PushService, each time you want to change apps (and certificates). This is not how PushSharp was designed to be used, and Apple would prefer you not open and close connections to them either.

Just create one instance of PushService for each app (certificate) you are using, and keep them running for the lifetime of your application or service.

izb commented 11 years ago

I have also hit this problem. I have multiple connections for my different apps. I still have the problem described by @alaa9jo - at the point that the expiration callback is delivered, it is not possible for the code to figure out what app/certificate it was connected with. The device token is not enough information at that moment. If PushSharp could pass through a simple identifier of the certificate or application, it would be very helpful.

Update: I have discovered though, that you can access the certificate and its thumbprint value through the callback's sender object. By comparing this to the thumbprint value you get in the apple settings object when you create it, you can work your way back to your application.