Sample application

Our sample application demonstrates how you can build push technology into your enterprise applications. Our sample includes a server application and a client application.

Our server application monitors a server IP address that you specify. If the server goes down or is unavailable, our server application sends a push message using an HTTP POST request to the BlackBerry Enterprise Service. The BlackBerry Enterprise Service then delivers the push message to the BlackBerry device.

The Push Service on the device receives the push message and starts our client application which displays the push message. The Push Service is part of the invocation framework in BlackBerry 10.

Before you begin

You need the following to run our sample application:
  • A BlackBerry device to run our client application.
  • Access to a BlackBerry Enterprise Service to deploy our client application.
  • A .NET web server to run our server application.
  • Microsoft Visual Studio to build and publish our server application on a .NET web server.

Download and install our client application

Follow these instructions to build our client application, deploy it on the BlackBerry Enterprise Service, and then install it on your device.

  1. Clone the ServerNotify repository to your local machine. The repository includes our client and server sample code.
  2. Import the SimplePushClient project into your workspace in the Momentics IDE for BlackBerry, and then open the project.
  3. In the Momentics IDE for BlackBerry, open the bar-descriptor.xml file, and change the value for the invoke-target id tag to something that's unique for your company and application. This value identifies the client application that's the target of a push message. For example, if your company is named ABC Company, and your application is called Server Notify, then your invoke-target id could be com.abccompany.servernotify.
    <invoke-target id="com.abccompany.servernotify">
         <type>APPLICATION</type>
         <filter>
              <action>bb.action.PUSH</action>
              <mime-type>application/vnd.push</mime-type>
         </filter>
    </invoke-target>

    Note that the action tag is set to bb.action.PUSH. This value indicates that the invoke event relates specifically to push messages.

  4. In the src folder, open the PushManager.cpp file, and set the BLACKBERRY_INVOKE_TARGET_ID value to match the invoke-target id in the bar-descriptor.xml file.
    const QString PushManager::BLACKBERRY_INVOKE_TARGET_ID = 
         "com.abccompany.servernotify";
  5. You can also set the BLACKBERRY_PUSH_APPLICATION_ID to a value that's unique to your company and application. Our client application uses the application ID to register with the Push Service to receive push messages. The application ID must be the same in the client and server applications.
    const QString PushManager::BLACKBERRY_PUSH_APPLICATION_ID = 
         "bb_server_notify";
  6. Build, sign, and export the project to create the .bar file.
  7. Deploy the signed .bar file to the BlackBerry Enterprise Service server by asking the administrator to do the following:
    • Add the .bar file to the BlackBerry Enterprise Service.
    • Add the .bar file to the software configuration.
    • Apply the software configuration to the user account that you're testing with. Software policies can take some time to be applied to your device.
  8. The administrator can make the software configuration either required or optional. If the software configuration is required, our client application is installed automatically through BlackBerry World for Work on your device. If the software configuration is optional, install our application in the work space on your device from BlackBerry World for Work.
  9. Run our application once on your device so that it can register with the Push Service to start receiving push messages.

Build and publish our server application

Follow these instructions to build and publish our monitoring application on a .NET web server.

  1. In Microsoft Visual Studio, select this type of new project: Visual C#> Web> ASP.Net Empty Web Application.

    Selections to create a new project.

  2. In the Name field, type ServerNotify.
  3. In the Location field, specify a location.
  4. Click OK.
  5. Copy the following server files and folders from the ServerNotify repository on your local computer to the ServerNotify project in Microsoft Visual Studio: Default.aspx, Default.aspx.cs, web.config, and the IMG folder. You can overwrite the existing files in the project.
  6. In Microsoft Visual Studio, right-click the ServerNotify project, and click Convert to Web Application if the option is available.
  7. Clean, build, and debug the project.
  8. Rebuild and publish the project to the .NET web server.

Run our sample application

