Push notifications are pretty tricky, especially interfacing with Apple’s push notification service. Below are some details I’ve figured out from a recent project.
Note: This article was specfically written about a 2.x version of PushSharp. While many of the concepts are probably the same, specific referenced APIs may be different or removed in more recent versions.
A few things about the SSL certificate for authenticating with Apple’s push notification service:
Export only the private key from the Mac’s key chain to a .p12 file PushSharp can have strange problems with the certificate file if it has more than just the private key in it
- Win+R to run, then run
- File -> Add Snap-In
- Pick Certificates
- Make it for Computer Account
- Local Computer
- Open the Certificates (Local Computer) node and drill down to Personal
- Right click on Personal and choose All Tasks -> Import
- Go through the wizard to import your p12 file(s).
- In Certificate manager, right click on the imported certificate
- All Tasks -> Manage Private Keys
- Under Security, click Add
IUSRand IIS_ISUSRS` and give them read permission
- In an elevated powershell command line, run
Get-ChildItem -path cert:\LocalMachine\My
- This will list the thumbprints for the installed certificate(s)
- Copy the thumbprint of the certificate
- Fill in the thumbprint to the following script and run it. Keep the thumbprint around for later
Make sure you’ve walked through all the above steps or you might get exceptions like “Client Authentication Error - Authentication failed because the remote party has closed the transport stream.”
To instantiate an instnace of ApplePushService, you’ll need to load the certificate from the store.
private X509Certificate2 FindApnsCert(string thumbprint)
Each platform provides a unique identifier for your user’s phone. This identifier is unique to your app. You’ll need your mobile app to send this token to your server for later processing.
Apple’s tokens look something like this:
Android’s tokens look something like this:
A malformed or bad token will be reported by PushSharp.
PushSharp works asynchronously: you queue up events and they are processed by a background thread. To provide feedback on processed notifications, PushSharp uses .NET Events. You’ll want to register to each of the following events and handle it accordingly:
OnChannelException: Seems to occur when there’s an error in the underlying network stream. Probably not much you can do to recover except restart the whole service
OnServiceException: Similar to above
OnNotificationFailed: occurs for a variety of reasons in which there was a problem sending a particular notification. For example, the provided token was invalid or rejected by the service. You may want to requeue your notification or mark it as errored.
OnDeviceSubscriptionExpired: occurs (only on Apple I think) when a device token has been expired. This can happen if the user turns off push notifications or uninstalls the app. You’ll probably want to delete the offending token from your database and acquire a new one the next time the user logs into your app.
OnDeviceSubscriptionChanged: similarly, Apple may notify PushSharp that a device token has been changed. The event passes back the old token and the new token, which you can use to update the database.
OnNotificationSent: occurs when a notification was successful. Log or mark your database rows as sent.
Since PushSharp operates asynchronously and fires back events when a
notification is processed, it allows you to attach any object to a
Tag property. You can stick any information on there you might
want to help processing the events. Events that support this feature pass back
INotification parameter that will have a
Tag property on it.
I’d recommend creating a custom
NotificationTag object that at least had a
string for the DeviceToken. This will aid in debugging because it will allow
you to log which device tokens are failing. You can add other needed properties
later, such as UserID or DeviceType.
You can add the tag to the Notification object using the
WithTag method, just
like we used