In this tutorial I will show how to integrate push notification in a Cordova Hybrid apps. Intel XDK legacy apps use pushMobi webservice to integrate push notifications but in cordova hydrid apps you have to use third party plugins.
Include Push Plugin
In this tutorial we will use third party Push Plugin to integrate push notification in Intel XDK cordova hydrid APP.
iOS Prerequisite
There are two things you need to setup push plugin in iOS app
- App ID configured for Push Notifications on Apple Developer Portal
- Generate .pem file for sending push messages from your server to apple servers
Android Prerequisite
For android you need to create a Google Developers Console project and retrieve project ID and API key
Understanding Push Notification Mechanism
Push Notification is useful when app is in background or lock state and you want to notify user about something important. You need to send the messages from your server to mobile vendor server’s and they will deliver the message to the respective phones.
When app is in background a tile is usually displayed when a new notification is received. When user clicks on the tile the app is switched to foreground state and a callback is fired by passing the message as parameter.
If app is in foreground then just a callback is fired when a new notification is received.
Registering User
Some apps require user to login to use it. For example: Gmail, Facebook etc apps require you to create or login to account. Some apps like Flappy bird, blog etc doesn’t require user to login.
Apps that require login actually sends different push notifications to different users. But the apps that don’t require login send same push notifications to all users.
If your app falls into login required category than When a user installs your app, your app needs to register the user to identify it uniquely. This will allow you to send notifications to specific users identified uniquely. Your app will get a unique token to identify the device in which app is installed. You need to send the token along with user credentials to your server so that you know to which device you need to send notification to for a particular user.
If your app falls into non-login category than also you need to register the user but in this case you can just send the unique token to your server. And then send push notification to all tokens.
Here is the code on how to register and retrieve the unique token for Android and iOS
document.addEventListener("deviceready", function(){
//Unregister the previous token because it might have become invalid. Unregister everytime app is started.
window.plugins.pushNotification.unregister(successHandler, errorHandler);
if(intel.xdk.device.platform == "Android")
{
//register the user and get token
window.plugins.pushNotification.register(
successHandler,
errorHandler,
{
//senderID is the project ID
"senderID":"",
//callback function that is executed when phone recieves a notification for this app
"ecb":"onNotification"
});
}
else if(intel.xdk.device.platform == "iOS")
{
//register the user and get token
window.plugins.pushNotification.register(
tokenHandler,
errorHandler,
{
//allow application to change badge number
"badge":"true",
//allow application to play notification sound
"sound":"true",
//register callback
"alert":"true",
//callback function name
"ecb":"onNotificationAPN"
});
}
}, false);
//app given permission to receive and display push messages in Android.
function successHandler (result) {
alert('result = ' + result);
}
//app denied permission to receive and display push messages in Android.
function errorHandler (error) {
alert('error = ' + error);
}
//App given permission to receive and display push messages in iOS
function tokenHandler (result) {
// Your iOS push server needs to know the token before it can push to this device
// here is where you might want to send the token to your server along with user credentials.
alert('device token = ' + result);
tokenID = result;
}
//fired when token is generated, message is received or an error occured.
function onNotification(e)
{
switch( e.event )
{
//app is registered to receive notification
case 'registered':
if(e.regid.length > 0)
{
// Your Android push server needs to know the token before it can push to this device
// here is where you might want to send the token to your server along with user credentials.
alert('registration id = '+e.regid);
tokenID = e.regid;
}
break;
case 'message':
//Do something with the push message. This function is fired when push message is received or if user clicks on the tile.
alert('message = '+e.message+' msgcnt = '+e.msgcnt);
break;
case 'error':
alert('GCM error = '+e.msg);
break;
default:
alert('An unknown GCM event has occurred');
break;
}
}
//callback fired when notification received in iOS
function onNotificationAPN (event)
{
if ( event.alert )
{
//do something with the push message. This function is fired when push message is received or if user clicks on the tile.
alert(event.alert);
}
if ( event.sound )
{
//play notification sound. Ignore when app is in foreground.
var snd = new Media(event.sound);
snd.play();
}
if ( event.badge )
{
//change app icon badge number. If app is in foreground ignore it.
window.plugins.pushNotification.setApplicationIconBadgeNumber(successHandler, errorHandler, event.badge);
}
}
This is how it looks on iOS
Sending Push Notification from PHP Server to Apple Push Servers
Here is the PHP code snippet to send push notification from your own server to apple servers so that apple can deliver it to the app.
$passphrase = ""; //enter passphrase that you created while generating .pem file
$message = "Sample Notification"; //notification message
$token = ""; //enter the token received by the app to uniquely identify device on which app is installed.
$payload = '{"aps":{"alert":"' . $message . '","sound":"default","badge":"1"}}';//set message, sound and badge number for the app callback to receive
$result = 'Start' . '<br />';
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'ck.pem'); //last parameter is the name of the .pem file.
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
$fp = stream_socket_client('ssl://gateway.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT, $ctx);
if (!$fp) {
exit("Failed to connect: $err $errstr" . '<br />');
} else {
echo 'Apple service is online. ' . '<br />';
}
$msg = chr(0) . pack('n', 32) . pack('H*', $token) . pack('n', strlen($payload)) . $payload;
$result = fwrite($fp, $msg, strlen($msg));
if (!$result) {
echo 'Undelivered message count: ' . $token . '<br />';
} else {
echo 'Delivered message count: ' . $token . '<br />';
}
if ($fp) {
fclose($fp);
echo 'The connection has been closed by the client' . '<br />';
}
This is how it looks on iOS when notification is received
Sending Push Notification from PHP Server to Google Cloud Messaging Android Servers
Here is the PHP code snippet to send push notification from your own server to android servers so that Google can deliver it to the app.
class GCMPushMessage {
var $url = 'https://android.googleapis.com/gcm/send';
var $serverApiKey = "";
var $devices = array();
function GCMPushMessage($apiKeyIn){
$this->serverApiKey = $apiKeyIn;
}
function setDevices($deviceIds){
if(is_array($deviceIds)){
$this->devices = $deviceIds;
} else {
$this->devices = array($deviceIds);
}
}
function send($message, $data = false){
if(!is_array($this->devices) || count($this->devices) == 0){
$this->error("No devices set");
}
if(strlen($this->serverApiKey) < 8){
$this->error("Server API Key not set");
}
$fields = array(
'registration_ids' => $this->devices,
'data' => array( "message" => $message ),
);
if(is_array($data)){
foreach ($data as $key => $value) {
$fields['data'][$key] = $value;
}
}
$headers = array(
'Authorization: key=' . $this->serverApiKey,
'Content-Type: application/json'
);
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, $this->url );
curl_setopt( $ch, CURLOPT_POST, true );
curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_POSTFIELDS, json_encode( $fields ) );
curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
function error($msg){
echo "Android send notification failed with error:";
echo "\t" . $msg;
exit(1);
}
}
$apiKey = ""; //api key
$devices = array(); //array of tokens
$message = "The message to send"; //message o send
$gcpm = new GCMPushMessage($apiKey);
$gcpm->setDevices($devices);
$response = $gcpm->send($message, array('title' => 'Test title')); //title of the message