Follow these instructions to send a test push message to our client application, and monitor the status of the push messge.

  1. Visit the Default.aspx page on the .NET web server to display the UI for our server application.

    UI for our server application

  2. Type the following information in the UI:
    • Name: The name of the server to monitor.
    • IP: The IP address of the server to monitor. Type an IP address of a server that you know is unavailable. This will cause our server application to send an alert in a push message to our client application indicating that the server is down.
  3. Click Add Server.
  4. Type the following additional information:
    • Notify: The email address or the PIN of the device where you want our server application to send the push message.
    • BES : The name of the BlackBerry Enterprise Service server that handles push messages for the email address you specified (for example, bes500cnc.your_company.net).
    • BES Push Port : The port on the BlackBerry Enterprise Service server that's used to send push messages (for example, 8080).
    • Interval: The interval in seconds that you want our server application to monitor the IP address you specified.
  5. Click Start Monitoring.

    Our server application monitors the IP address you specified. If the server is down, our server application sends an alert in a push message to the email address you specified. Our client application then displays the alert in a global dialog box. Our server application also displays the status of the push message in the Results field of the UI.

Client application

The code for our client application is in the PushManager.cpp file. Here's how the code processes push messages.

Create PushService object

First, our application creates a PushService object to create a push session and perform push-related operations. The application ID and invoke-target id are parameters of the PushService() constructor.

const QString PushManager::BLACKBERRY_PUSH_APPLICATION_ID = 
    "bb_server_notify";
const QString PushManager::BLACKBERRY_INVOKE_TARGET_ID = 
   "com.abccompany.servernotify";

// ...
m_pushService = new PushService ( BLACKBERRY_PUSH_APPLICATION_ID,
   BLACKBERRY_INVOKE_TARGET_ID );

Our application also connects the signals for the createSessionCompleted and createChannelCompleted events.

connect(m_pushService,
  SIGNAL(createSessionCompleted (const bb::network::PushStatus &)),
  this,
  SLOT(createSessionCompleted(const bb::network::PushStatus&)));

 // ...
connect(m_pushService,
  SIGNAL(createChannelCompleted (const bb::network::PushStatus&,
  const QString &)), this,
  SLOT(createChannelCompleted(const bb::network::PushStatus&,
  const QString &)));

Create a session

After the PushService object is created, our application creates a session by calling createSession(). Creating a session sets up inter-process communication between our application and the Push Service.

m_pushService->createSession();

Create a channel

When the session is created, our application calls createChannel() to create a channel to the BlackBerry Enterprise Service to receive push messages. The call to createChannel() takes a URL as an argument. When creating a channel to the BlackBerry Enterprise Service, an empty string is passed as the URL.

const QString PushManager::BLACKBERRY_PUSH_URL = "";

