Push Notifications for Documentation

White-Label

We provide a complete solution to send mobile push notification messages to iOS, Android, Windows Phone 8 and BlackBerry 10 platforms . With this system you have your own push notification system like other providers but to send with no limit so system connects directly with Apple & Google servers to send the push notification messages . It is an excellent choice for mobile applications owner and mobile development companies who want to provide this service for their mobile apps clients and gain profits so system provides a white label to brand your company .

Requirements

  •  PHP version 7.1 or later.
  •  Apache or Nginx.
  •  MySQL 5 or later / MariaDB 10 or later.
  •  CURL PHP library is enabled.
  •  POSIX PHP extension is installed.
  •  OpenSSL PHP library.
  •  GMP PHP library.
  •  MBSTRING PHP library.
  •  ZipArchive extension is installed.
  •  Gettext library.
  •  GD library.
  •  InnoDB and MyISAM is supported.
  •  mod_rewrite module is installed and enabled for Apache.

How to install

1- Download your purchased copy from the download center http://intupush.com/support

2- Upload your downloded ZIP file to your server using FTP

3- Unzip the uploaded file to extract its contents

4- Give folder `media` 0777 permissions

5- Open and edit file config.php which exists in this path include/config.php

6- Replace YOUR_DATABASE_NAME, YOUR_DATABASE_USER, YOUR_DATABASE_PASSWORD with your values

7- Open this link using your browser to start installing your system http://YOURSITELINK/install

8- Add this cron-job to run every minute using your CPanel or Linux command

php PATH_TO_SMART_SYSTEM_DIRECTORY/index.php cronjob

or using wget [not recommended]

wget -O /dev/null http://YOURSITELINK/cronjob

9- If your server type is Nginx, put this rule in Nginx configurations file

location / {
	try_files $uri $uri/ /index.php?route=$uri&$args;
}

In case of subdirectory

location /subdirectory/ {
	try_files $uri $uri/ @smart_system_rules;
}
location @smart_system_rules {
	rewrite ^/subdirectory/(.*)$ /subdirectory/index.php?route=$1&$args;
}

10- Increasing MySQL max_allowed_packet and max_connections [recommended]

open MySQL configurations file almost you can find it under this path

nano /etc/mysql/my.cnf

if it is blank then try

nano ~/.my.cnf

then click on ctrl+w and type

max_allowed_packet

change it to

max_allowed_packet = 500M

then click on ctrl+w again and type

max_connections

change it to

max_connections = 800

then click on ctrl+w again and type

sql-mode

change it to

sql-mode='NO_ENGINE_SUBSTITUTION'

finally restart your MySQL server

sudo service mysql restart

Install PHP 7 ZTS

These steps will build PHP with access to the `Thread` class, which in turn gives access to true multi-threading with PHP! Prerequisite: a Virtual Machine or server running a clean install of Ubuntu 16.04.

1. Update everything and install the required packages

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install libzip-dev bison autoconf build-essential pkg-config git-core libltdl-dev libbz2-dev libxml2-dev libxslt1-dev libssl-dev libicu-dev libpspell-dev libenchant-dev libmcrypt-dev libpng-dev libjpeg8-dev libfreetype6-dev libmysqlclient-dev libreadline-dev libcurl4-openssl-dev php-pear unzip libgmp-dev

2. Download, unpack and build PHP 7.2.14 from its source

wget https://github.com/php/php-src/archive/PHP-7.2.14.zip
unzip PHP-7.2.14.zip
rm -f PHP-7.2.14.zip

cd php-src-PHP-7.2.14
./buildconf --force

3. Configure PHP with the correct settings

These are the PHP configuration settings.

Note the last line’s

CONFIGURE_STRING="--prefix=/etc/php7 --without-pear --with-bz2 --with-zlib --enable-zip --disable-cgi \
--enable-soap --enable-intl --with-openssl --with-gmp --with-readline --with-curl --enable-ftp \
--enable-mysqlnd --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd --enable-sockets \
--enable-pcntl --with-pspell --with-enchant --with-gettext --with-gd --enable-exif \
--with-jpeg-dir --with-png-dir --with-freetype-dir --with-xsl --enable-bcmath \
--enable-mbstring --enable-calendar --enable-simplexml --enable-json --enable-hash \
--enable-session --enable-xml --enable-wddx --enable-opcache --with-pcre-regex \
--with-config-file-path=/etc/php7/cli  --with-mysql-sock=/var/lib/mysql/mysql.sock --with-config-file-scan-dir=/etc/php7/etc \
--enable-cli --enable-debug --enable-fpm --with-fpm-user=www-data --with-fpm-group=www-data \
--enable-sysvmsg --enable-sysvsem --enable-sysvshm --enable-shmop \
--enable-pthreads --with-tsrm-pthreads --enable-maintainer-zts"

./configure $CONFIGURE_STRING
make && sudo make install

4. Check ZTS is enabled (this should return an integer of ‘1’)

/etc/php7/bin/php -r "echo PHP_ZTS;"

5. Setup `phpize` and `php-config` for installing pThreads

chmod o+x /etc/php7/bin/phpize
chmod o+x /etc/php7/bin/php-config

6. Download, configure and install pThreads from source

Clone into the current directory from earlier – ‘php-src-PHP-7.2.14’.

git clone https://github.com/krakjoe/pthreads.git

Then move into the new ‘pthreads’ directory.

cd pthreads
/etc/php7/bin/phpize
./configure --prefix='/etc/php7' --with-libdir='/lib/x86_64-linux-gnu' --enable-pthreads=shared --with-php-config='/etc/php7/bin/php-config'
make && sudo make install

7. Check that pThreads is installed (this should return an integer of ‘1’)

/etc/php7/bin/php -r "print_r(class_exists('Thread'));"

8. Finally configure the CLI settings

