Saturday 15 August 2015

Using nativescript push notifications from an ASP NET perspective

Nativescript added push notification support in version 1.2. I decided to try using this for my android app, but found some of the instructions a bit vague, so I thought I would add some notes to help others who are trying to use it. First of all, the details on how to install it can be found here.

One thing I found, is that getting the token from the console when using node js can be quite frustrating as there is a lot of other stuff coming through from the phone, so I would recommend installing another plugin nativescript clipboard as well, and then using this to store the token so you can paste it into an email and email it to yourself while testing.

Below is my amended code from the hello world project.

var __extends = this.__extends || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    __.prototype = b.prototype;
    d.prototype = new __();
};
var observable = require("data/observable");
var HelloWorldModel = (function (_super) {
    __extends(HelloWorldModel, _super);
    function HelloWorldModel() {
        _super.call(this);
        this.counter = 42;
        this.set("message", this.counter + " taps left");

        var pushPlugin = require("nativescript-push-notifications");
        var clipboard = require("nativescript-clipboard");
        var self = this;
        var settings =
        {
            senderID: 'YOUR GOOGLE ID'
        };

        pushPlugin.register(settings,
               // Success callback
               function (token) {
                   clipboard.setText(token);
                   alert('Device registered successfully ' + token);
               },
               // Error Callback
               function (error) {
                   alert(error.message);
               }
           );

        pushPlugin.onMessageReceived(function callback(data) {
            alert(JSON.stringify(data));
        });

        pushPlugin.onTokenRefresh(function (token) {
            alert(token);
        });
    }
    HelloWorldModel.prototype.tapAction = function () {
        this.counter--;
        if (this.counter <= 0) {
            this.set("message", "Hoorraaay! You unlocked the NativeScript clicker achievement!");
        }
        else {
            this.set("message", this.counter + " taps left");
        }
    };
    return HelloWorldModel;
})(observable.Observable);
exports.HelloWorldModel = HelloWorldModel;
exports.mainViewModel = new HelloWorldModel();

So what exactly is your google id?

You need to create an account and logon to Google Developer Console.

Create a project and click on the overview option. The project id appears at the top of the screen as "Project Number". It also appears in the url after https://console.developers.google.com/project/.

You also need to go to the APIs section and give yourself access to "Google Cloud Messaging for Android".

Then goto the credentials section and click "Add Credentials" and create a server key. Copy the API key, you will need this later.

The next step is to write the code for sending the messages to the devices. How to do this is outlined here.

It details message formats. If however, you are using ASP NET for your server technology, I include my code here, so you can reuse it.
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Drawing;

public static class AndroidGCMPushNotification
{
    #region Constants

    const string AuthorizationKey = "YOUR AUTHORIZATION KEY";
    const string SenderId = "YOUR GOOGLE PROJECT ID";

    #endregion

    #region Public Methods

    public class MessageToSend
    {
        public string Title { set; get; }  // Title of message
        public string Message { set; get; } // Message Countent
        public int? MessageCount { set; get; }  // Number to show up in message
        public long NotId { set; get; } // Notification Id - If set to zero, it makes one randomly
        public string Sound { set; get; } // Sound to play
        public Color? Color { set; get; } // Color of Notification
        public string Icon { set; get; } // Icon for Notification
    }

    /// 
    /// Send message to google servers in JSON format
    /// 
    /// Tokens generated from Nativescript code
    /// Message to send
    /// 


    public static Response SendNotificationJSON(string[] deviceIds, MessageToSend messageToSend)
    {
        var webRequest = GetWebRequest(true);

        var pushNotification = new PushNotification();
        pushNotification.registration_ids = deviceIds;

        // Data

        pushNotification.data = new Dictionary();
        pushNotification.data.Add("title", messageToSend.Title);
        pushNotification.data.Add("message", messageToSend.Message);
        pushNotification.data.Add("notId", messageToSend.NotId.ToString());
        if (messageToSend.MessageCount.HasValue)
        {
            pushNotification.data.Add("msgcnt", messageToSend.MessageCount.ToString());
        }
        if (!String.IsNullOrEmpty(messageToSend.Sound))
        {
            pushNotification.data.Add("sound", messageToSend.Sound);
        }
        if (messageToSend.Color.HasValue)
        {
            pushNotification.data.Add("color", ColorTranslator.ToHtml(messageToSend.Color.Value));
        }
        if (!String.IsNullOrEmpty(messageToSend.Icon))
        {
            pushNotification.data.Add("smallIcon", messageToSend.Icon);
            pushNotification.data.Add("largeIcon", messageToSend.Icon);
        }
        pushNotification.data.Add("time", System.DateTime.Now.ToString()); // This will not be read by nativescript

        var postData = JsonConvert.SerializeObject(pushNotification, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }).Replace("\"messageOption\":", "");