// ...
void PushManager::createSessionCompleted(
		const bb::network::PushStatus& status) {
	if (!status.isError() && m_pushService) {
		log("Session creation completed successfully");
// ...
m_pushService->createChannel(QUrl(BLACKBERRY_PUSH_URL));

Register to launch

After our application creates a channel, it calls registerToLaunch(). This call tells the Push Service to start running our application in the background if it isn't already running when a push message arrives. In your application, if you only want to see push messages when your application is open, you don't need to call registerToLaunch().

void PushManager::createChannelCompleted(const 
          bb::network::PushStatus& status,
		const QString& token) {
	Q_UNUSED(token);
	if (!status.isError() && m_pushService) {
		log("Channel creation completed successfully");
		m_pushService->registerToLaunch();
	} else {
		log("Channel creation failed: " + status.errorDescription());
	}
}

Handle push messages

Now that a session and channel have been created, our application can handle push messages. When a push message arrives on the device, the Push Service matches the application ID in the push header to a client application that's registered with the Push Service. The Push Service then invokes the application associated with the ID.

In the PushHandler constructor, we connected the invoked() signal with the invoked() slot.

invokeManager = new InvokeManager(this);
     connect(invokeManager,
          SIGNAL(invoked(const bb::system::InvokeRequest&)), this,
          SLOT(invoked(const bb::system::InvokeRequest&)));

The void PushManager::invoked() function takes in the invoke request that includes the push message, and processes the push message like this:

  1. Checks the invoke request to see if it came from the Push Service.
    void PushManager::invoked(const InvokeRequest& request) {
    	//Check whether the app was invoked via a push
    	if (request.action().compare("bb.action.PUSH") != 0) {
    		log("Not a push invocation :("); //Nope, so we return
    		return;
    	}
  2. Creates a payload object from the invoke request.
    PushPayload payload(request);
  3. Checks that the payload is valid.
    if (payload.isValid()) {
  4. Uses the Notify URL to acknowledge that the push message was received. In your application, you would acknowledge the push message if the server application requires notification that the client application received the message.
    if (payload.isAckRequired()) { 
              m_pushService->acceptPush(payload.id());
         }
  5. Reads the push message.
    QString message = payload.data();

Our application assumes that push messages consist of four parts that are delimited with a "|" character. Our push messages also have three priority levels: low, medium, and high.

//For the purposes of this sample only we are expecting that all push 
//data is formatted into 4 parts using a '|' character as a delimiter.
QStringList messageParts = message.split('|');
if (messageParts.size() != 4) {
		log(
			"Invalid list length. Expected 4, received "
			+ messageParts.size());
        return;
}

// ...
//The first part of the push denotes the priority of the message
switch (messageParts.at(0).toInt()) {
case PushManager::Low:
	 handleLowPriorityPush();
	 break;
case PushManager::Medium:
     handleMediumPriorityPush(messageParts.at(1), 
      messageParts.at(2), messageParts.at(3));
 	break;
case PushManager::High:
  	handleHighPriorityPush(messageParts.at(1), 
       messageParts.at(2), messageParts.at(3));
  	break;
default:
  	break;
		}

If the message is in the correct format, our application splits the message into its various parts and stores them.

void PushManager::logPush(const QString & pushMessage) {
	pushList = settings.value("pushList").toList();
	QString pushMessageWithDate = pushMessage;
	pushMessageWithDate = pushMessageWithDate.append(
			"|" + QDateTime::currentDateTime().toString("h:mm:ss ap"));
	log(pushMessageWithDate);
	pushList.append(pushMessageWithDate);
	settings.setValue("pushList", pushList);


            

For low priority messages, our application adds the Splat indicator to the application icon, and closes our application if the user hasn't opened it full screen.

void PushManager::handleLowPriorityPush() {
	app->setIconBadge(bb::IconBadge::Splat);
	if (!appWasLaunchedFromRibbon() && !hasBeenFullScreened) {
		app->requestExit();
	}
}

For medium priority messages, our application sends a system notification (with the associated sound notification, LED notification, or device vibration), adds the Splat indicator to the application icon, and closes our application if the user hasn't opened it full screen.

void PushManager::handleMediumPriorityPush(const QString & title,
		const QString & body, const QString & url) {
	notification.setTitle(title);
	notification.setBody(body);
	InvokeRequest invokeRequest;
	invokeRequest.setUri(url);
	notification.setInvokeRequest(invokeRequest);
	notification.notify();
	if (!appWasLaunchedFromRibbon() && !hasBeenFullScreened) {
		app->requestExit();
	}
}

For high priority messages, our application sends a notification repeatedly using the notificationDialog (with the associated sound notification, LED notification, or device vibration), adds the Splat indicator to the application icon, and leaves our application open. The notification continues to appear until the user dismisses it.

void PushManager::handleHighPriorityPush(const QString & title,
		const QString & body, const QString & url) {
	notificationDialog.cancel();
	notificationDialog.setTitle(title);
	notificationDialog.setBody(body);
	notificationDialog.setRepeat(true);
	notificationDialog.show();
}

In your application, you should only use global dialog boxes in urgent situations. In other situations, you can display a notification to the user in the BlackBerry Hub, or you can use some other method for processing non-urgent messages.

Exit after processing a push message

Since our application calls registerToLaunch() to run in the background when a push message arrives, it continues to run after it processes the message. This can use up device resources, so we exit our application after it processes a push message. This is a good practice that you should implement in your application. You have to be careful, however, not to exit your application if it was ever displayed full screen (in the foreground) because the user might still be using your application.

To exit after processing a push message, our sample application uses the hasBeenFullScreened variable to check whether the application was ever displayed full screen. The variable is set initially to false.

PushManager::PushManager(Application *app) :
		app(app) {

	hasBeenFullScreened = false;

Our sample application also connects a slot to the fullscreen() signal. If this signal is emitted, our application was displayed full screen, and the hasBeenFullScreened variable is set to true. Our application also clears the notifications when it's displayed full screen.

connect ( app , SIGNAL ( fullscreen ()), this , 
     SLOT ( appFullScreened ()));

// ...
void PushManager::appFullScreened() {
	notification.clearEffectsForAll();
	app->setIconBadge(bb::IconBadge::None);
	hasBeenFullScreened = true;
}

After our sample application processes a low or medium priority push message, it checks the hasBeenFullScreened variable. If the variable is false, the application was never displayed full screen. Our application also checks that it was started in the background when a push message arrived (instead of by the user). If our application was started when a message arrived, it can exit after it processes the message.

if (!appWasLaunchedFromRibbon() && !hasBeenFullScreened) {
		app->requestExit();

Server application

The code for our server application is in the Default.aspx.cs file. The file includes the code for the UI and for monitoring the IP address that you specify.

Send a push message

To send the alert to our client application using a push message, the sendAlert() method sends an HTTP POST request to the BlackBerry Enterprise Service. The request includes the delivery parameters and the push message that's being sent. The BlackBerry Enterprise Service then delivers the push message to our client application.

The delivery parameters of the sendAlert() method include the following information:

  • Content of the push message (transmitData).
  • BlackBerry Enterprise Service host name (besServer).
  • BlackBerry Enterprise Service push port (besPushPort).
  • Email address or PIN of the application user (alertRecipient). We recommend using the email address.
  • Application ID for the client application (pushAppID).
  • The URL for the BlackBerry Enterprise Service that you want to send the push message to (httpURL).

For your application, you can get the host name, push port, and URL from the BlackBerry Enterprise Service administrator. You can get the application ID from the developer of the client application.

public void sendAlert(String serverName, String serverIP)
   {
     String transmitData = "2|" + serverName + " DOWN!|ALERT!!! " 
             + serverName + " at " 
             + serverIP 
             + " appears to be DOWN!!!!|http://www.woot.com";
     String besServer = tbBesName.Text;
     String besPushPort = tbPushPort.Text;
     String alertRecipient = tbRecipient.Text;
     String pushAppID = "bb_server_notify";
     String httpURL = "http://" + besServer
                         + ":" + besPushPort
                         + "/push?DESTINATION=" + alertRecipient
                         + "&PORT=" + pushAppID
                         + "&REQUESTURI=/";
     try
     {
         HttpWebRequest HttpWReq = 
           (HttpWebRequest)WebRequest.Create(httpURL);
         HttpWReq.Method = ("POST");
         HttpWReq.Headers.Add("ContentType", "text/plain");
         byte[] data = 
           System.Text.ASCIIEncoding.UTF8.GetBytes(transmitData);
         if (data.Length <= 8192)
         {
            HttpWReq.ContentLength = data.Length;
            Stream requestStream = HttpWReq.GetRequestStream();
            requestStream.Write(data, 0, data.Length);
            HttpWebResponse HttpWRes = 
              (HttpWebResponse)HttpWReq.GetResponse();
            if (HttpWRes.StatusCode == HttpStatusCode.OK)
            {
                //write success push
                tbResults.Text += "Notified " + alertRecipient 
                     + " via PUSH, 
                   Status: SUCCESS" + Environment.NewLine;
            }
            else
            {
                //write fail push
                tbResults.Text += "Notified " + alertRecipient 
                     + " via PUSH, 
                   Status: FAILED" + Environment.NewLine;
            }
            requestStream.Close();
            HttpWRes.Close();
         }
     }
     catch (Exception err)
     {
         //deal later
         tbResults.Text += "Error: " + err.ToString() 
              + Environment.NewLine;
     }
 }