Move out of ‘pthreads’ and back into the ‘php-src-PHP-7.2.14’ directory.

cd ..
mkdir -p /etc/php7/cli/
cp php.ini-production /etc/php7/cli/php.ini

echo "extension=pthreads.so" | sudo tee -a /etc/php7/cli/php.ini
echo "zend_extension=opcache.so" | sudo tee -a /etc/php7/cli/php.ini

Install Node JS

Step 1: Add Node.js PPA

sudo apt install curl

Then for the Latest release, add this PPA..

curl -sL https://deb.nodesource.com/setup_10.x | sudo bash -

Step 2: Install Node.js and NPM

sudo apt install nodejs

You can use the commands below to view the version number installed…

node -v
npm -v

Step 3: Finally install all required Node JS libraries by our system.

cd SMART_PUSH_SYSTEM_DIRECTORY_PATH
npm install web-push cluster os mysql --save

API services

Base URLhttps://intupush.com/projects/push/api/
Send TypeData can be sent in two methods POST and GET
AuthenticationSend the application access token in the HEADER or POST body for each API request with parameter name `Access_Token` to pass the authentication layer
Response Schema
respondSuccess return 1, and 0 if fails
messageReturn string message when happens error or success insert, and return empty if there’s result
resultReturn array(s) of data, and empty if there’s no result or happened error
Output TypeJSON
PHP VersionSystem requires PHP version 5.3 or later
SupportWe will be happy if you ask us for any help intuPUSH

Localization

1- Download a copy for lang.po file from your system path /language/en/LC_MESSAGES/lang.po

2- Open .PO file for editing using any suitable software or use this online solution https://localise.biz/free/poeditor

3- After finish from translating .PO file into your language choose to save your work as .MO file

4- Save .MO file with name lang.mo and upload it to the same path /language/en/LC_MESSAGES/lang.mo

Subdomain Feature

You must have a wildcard SSL certificate to use this feature.

1- Login as admin and go to Dashboard > Settings then active `Enable Subdomain` option.

2- Open .htaccess file and remove sign (#) from the beginning of 7,8,9 and 10 lines.

3- Add a wildcard subdomain in cPanel

a- Log into your cPanel

b- Navigate to Domains section > Subdomains menu

c- Create a subdomain * pointing it to your push system directory

Update Tags

1- Create your new tag by going to administrator dashboard>Device Dynamic Info>Add New Parameters

2- Choose title for your tag like (Made A Purchase) and enter Unique Name like (madePurchase)

3- Go to client dashboard and create a new advanced app

4- Upload the Javascript push.js file on your website and put the integration Javascript line in your HTML pages.

5- Now to update the tag for a certain user, you can use this Javascript function like this

<script>smpushSaveTag("madePurchase", 1)</script>

6- When you create a new campaign, you can filter your subscribers using this tag.

iOS xcode

This is a tutorial for how to implement the push notification feature inside your iOS application and connect with Push Notification System .

STEP 1:

First follow instructions here step by step to know how to create the certification filehttp://www.raywenderlich.com/32960/apple-push-notification-services-in-ios-6-tutorial-part-1

STEP 2:

In your xcode project in the file Appdelegate.m and inside this:

– (BOOL)application:(UIApplication )application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

Add this lines:

    UIUserNotificationType userNotificationTypes = (UIUserNotificationTypeAlert |
                                                UIUserNotificationTypeBadge |
                                                UIUserNotificationTypeSound);
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:userNotificationTypes
                                                                         categories:nil];
[application registerUserNotificationSettings:settings];
[application registerForRemoteNotifications];

STEP 3:

Now in the same file and outside this:

– (BOOL)application:(UIApplication )application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

Add this lines at anywhere:

- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    NSString *token = [deviceToken description];
    token = [token stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
    token = [token stringByReplacingOccurrencesOfString:@" " withString:@""];
    
    [[NSUserDefaults standardUserDefaults] setObject:token forKey:@"deviceToken"];
    
    NSData *postData = [[NSString stringWithFormat:@"token=%@", deviceToken] dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
    NSString *postLength = [NSString stringWithFormat:@"%lu",(unsigned long)[postData length]];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    //Don't forget to change the API link to your own link
    [request setURL:[NSURL URLWithString:[NSString stringWithFormat:
    @"http://smartiolabs.com/projects/push/api/save_device/?device_token=%@&device_type=ios&channels_id=1", token]]];

    [request setHTTPMethod:@"POST"];
    [request setValue:postLength forHTTPHeaderField:@"Content-Length"];
    [request setHTTPBody:postData];
    NSURLConnection *conn = [[NSURLConnection alloc]initWithRequest:request delegate:self];
    
    NSLog(@"My device token is: %@", deviceToken);
}

- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error {
    NSLog(@"Failed to get token, error: %@", error);
}

Safari Certificates

Registering with Apple

You are required to register in the Certificates, Identifiers & Profiles section of the Member Center to send push notifications. Registration requires an iOS developer license or Mac developer license.

When registering, include the following information:

  • Identifier. This is your unique reverse-domain string, such as web.com.example.domain (the string must start with web.). This is also known as the Website Push ID.
  • Website Push ID Description. This is the name used throughout the Provisioning Portal to refer to your website. Use it for your own benefit to label your Website Push IDs into a more human-readable format.

Creating a Website Push Client SSL Certificate

You use Member Center to generate a push notification client SSL certificate that allows your notification server to connect to the APNs. Each Website Push ID is required to have its own client SSL certificate.

To generate a website push client SSL certificate:

  1. In Certificates, Identifiers & Profiles, select Certificates.
  2. Click the Add button (+) in the upper-right corner.
  3. Under Production, select the “Website Push ID Certificate” checkbox, and click Continue.
  4. Choose the explicit Website Push ID that matches your Website Push ID from the pop-up menu, and click Continue.
  5. Follow the instructions on the next webpage to create a certificate request on your Mac, and click Continue.
  6. Click Choose File.
  7. In the dialog that appears, select the certificate request file (with a .certSigningRequest extension), and click Choose.
  8. Click Generate.
  9. Click Download and save the file (website_aps_production.cer).
  10. Click Done.

Generate the SSL certificate for Push Notifications for Safari configurations part

  1. Load website_aps_production.cer in the Keychain Access double-clicking on it.
  2. From the Keychain Access application select the certificate (search for “Website Push ID”) and press the right mouse button.
  3. Select “Export” and save it as Certificates.p12 using a password that you remember (the one you will use in Push Notifications for Safari configurations part as P12 Certificate Password).
  4. From the command line, in the same directory where you have saved the certificates enter this command:
    $ openssl x509 -in website_aps_production.cer -inform der -out Cert.pem
  5. Then, from the same position enter this:
    $ openssl pkcs12 -nocerts -out Key.pem -in Certificates.p12
    It will ask an import password (the one you have used in step 3) and then a secure password for the certificate (the one you will use in Push Notifications for Safari configurations part as PEM Certificate Password).
  6. At this point merge the certificate and the key together:
    $ cat Cert.pem Key.pem > ck.pem
    The ck.pem file will be the one you have to use in Push Notifications Safari configurations part.

Setup Chrome

Chrome Configuration

You need to get Project ID and API Key from the Firebase Console. You can reach to the console by this link https://console.firebase.google.com then follow the video steps to get these values.

iOS Swift

This is a tutorial for how to implement the push notification feature inside your iOS application using Swift language and connect with Push Notification System .

STEP 1:

First follow instructions here step by step to know how to create the certification filehttp://www.raywenderlich.com/32960/apple-push-notification-services-in-ios-6-tutorial-part-1

STEP 2:

In your xcode project in the file AppDelegate.swift and inside didFinishLaunchingWithOptions method add this lines :

// Register for Push Notitications, if running iOS 8
if application.respondsToSelector("registerUserNotificationSettings:") {

  let types:UIUserNotificationType = (.Alert | .Badge | .Sound)
  let settings:UIUserNotificationSettings = UIUserNotificationSettings(forTypes: types, categories: nil)

  application.registerUserNotificationSettings(settings)
  application.registerForRemoteNotifications()

} else {      
  // Register for Push Notifications before iOS 8
  application.registerForRemoteNotificationTypes(.Alert | .Badge | .Sound)
}

STEP 3:

Now in the same file and outside didFinishLaunchingWithOptions method add this lines at anywhere:

func application(application: UIApplication,didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
	let deviceTokenStr = convertDeviceTokenToString(deviceToken)
	//send this device token to server
	let urlPath: String = "http://smartiolabs.com/projects/push/api/save_device/"
	var url: NSURL = NSURL(string: urlPath)!
	var request1: NSMutableURLRequest = NSMutableURLRequest(URL: url)
	request1.HTTPMethod = "POST"
	var stringPost="device_token=\(deviceTokenStr)&device_type=ios&channels_id=1"
	let data = stringPost.dataUsingEncoding(NSUTF8StringEncoding)
	request1.timeoutInterval = 60
	request1.HTTPBody=data
	request1.HTTPShouldHandleCookies=false
	let queue:NSOperationQueue = NSOperationQueue()
	NSURLConnection.sendAsynchronousRequest(request1, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
		var err: NSError
		var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
		println("AsSynchronous\(jsonResult)")
	})
}

//Called if unable to register for APNS.
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
	println(error)
}

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
    println("Recived: \(userInfo)")
   //Parsing userinfo:
   var temp : NSDictionary = userInfo
   if let info = userInfo["aps"] as? Dictionary<string, anyobject=""> 
	{
		var alertMsg = info["alert"] as! String
		var alert: UIAlertView!
		alert = UIAlertView(title: "", message: alertMsg, delegate: nil, cancelButtonTitle: "OK")
		alert.show()
	}
}

private func convertDeviceTokenToString(deviceToken:NSData) -> String {
    //  Convert binary Device Token to a String (and remove the <,> and white space charaters).
    var deviceTokenStr = deviceToken.description.stringByReplacingOccurrencesOfString(">", withString: "", options: nil, range: nil)
    deviceTokenStr = deviceTokenStr.stringByReplacingOccurrencesOfString("<", withString: "", options: nil, range: nil)
    deviceTokenStr = deviceTokenStr.stringByReplacingOccurrencesOfString(" ", withString: "", options: nil, range: nil)
    
    // Our API returns token in all uppercase, regardless how it was originally sent.
    // To make the two consistent, I am uppercasing the token string here.
    deviceTokenStr = deviceTokenStr.uppercaseString
    return deviceTokenStr
}</string,>

Android Native

GCM architecture

  1. GCM connection server : It receives the messages from application server and send these messages to the GCM enabled android devices.
  2. Application server : It sends the message to the GCM connection server. I will use PHP to build the application server in this tutorial.
  3. Android Application : It receives the messages from GCM connection server after application server sends message to the GCM connection server.

Life Cycle Flow

  1. Android application enables the GCM by registering to the GCM. The application needs Sender ID to get the registration ID.
  2. GCM connection server receives the sender ID from application and returns the unique registration id.
  3. The application send the registration ID to the back end application server for the storage.
  4. The application server, stores the registration Id in the database.
  5. When a new message need to send, the application server fetches the registration ids from database and send to the GCM connection serer along with the message.
  6. The GCM server sends the message to the application.

Basic Library and Tools Installation