        return GetWebResponse(webRequest, postData);
    }

    #endregion

    #region Private Methods

    /// 
    /// Builds the web request for url encoded or JSON format
    /// 
    /// indicates JSON is required
    /// Web request

    private static WebRequest GetWebRequest(bool json)
    {
        WebRequest webRequest;
        webRequest = WebRequest.Create("https://android.googleapis.com/gcm/send");
        webRequest.Method = "post";
        webRequest.ContentType = json ? "application/json" : "application/x-www-form-urlencoded;charset=UTF-8";
        webRequest.Headers.Add(string.Format("Authorization: key={0}", AuthorizationKey));
        webRequest.Headers.Add(string.Format("Sender: id={0}", SenderId));

        return webRequest;
    }

    /// 
    /// Posts data and gets response from server
    /// 
    /// Web request to post
    /// Web request body
    /// 

    private static Response GetWebResponse(WebRequest webRequest, string postData)
    {
        Byte[] byteArray = Encoding.UTF8.GetBytes(postData);
        webRequest.ContentLength = byteArray.Length;

        Stream dataStream = webRequest.GetRequestStream();
        dataStream.Write(byteArray, 0, byteArray.Length);
        dataStream.Close();

        WebResponse webResponse = webRequest.GetResponse();

        dataStream = webResponse.GetResponseStream();

        StreamReader tReader = new StreamReader(dataStream);

        String sResponseFromServer = tReader.ReadToEnd();

        tReader.Close();
        dataStream.Close();
        webResponse.Close();

        return JsonConvert.DeserializeObject<Response>(sResponseFromServer);
    }

    #endregion

    #region Push Notification Classes for JSON serialization

    // Message class for serialization taken from here
    // https://developers.google.com/cloud-messaging/server-ref#table1

    private class PushNotification
    {
        public string[] registration_ids;
        public Notification notification; // Not used in nativescript
        public Dictionary<string, string> data;
        public PushNotificationOption messageOption;
    }

    private class PushNotificationOption
    {
        public PushNotificationOption()
        {
            content_available = true;
            delay_while_idle = false;
            time_to_live = 4;
            dry_run = false;
        }

        public string collapse_key;
        public string priority;
        public bool? content_available;
        public bool? delay_while_idle;
        public int? time_to_live;
        public string restricted_package_name;
        public bool? dry_run;

    }

    private class Notification
    {
        public Notification()
        {
            icon = "ic_launcher";
        }
        public string title;
        public string body;
        public string icon; // Android
        public string badge; // IOS
        public string tag; // Android
        public string color; // Android
        public string click_action;
    }

    public class ResponseResult
    {
        public string message_id { set; get; }
        public string registration_id { set; get; }
        public string error { set; get; }

    }

    public class Response
    {
        public long multicast_id { set; get; }
        public int success { set; get; }
        public int failure { set; get; }
        public int canonical_ids { set; get; }
        public ResponseResult[] results { set; get; }

    }

    #endregion
}
Run up your android app, paste the token from the clipboard and pass it into the method as a device id.

AndroidGCMPushNotification.SendNotificationJSON(string[] deviceIds, MessageToSend messageToSend)

With the magic of nativescript, you can see your push notification come through, an example is shown below.



See the MessageToSend class for things you can control. This includes :
  1. Title of message
  2. Message
  3. Unique Notification Id
  4. Message Count - see number on the right under the message time
  5. Sound - custom sound to play - you need to put the custom sound in the \platforms\android\res\raw folder. For example a mp3 or wav file. The sound passed in does not have to include the file extension
  6. Color - color of notification
  7. Icon - icon of notification - put image file in \platforms\android\res\drawable folder.
See here for Telerik's android implementation of the notification.

Hopefully this may help someone else get started at least.

No comments:

Post a Comment