Push

Push helps you reach out to your users in a timely fashion with important messages. You can use it to inform users about updates to some piece of data, about new services available nearby or that they are winners in a game. Using Custom server code you can set up triggers which send push notifications to a targeted set of people based on changes in the data you specify.

Kinvey brings Android Push Notifications to you through an integration with Firebase Cloud Messaging (FCM) and iOS Push Notifications through an integration with AWS SNS. While push notifications can only be configured to be used by either iOS or Android devices, our APIs provide support for registering/unregistering devices and associating them with Kinvey users.

Android

Android Push functionality is provided through the Kinvey SDK on NuGet.

Console Setup

  1. Navigate to the Firebase Console and follow the guide to create a new project or select an existing project.
  2. Click the gear icon in the top left of the side menu and select Project Settings.
  3. Click on the Cloud Messaging tab and write down the Sender ID and Server Key (formerly known as Project Number).
  4. On Kinvey's console select your App.
  5. Navigate to Engagement and select Push.
  6. Click Configure Push.
  7. In the Android section, fill in the Sender ID and Server Key fields with the respective Sender ID and Server Key values obtained in step 3.
  8. Click Save

Project Setup

Android push functionality is provided through the Kinvey .NET SDK on NuGet.

On your Xamarin Android project, right click Components directory -> Get More Components. In the window that pops up, search for Google Play Services, and install the latest version (>= v22.0.0.0).

Right click your project name -> Options -> on the Build/General tab ensure the Target Framework is set to at least Android 5.0 (Lollipop)

In addition to this, you will need to add the google-services.json file that you have from the Firebase Console, and place it at the root of your app project. Please see this article for more information.

Set your Project ID when you create your client (or modify your existing client):

Client kinveyClient = new Client.Builder(your_app_key, your_app_secret)
            .SetProjectId(your_sender_ID)
            .Build();

Receiving Push Messages

For push to work, an Android application must implement two classes to receive and handle push notifications.

First, create a new class that extends KinveyFCMService. This class provides 4 methods, one for each of the possible FCM actions. Overriding these methods allows you to run any code when a message is received (for example, showing a notification or just writing to the logs).

using Kinvey;

[Service]
public class FCMService : KinveyFCMService
{
   public override void onError(string error)
   {
       DisplayNotification(error);
   }

   public override void onMessage(string message)
   {
       DisplayNotification(message);
   }

   public override void onRegistered(string registrationId)
   {
       DisplayNotification(registrationId);
   }

   public override void onUnregistered(string oldID)
   {
       DisplayNotification(oldID);
   }

   private void DisplayNotification(string message)
   {
       NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
         .SetContentTitle("Push Received!") // Set the title
         .SetSmallIcon(Resource.Drawable.Icon) // This is the icon to display
         .SetContentText(message); // the message to display.
       NotificationManager notificationManager = (NotificationManager)GetSystemService(NotificationService);
       notificationManager.Notify(100, builder.Build());
   }
}

Now that you have a class to handle receiving messages, you need to be register it with FCM. Create a new class in the same package as the above, and extend the Android class BroadcastReceiver.

[BroadcastReceiver(Permission = "com.google.android.c2dm.permission.SEND")]
public class CustomFCMBroadcastReceiver : BroadcastReceiver
{
   public override void OnReceive(Context context, Intent intent)
   {
       var i = new Intent(context, typeof(FCMService));
       i.SetAction(intent.Action);
       i.PutExtras(intent.Extras);
       context.StartService(i);
       SetResult(Result.Ok, null, null);
   }
}

In the above code sample, replace FCMService with the name of the KinveyFCMService you created earlier.

Besides you need to add the CustomFCMBroadcastReceiver to a MainActivity class.

[Activity(
    Label = "Kinvey.TestLocalLibApp",
    Icon = "@mipmap/icon",
    Theme = "@style/MainTheme",
    MainLauncher = true,
    ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation
)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
    private CustomFCMBroadcastReceiver _customFCMBroadcastReceiver;

    protected override void OnCreate(Bundle savedInstanceState)
    {
        TabLayoutResource = Resource.Layout.Tabbar;
        ToolbarResource = Resource.Layout.Toolbar;

        base.OnCreate(savedInstanceState);
        _customFCMBroadcastReceiver = new CustomFCMBroadcastReceiver();
        global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
        LoadApplication(new App());  
    }

    protected override void OnResume()
    {
        base.OnResume();
        var intentFilter = new IntentFilter();
        intentFilter.AddAction(Constants.STR_C2DM_INTENT_RECEIVE);
        intentFilter.AddAction(Constants.STR_C2DM_INTENT_REGISTRATION);
        intentFilter.AddAction(Constants.STR_KINVEY_FCM_UNREGISTRATION);
        intentFilter.AddAction(Constants.STR_KINVEY_ANDROID_ERROR);

        RegisterReceiver(_customFCMBroadcastReceiver, intentFilter);
    }

    protected override void OnPause()
    {
        base.OnPause();
        UnregisterReceiver(_customFCMBroadcastReceiver);
    }
}

Manifest Changes

To use FCM for push notifications, add the following lines within the <application> tag.

<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>

Registering the Device

Now that you have configured your manifest and added the two necessary classes, it is necessary to register a device to receive Push notifications. To register the active user to receive push notifications on the current device, use the following:

await kinveyClient.FcmPush().InitializeAsync(Application.Context)

After registration has completed, your application will be notified via the onRegistered() method of the KinveyFCMService.