Step I : Install Google Play Services SDK
In order to use Google Services like GCM, you need to have Google Play Services SDK. Look at this official documentation to setup the SDK. One important thing you should take care is in referencing the library. You should not reference the library directly from the Android SDK. Instead first copy the library (i.e. google-play-services_lib) into your current workspace and then reference. In Eclipse, you can do this by checking the “Copy projects into workspace” checkbox while importing the project. 

Step II: Install Google APIs
For testing the project in emulator, you need Google APIs. Install the Google APIs and create a new AVD with Google APIs as the platform target. 

Step III: Install GCM for Android library
In SDK Manager.exe, expand the extras, select and install the Google Cloud Messaging for Android. Now you have setup all the library needed to create a GCM application.

Registering with Google Cloud Messaging

  1. Open the Google Cloud Console.
  2. If you haven’t created the API project yet, click CREATE PROJECT. Give the name of the project and click Create.



  3. Note down the project number. You will use the project number as sender ID in the registration process.
  4. In the sidebar on the left, click APIs and auth.
  5. In the displayed list of APIs, turn the Google Cloud Messaging for Android toggle to ON.
  6. In the sidebar on the left, click APIs & auth >> Credentials.
  7. Click CREATE NEW KEY and select Server Key.



  8. Provide the list of IP address from which the GCM server accepts the request. Left blank if you want to allow any IP.
  9. Copy down the Server Key, you will need this later.

Creating the android application

The final steps is to create a android application named GCMDemo. The project structure is given below



AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.programmingtechniques.gcmdemo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="11"
        android:targetSdkVersion="19" />

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <permission android:name="com.programmingtechniques.gcmdemo.permission.C2D_MESSAGE"
    android:protectionLevel="signature" />
 <uses-permission android:name="com.programmingtechniques.gcmdemo.permission.C2D_MESSAGE" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.programmingtechniques.gcmdemo.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <meta-data android:name="com.google.android.gms.version"
           android:value="@integer/google_play_services_version" />

        <receiver
            android:name=".GcmBroadcastReceiver"
            android:permission="com.google.android.c2dm.permission.SEND" >
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                <category android:name="com.programmingtechniques.gcmdemo" />
            </intent-filter>
        </receiver>
        <service android:name=".GcmIntentService" />
    </application>

</manifest>

activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/register"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Register Device">
    </Button>"

</RelativeLayout>


GcmBroadcastReceiver
package com.programmingtechniques.gcmdemo;
 
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.support.v4.content.WakefulBroadcastReceiver;
 
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
  
    @Override
    public void onReceive(Context context, Intent intent) {
        // Explicitly specify that GcmIntentService will handle the intent.
        ComponentName comp = new ComponentName(context.getPackageName(),
                GcmIntentService.class.getName());
        // Start the service, keeping the device awake while it is launching.
        startWakefulService(context, (intent.setComponent(comp)));
        setResultCode(Activity.RESULT_OK);
    }
}

GcmIntentService.java
package com.programmingtechniques.gcmdemo;
 
import com.google.android.gms.gcm.GoogleCloudMessaging;
import android.app.IntentService;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
 
public class GcmIntentService extends IntentService {
    public static final int NOTIFICATION_ID = 1;
 private static final String TAG = "GcmIntentService";
    private NotificationManager mNotificationManager;
    NotificationCompat.Builder builder;
 
    public GcmIntentService() {
        super("GcmIntentService");
    }
 
    @Override
    protected void onHandleIntent(Intent intent) {
        Bundle extras = intent.getExtras();
        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
        // The getMessageType() intent parameter must be the intent you received
        // in your BroadcastReceiver.
        String messageType = gcm.getMessageType(intent);
 
        if (!extras.isEmpty()) {  // has effect of unparcelling Bundle
            /*
             * Filter messages based on message type. Since it is likely that GCM
             * will be extended in the future with new message types, just ignore
             * any message types you're not interested in, or that you don't
             * recognize.
             */
            if (GoogleCloudMessaging.
                    MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
                sendNotification("Send error: " + extras.toString());
            } else if (GoogleCloudMessaging.
                    MESSAGE_TYPE_DELETED.equals(messageType)) {
                sendNotification("Deleted messages on server: " +
                        extras.toString());
            // If it's a regular GCM message, do some work.
            } else if (GoogleCloudMessaging.
                    MESSAGE_TYPE_MESSAGE.equals(messageType)) {
                // This loop represents the service doing some work.
                for (int i=0; i<5; i++) {
                    Log.i(TAG, "Working... " + (i+1)
                            + "/5 @ " + SystemClock.elapsedRealtime());
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                    }
                }
                Log.i(TAG, "Completed work @ " + SystemClock.elapsedRealtime());
                // Post notification of received message.
                sendNotification(extras.getString("message"));
                Log.i(TAG, "Received: " + extras.toString());
            }
        }
        // Release the wake lock provided by the WakefulBroadcastReceiver.
        GcmBroadcastReceiver.completeWakefulIntent(intent);
    }
 
    // Put the message into a notification and post it.
    // This is just one simple example of what you might choose to do with
    // a GCM message.
    private void sendNotification(String msg) {
        mNotificationManager = (NotificationManager)
                this.getSystemService(Context.NOTIFICATION_SERVICE);
 
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
                new Intent(this, MainActivity.class), 0);
 
        NotificationCompat.Builder mBuilder =
                new NotificationCompat.Builder(this)
       // .setSmallIcon(R.drawable.ic_stat_gcm)
        .setContentTitle("GCMDemo")
        .setSmallIcon(R.drawable.ic_launcher)
        .setStyle(new NotificationCompat.BigTextStyle()
        .bigText(msg))
        .setContentText(msg);
 
        mBuilder.setContentIntent(contentIntent);
        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
    }
}

RegisterApp.java
package com.programmingtechniques.gcmdemo;
 
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import com.google.android.gms.gcm.GoogleCloudMessaging;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.Toast;
 
 
public class RegisterApp extends AsyncTask<Void, Void, String> {
 
 private static final String TAG = "GCMRelated";
 Context ctx;
 GoogleCloudMessaging gcm;
 String SENDER_ID = "343594554298";
 String regid = null;
 private int appVersion;
 public RegisterApp(Context ctx, GoogleCloudMessaging gcm, int appVersion){
  this.ctx = ctx;
  this.gcm = gcm;
  this.appVersion = appVersion;
 }
  
  
 @Override
 protected void onPreExecute() {
  super.onPreExecute();
 }
 
 
 @Override
 protected String doInBackground(Void... arg0) {
  String msg = "";
        try {
            if (gcm == null) {
                gcm = GoogleCloudMessaging.getInstance(ctx);
            }
            regid = gcm.register(SENDER_ID);
            msg = "Device registered, registration ID=" + regid;
 
            // You should send the registration ID to your server over HTTP,
            // so it can use GCM/HTTP or CCS to send messages to your app.
            // The request to your server should be authenticated if your app
            // is using accounts.
            sendRegistrationIdToBackend();
 
            // For this demo: we don't need to send it because the device
            // will send upstream messages to a server that echo back the
            // message using the 'from' address in the message.
 
            // Persist the regID - no need to register again.
            storeRegistrationId(ctx, regid);
        } catch (IOException ex) {
            msg = "Error :" + ex.getMessage();
            // If there is an error, don't just keep trying to register.
            // Require the user to click a button again, or perform
            // exponential back-off.
        }
        return msg;
 }
 
 private void storeRegistrationId(Context ctx, String regid) {
  final SharedPreferences prefs = ctx.getSharedPreferences(MainActivity.class.getSimpleName(),
             Context.MODE_PRIVATE);
     Log.i(TAG, "Saving regId on app version " + appVersion);
     SharedPreferences.Editor editor = prefs.edit();
     editor.putString("registration_id", regid);
     editor.putInt("appVersion", appVersion);
     editor.commit();
   
 }
 
 
 private void sendRegistrationIdToBackend() {
  URI url = null;
  try {
   url = new URI("http://smartiolabs.com/projects/push/api/save_device/?device_token="+regid+"&device_type=android&channels_id=1,2");
  } catch (URISyntaxException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  HttpClient httpclient = new DefaultHttpClient();
  HttpGet request = new HttpGet();
  request.setURI(url);
  try {
   httpclient.execute(request);
  } catch (ClientProtocolException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
 
 
 @Override
 protected void onPostExecute(String result) {
  super.onPostExecute(result);
  Toast.makeText(ctx, "Registration Completed. Now you can see the notifications", Toast.LENGTH_SHORT).show();
  Log.v(TAG, result);
 }
}

MainActivity.java
package com.programmingtechniques.gcmdemo;
 
import java.util.concurrent.atomic.AtomicInteger;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.gcm.GoogleCloudMessaging;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
 
public class MainActivity extends Activity {
  
 private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
 public static final String EXTRA_MESSAGE = "message";
 public static final String PROPERTY_REG_ID = "registration_id";
 private static final String PROPERTY_APP_VERSION = "appVersion";
 private static final String TAG = "GCMRelated";
 GoogleCloudMessaging gcm;
 AtomicInteger msgId = new AtomicInteger();
 String regid;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  final Button button = (Button) findViewById(R.id.register);
   
  if (checkPlayServices()) {
      gcm = GoogleCloudMessaging.getInstance(getApplicationContext());
            regid = getRegistrationId(getApplicationContext());
            if(!regid.isEmpty()){
             button.setEnabled(false);
            }else{
             button.setEnabled(true);
            }
  }
   
  button.setOnClickListener(new View.OnClickListener() {
    
   @Override
   public void onClick(View view) {
    // Check device for Play Services APK.
       if (checkPlayServices()) {
        gcm = GoogleCloudMessaging.getInstance(getApplicationContext());
              regid = getRegistrationId(getApplicationContext());
               
              if (regid.isEmpty()) {
               button.setEnabled(false);
                  new RegisterApp(getApplicationContext(), gcm, getAppVersion(getApplicationContext())).execute();
              }else{
               Toast.makeText(getApplicationContext(), "Device already Registered", Toast.LENGTH_SHORT).show();
              }
       } else {
              Log.i(TAG, "No valid Google Play Services APK found.");
       }
   }
  });
   
   
 }
 
 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }
  
 /**
  * Check the device to make sure it has the Google Play Services APK. If
  * it doesn't, display a dialog that allows users to download the APK from
  * the Google Play Store or enable it in the device's system settings.
  */
  
 private boolean checkPlayServices() {
     int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
     if (resultCode != ConnectionResult.SUCCESS) {
         if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
             GooglePlayServicesUtil.getErrorDialog(resultCode, this,
                     PLAY_SERVICES_RESOLUTION_REQUEST).show();
         } else {
             Log.i(TAG, "This device is not supported.");
             finish();
         }
         return false;
     }
     return true;
 }
  
 /**
  * Gets the current registration ID for application on GCM service.
  *
  * If result is empty, the app needs to register.
  *
  * @return registration ID, or empty string if there is no existing
  *         registration ID.
  */
 private String getRegistrationId(Context context) {
     final SharedPreferences prefs = getGCMPreferences(context);
     String registrationId = prefs.getString(PROPERTY_REG_ID, "");
     if (registrationId.isEmpty()) {
         Log.i(TAG, "Registration not found.");
         return "";
     }
     // Check if app was updated; if so, it must clear the registration ID
     // since the existing regID is not guaranteed to work with the new
     // app version.
     int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
     int currentVersion = getAppVersion(getApplicationContext());
     if (registeredVersion != currentVersion) {
         Log.i(TAG, "App version changed.");
         return "";
     }
     return registrationId;
 }
  