Push registration occurs in the context of an initialized Kinvey client and a logged-in Kinvey user (either explicit or implicit).

Disabling Push Notifications (Android)

The unregister operation allows you to remove the current device from the user account's list of registrations, effectively stopping the user from receiving push notifications on the device. The operation is useful when the user has opted out of receiving this kind of notifications or for another reason. Unregister requires an active user. It will return an error if you call it after logging out the user.

Upon unregistering the active user, FCM replies with a confirmation which is caught by the onUnregistered handler inside the KinveyFCMService class.

await kinveyClient.FcmPush().DisablePushAsync(Application.Context);

iOS

iOS Push functionality is provided through the Kinvey SDK on NuGet.

APN and Certificate setup

Navigate to the Xamarin Push Notifications in iOS guide and follow the instructions for Creating and Using Certificates.

To confirm that the configuration is done properly, right click on your project -> Options -> iOS Bundle Signing. Both Signing Identity and Provisioning Profile should be set appropriately for your application.

Console Setup

When using Apple Push Notification Service (APNS) you will get two push certificates; one for development and one for production/ad-hoc. These certificates require push notifications to be sent to different servers depending on if your app is in development or production.

The production certificate is only usable if your app is in the App Store.

  1. Generate an Apple Push Certificate .p12 file for your app (instructions).
  2. After you export the .p12 file, on Kinvey's console navigate to Engagement and select Push.
  3. Click Configure Push.
  4. In the iOS section drag your .p12 file generated in step 1 where it says Drag here or click to upload a .p12 file.
  5. Click Save
  6. When you are ready to deploy your app, use your production/ad-hoc certificate. Export the .p12 file, and upload that to our service. Then select production as the certificate type and click Save. Deploying your application is a one-time action and cannot be undone.

Project Setup

Within the FinishedLaunching(UIApplication application) method of your AppDelegate, call:

kinveyClient.Push().RegisterForToken();

Add the following code to your AppDelegate, which will kick off registration with Kinvey and also handle registration errors from iOS. Note this code first checks if a Kinvey User has successfully logged in, and will only attempt to register if they have.

public string MyDeviceToken { get; set; }

public override void RegisteredForRemoteNotifications(
            UIApplication application,
            NSData deviceToken
)
{
    MyDeviceToken = deviceToken.ToString();

    if (kinveyClient.ActiveUser != null)
    {
      kinveyClient.Push().Initialize(MyDeviceToken);
    }
}

public override void FailedToRegisterForRemoteNotifications(
            UIApplication application,
            NSError error
)
{
    new UIAlertView(
            "Error registering push notifications",
            error.LocalizedDescription,
            (IUIAlertViewDelegate) null,
            "OK",
            null
            ).Show();
}

Add the following code after successfully logging in a user (the below code assumes this is done in a ViewController). This covers the condition where login finishes before the iOS callback for registration has completed:

string token = ((AppDelegate)UIApplication.SharedApplication.Delegate)
                .MyDeviceToken;

if (token != null)
{
  kinveyClient.Push().Initialize(token);
}

Disabling Push Notifications (iOS)

The unregister operation allows you to remove the current device from the user account's list of registrations, effectively stopping the user from receiving push notifications on the device. The operation is useful when the user has opted out of receiving this kind of notifications or for another reason. Unregister requires an active user. It will return an error if you call it after logging out the user.

kinveyClient.Push().DisablePush();

Triggering Push Notifications

In addition to using the Console, you can trigger a push notification from Business Logic or a Flex service. This approach allows for greater flexibility as it makes it possible to schedule push notifications, to tie them down to various data events, and to set advanced options supported by Android and iOS.

You can send push notification from either collection hooks, effectively tying the notification to a data event, or custom endpoints which you can call manually or programmatically when needed.

The methods for sending push notifications are provided by the push module available in both Business Logic and the Flex SDK. They include send(), sendMessage(), sendPayload(), broadcastPayload(), and broadcastMessage(). Check the module's reference for detailed information.

The following code uses the onPreSave() before-processing collection hook to send a simple push notification to all users who fancy the winning team. Instead of saving any data to the data store, this request just causes the push notification to be sent.

function onPreSave(request,response,modules){
   var userCollection = modules.collectionAccess.collection('user')
   , utils = modules.utils
   , push = modules.push
   , template = '{{name}}, the {{team}} just won!'
   , pushedMessageCount = 0
   , userCount;

   // Find all users whose favoriteTeam matches
   // the incoming request's winning team.
   userCollection.findAsync({"favoriteTeam": request.body.winningTeam})
   .then(function(userDocs){
     // Total number of messages to send
     userCount = userDocs.length;

     // Each message is customized
     userDocs.forEach(function(doc){
       var values = {
          name: doc.givenName,
          team: doc.favoriteTeam
       };

       // Render the message to send
       var message = utils.renderTemplate(template, values);

       // Send the push
       push.send(doc, message);

       // Keep track of how many pushes are sent
       pushedMessageCount++;

       // Reduce the number of users left to push to
       userCount--;
       if (userCount <= 0){
         // All pushes sent out, complete the request
         response.body = {
             "message": "Attempted to push "
             + pushedMessageCount
             + " messages."
         };
         response.complete(200);
        }
     });
  })
  .catch(function(error){
      response.body = error;
      response.complete(400);
  });
}

The body of the request must have a winningTeam property. For example:

{
  "winningTeam": "Boston Red Sox"
}

Users are expected to have a givenName property and a favoriteTeam property.

The Push notification will be similar to:

Joe, the Kansas City Royals just won!