 /**
  * @return Application's {@code SharedPreferences}.
  */
 private SharedPreferences getGCMPreferences(Context context) {
  // This sample app persists the registration ID in shared preferences, but
     // how you store the regID in your app is up to you.
     return getSharedPreferences(MainActivity.class.getSimpleName(),
             Context.MODE_PRIVATE);
 }
  
 /**
  * @return Application's version code from the {@code PackageManager}.
  */
 private static int getAppVersion(Context context) {
     try {
         PackageInfo packageInfo = context.getPackageManager()
                 .getPackageInfo(context.getPackageName(), 0);
         return packageInfo.versionCode;
     } catch (NameNotFoundException e) {
         // should never happen
         throw new RuntimeException("Could not get package name: " + e);
     }
 }
}

When you run the above android application, it displays a layout with a simple button. After clicking the button, the application checks whether it has registration id or not. If not then the application registers the device in background. Once it gets the registration id, it sends that Id to the application server to store in the database. The application now can receive the messages sent by the application server. Whenever it sense the new message, then it pushes the message as a notification using notification manager.

Cordova

Introduction

Many of platforms based on Apache Cordova project like PhoneGap, Monaca and ionic [e.g. http://cordova.apache.org/#supported_platforms_section]

so if you use one of this platform you can proceed in this tutorial to implement the push notification in your mobile app

and we will use a third-patry Cordova plugin in our tutorial to enable the push notification in our app

https://github.com/phonegap/phonegap-plugin-push

Installation

This requires phonegap/cordova CLI 5.0+ ( current stable v1.3.0 )

phonegap plugin add phonegap-plugin-push

or

cordova plugin add phonegap-plugin-push

Obtaining a device token

//senderID: Get Google senderID from Google console
var push = PushNotification.init({ "android": {"senderID": "12345679"},
"ios": {"alert": "true", "badge": "true", "sound": "true"}, "windows": {} } );

push.on('registration', function(data) {
	var deviceToken = data.registrationId;
	$.ajax({
		"url": "http://smartiolabs.com/projects/push/api/save_device/",
		"dataType": "json",
		"method": "POST",
		"data": {
			"device_token" : deviceToken,
			"device_type" : 'android',
			"channels_id" : '1,2'
		},
		"success": function(response) {
			console.log("Device ID "+deviceToken+" sent successfuly");
		}
	});
});

push.on('notification', function(data) {
	// data.message,
	// data.title,
	// data.count,
	// data.sound,
	// data.image,
	// data.additionalData
	alert(data.message);
});

push.on('error', function(e) {
	console.log("Error");
});

PhoneGap Build Support

Including this plugin in a project that is built by PhoneGap Build is as easy as adding:

<gap:plugin name="phonegap-plugin-push" source="npm" />

into your apps config.xml file. PhoneGap Build will pick up the latest version of phonegap-plugin-push published on npm. If you want to specify a particular version of the plugin you can add the version attribute to the gap tag.

<gap:plugin name="phonegap-plugin-push" source="npm" version="1.2.3" />
Note: version 1.3.0 of this plugin begins to use Gradle to install the Android Support Framework. Support for Gradle has recently been added to PhoneGap Build. Please read this blog post for more information.

Android Behaviour

Compiling

As of version 1.3.0 the plugin has been switched to using Gradle/Maven for building. You will need to ensure that you have installed the Android Support Library version 23 or greater, Android Support Repository version 20 or greater, Google Play Services version 27 or greater and Google Repository version 22 or greater.



For more detailed instructions on how to install the Android Support Library visit Google’s documentation.

Desktop Push Integration

We made the desktop push notification integration very easy for you so we write one file to upload in the root of your site and one line to include in your site HTML to start enabling the desktop push service for Chrome, Safari and Firefox browsers .

Requirements:

  •  To get your push permissions your site must work under HTTPS protocole
  •  Google API key and project ID how to video here
  •  Apple developer account to create your push ID
  •  Add your website domain in the whitelist field when editing your app in your push system dashboard

STEP 1:

Download the PHP file push.php from this link then unzip the compressed file and upload push.php to the root folder of your site .
Note: You should upload the file to your root so you can get the full permission to your all site parts .

STEP 2:

Open push.php file and replace the sample values with your real values and you will find them in the beginning of push.php file and here is an example for how the values will be like

//your smart push system link
define('PUSH_API_URL', 'https://YOUR_SITE_URL/projects/push');

//link for the push.php file where you uploaded
define('PUSH_URL', 'https://YOUR_SITE_URL/push.php');

//put a name for your site to appear in the notification messages
define('SITE_NAME', 'Your Site Name');

//you can get the app ID when you open the edit app page in your push system account
define('APPID', '105982477');

//Google project ID and get it from Google console https://youtu.be/Fa6208E-wXM
define('GOOGLE_PROJECT_ID', '590173865545');

//create your web ID using your Apple developer account
define('SAFARI_WEB_ID', 'web.safari.test');

//set a default 150x150 icon to appear in the push message when there is no icon in the payload
define('PUSH_NOTIFICATION_ICON', 'https://YOUR_SITE_URL/sample_icon.png');

STEP 3:

Simply add the below line in the HEAD tag of your website HTML pages or templates tag to include the push.php file and start enabling the desktop push listeners to request a permission from your visitors to receive the desktop notifications

<script type="text/javascript" src="https://YOUR_SITE_URL/push.php"></script>

Titanium Appcelerator

Obtaining a device token

To receive push notifications, your application first needs to obtain a device token. To obtain a device token:

  1. On Android, call the Titanium.CloudPush module’s retrieveDeviceToken() method.
  2. On iOS, call the Titanium.Network.registerForPushNotifications()

Once your application has obtained a device token it should save it for later use.

Obtaining a device token on Android

To obtain a device token from GCM you first need to add the CloudPush module to your project. This module is included with the Titanium SDK, but is not included by default in new projects.
To add the CloudPush module to your project:

  1. In Studio, open your project’s tiapp.xml file.
  2. In the Modules section, click the add (+) button.
  3. Select ti.cloudpush and click OK.

In your application code, require the ti.cloudpush module and call its retrieveDeviceToken() method, and register event handlers to respond to success and error events. Once a device token has been retrieved, your application can listen for the callback event to process incoming push notifications. Your application should save the device token for later use. The following code demonstrates the minimal code required to obtain a device token and setup event handlers:

// Require the module
var CloudPush = require('ti.cloudpush');
var deviceToken = null;
 
// Initialize the module
CloudPush.retrieveDeviceToken({
    success: deviceTokenSuccess,
    error: deviceTokenError
});

// Enable push notifications for this device
// Save the device token for subsequent API calls
function deviceTokenSuccess(e) {
    deviceToken = e.deviceToken;
    
    var xhr = Ti.Network.createHTTPClient();
    xhr.open('POST','http://smartiolabs.com/projects/push/api/save_device/');
    xhr.send({
        device_token:deviceToken,
        device_type:'android',
        channels_id:'1,2'
    });
}
function deviceTokenError(e) {
    alert('Failed to register for push notifications! ' + e.error);
}
 
// Process incoming push notifications
CloudPush.addEventListener('callback', function (evt) {
    alert("Notification received: " + evt.payload);
});

Obtaining a device token on iOS

To obtain a device token on iOS, call the Titanium.Network.registerForPushNotifications() and setup callbacks for the success, error, and callback events. You can also specify the types of notifications enabled for your application, which can include one or more of the following: NOTIFICATION_TYPE_ALERT, NOTIFICATION_TYPE_BADGE, NOTIFICATION_TYPE_NEWSSTAND, or NOTIFICATION_TYPE_SOUND.

For iOS 8 and later, you need to register the user notification types you want to use with the Titanium.App.iOS.registerUserNotificationSettings() method before calling the registerForPushNotifications() method. Passing the notification types to use with the registerForPushNotifications() method has no effect on devices running iOS 8 or later.

var deviceToken = null;

// Check if the device is running iOS 8 or later
if (Ti.Platform.name == "iPhone OS" && parseInt(Ti.Platform.version.split(".")[0]) >= 8) {
    function registerForPush() {
        Ti.Network.registerForPushNotifications({
            success: deviceTokenSuccess,
            error: deviceTokenError,
            callback: receivePush
        });
        // Remove event listener once registered for push notifications
        Ti.App.iOS.removeEventListener('usernotificationsettings', registerForPush); 
    };
 
	// Wait for user settings to be registered before registering for push notifications
    Ti.App.iOS.addEventListener('usernotificationsettings', registerForPush);
 
    // Register notification types to use
    Ti.App.iOS.registerUserNotificationSettings({
	    types: [
            Ti.App.iOS.USER_NOTIFICATION_TYPE_ALERT,
            Ti.App.iOS.USER_NOTIFICATION_TYPE_SOUND,
            Ti.App.iOS.USER_NOTIFICATION_TYPE_BADGE
        ]
    });

} else {
    // For iOS 7 and earlier
    Ti.Network.registerForPushNotifications({
        // Specifies which notifications to receive
        types: [
            Ti.Network.NOTIFICATION_TYPE_BADGE,
            Ti.Network.NOTIFICATION_TYPE_ALERT,
            Ti.Network.NOTIFICATION_TYPE_SOUND
        ],
        success: deviceTokenSuccess,
        error: deviceTokenError,
        callback: receivePush
    });
}

// Process incoming push notifications
function receivePush(e) {
    alert('Received push: ' + JSON.stringify(e));
}
// Save the device token for subsequent API calls
function deviceTokenSuccess(e) {
    deviceToken = e.deviceToken;
    
    var xhr = Ti.Network.createHTTPClient();
    xhr.open('POST','http://smartiolabs.com/projects/push/api/save_device/');
    xhr.send({
        device_token:deviceToken,
        device_type:'ios',
        channels_id:'1,2'
    });
}

function deviceTokenError(e) {
    alert('Failed to register for push notifications! ' + e.error);
}

Chanelog

Version 5.9.4 – 02/08/2019

-New Feature: Node JS and PHP 7 multi threading new sending algorithm accelerate web push messages sending speed rate 1000x .
-New Feature: New popup layout One Way.
-Improvement: Popup layouts improvements.
-Bug Fix: Important bugs fixes and system stability.

Version 5.9.3 – 02/01/2019

-Bug Fix: Minor bugs fixes.

Version 5.9.2 – 01/22/2019

-Improvement: Improve sending algorithm.

Version 5.9.1 – 01/09/2019

-Bug Fix: Minor bugs fixes and system stability.

Version 5.9 – 01/04/2019

-New Feature: Completely new awesome UI for create and edit application page.
-New Feature: Moved to new web push API over VAPID.
-New Feature: Easy create embedded forms for SSL apps.
-New Feature: Cover image for popup.
-New Feature: New UI for applications forms and subscription page.
-New Feature: New options to customize Chrome and Safari configurations for non-SSL websites.
-Improvement: Database structure improvements for better performance with percent 70%.
-Improvement: Important improvements for sending algorithm.
-Bug Fix: Minor bugs fixed.

Version 5.8 – 11/01/2018

-New Feature: New GDPR tools.
-New Feature: Setup guid block in the client home dashboard.
-New Feature: Authenticate with iOS APNS server using P8 certificate.
-New Feature: New settings option to modify your system privacy template.
-New Feature: New settings option to select the default app automated template.
-Improvement: New campaign page UI improvements.
-Improvement: Create application UI improvements.
-Bug Fix: Minor bugs fixed.

Version 5.7 – 05/28/2018

-New Feature: Facebook Messenger subscribe and unsubscribe commands.
-New Feature: Facebook Messenger auto subscribe button in the subscription page for `Pop-up Builder` apps.
-New Feature: Delete account button in the subscription page for `Pop-up Builder` apps.
-New Feature: New ways to show the popup box by clicking on buttons or page scrolling events.
-New Feature: Now users can change their notification settings by opening the subscription page again using the button option.
-Bug Fix: Popup box does not close after the subscription finishes.
-New Feature: Membership plans rich editor.
-Bug Fix: Fix payments search query.
-Bug Fix: Quick permission toggle inputs.
-Bug Fix: Error show popup box wit quick permission option enabled.
-Bug Fix: Minor bugs fixed.

Version 5.6 – 05/14/2018

-New Feature: A new payment gateway 2Checkout.
-New Feature: Add applications into different groups.
-New Feature: Create multiple campaigns one time for all apps.
-New Feature: Support Facebook Messenger message templates.
-Improvement: Improved the price plan tables UI.
-Improvement: Improved auto generated push.js code.
-Bug Fix: Minor bugs fixed.

Version 5.5 – 03/13/2018

-New Feature: Provide new API covers all system.
-New Feature: Pay to read option for quick apps.
-New Feature: Update segments counters as new maintenance tool.
-New Feature: HD VBX as a new SMS provider.
-New Feature: Auto login floating form when session is expired.
-Improvement: Price plans accepts decimal values now.
-Improvement: Focused menu for current page.
-Improvement: A lot of improvements on design responsive.

Version 5.4 – 01/23/2018

-New Feature: Support sending SMS messages as new platform.
-New Feature: Add Viber as new platform.
-New Feature: Manage platforms supporting for each plan.
-Improvement: Customize tutorials links.

Version 5.32 – 12/04/2017

-New Feature: Add Stripe as new payment gateway.
-Improvement: A lot of optimizations and system improvements.
-Bug Fix: Minor bugs fixed.

Version 5.31 – 12/01/2017

-New Feature: Request GPS location for quick app mode.
-Improvement: Optimize system speed for links redirection, clicks and tracking.
-Bug Fix: Prevents show popup for supported browsers in incognito mode.
-Bug Fix: Fix minor bugs.

Version 5.3 – 11/21/2017

-New Feature: Live popup box design for quick applications.
-New Feature: Import subscribers from CSV files.
-New Feature: New Chrome web push options like actions, big image, badge, direction etc...
-New Feature: New media library and uploader with limit number of files for each plan.
-New Feature: Add mobile platforms to quick applications mode.
-Improvement: Side menu UI improvements.
-Improvement: New Campaign page UI improvements.
-Improvement: General UI improvements.
-Bug Fix: Fix critical issues.

Version 5.2 – 09/29/2017

-New Feature: System is compatible now with PHP 7.
-New Feature: Add Firebase parameters for Android platform payload.
-Bug Fix: Fix critical issues.

Version 5.0 – 08/15/2017

-New Feature: Added new platform Facebook Messenger.
-New Feature: Added new platform Facebook Notifications.
-New Feature: Added new Newsletter system.
-New Feature: Added new platform Opera browser.
-New Feature: Added new platform Samsung Browser.
-New Feature: Added new platform Edge browser.
-New Feature: New GUI statistics for every campaign.
-New Feature: Auto responder campaigns.
-New Feature: Filter subscribers using tags.
-New Feature: Generating WordPress plugin automatically for quick apps.
-New Feature: Added video tutorials links for each setup part.
-Improvement: Redesign creating new advanced application page.
-Improvement: Redesign creating new campaign.
-Improvement: Improved popup page design.
-Improvement: Improved manage devices design.
-Bug Fix: Creating new invoice for free subscriptions.
Warning: This version requires IonCube installed in your server before upgrading.

Version 4.2 – 05/02/2017

-New Feature: Read and import RSS/Atom feeds and send push notification messages automatically.
-New Feature: New option to enable cache system that reduces CPU and memory usage up to 65%.

Version 4.1 – 04/13/2017

-Bug Fix: Fix bugs prevent creating new applications

Version 4.0 – 04/05/2017

-New Feature: Redesign creating new application page.
-New Feature: Support segments for desktop push platforms in quick mode integration.
-New Feature: Emoji picker for title and message fields.
-New Feature: Add ability to get GPS locations for desktop push platforms in advanced mode.
-New Feature: New amazing popup box layouts for quick mode integration.
-Improvement: Support old Apple SSL API besides new HTTP/2 API for Safari.
-Improvement: Disable expired devices for Android and Chrome.
-Bug Fix: Filter with Geo-fence in sending dashboard
-Bug Fix: Reset Safari settings for advanced mode when an error log added.
-Bug Fix: Minor bug fixes

Version 3.8 – 12/14/2016

-New Feature: Ability to add plans with unlimited resources
-New Feature: Support adding local currency
-New Feature: Add new option for delaying the appearing of popup box for the desktop push notification
-New Feature: Generate the push file of client server for advanced push option automatically
-Improvement: Change iOS and Safari (APNS) API provider to the new API from Apple https://developer.apple.com/news/?id=12172015b
Warning: This new API requires special requirements for server CURL version >= 7.46 and OpenSSL version >= 1.0.2e with HTTP/2 enabled
-Bug Fix: Update Firefox push service URL due to the last Firefox change
-Bug Fix: Minor bug fixes

Serious about security & privacy

25,000,000,000+ notifications sent

Your subscribers, your data

Web Push Notifications Made Easier
Easiest way to add user specific push notifications to your web application. Add realtime notifications, native web push notifications and a notification feed to your web app in less than 5 minutes.

Support

Intupush.com © All rights reserved