PhoneGap, Parse.com, and Push Notifications
Edit on March 7, 2013: Please read this blog entry.
As I've been working my way through a sample application that makes use of Parse.com and PhoneGap, I wanted to take a look at how Parse handles Push Notifications. I assumed it would be easy and I'd simply include it into my series, but it turned out to be a more complex than I anticipated. Therefore, I've decided to blog about it on its own so as to keep things as simple and direct as possible. In the end, the process to get notifications working with PhoneGap and Parse wasn't terribly difficult, but there are a few things you have to orchestrate just right to get the desired results.
The first thing I need to warn you about is that notifications are going to be slightly different based on each platform. In general, you can do many of the same things between Android and iOS, but there are a few differences. You can take a look at the Android docs and the iOS docs as well as checking out a video the Parse team made just for iOS. You may notice that the JavaScript API has a section on Push Notifications as well, but it only supports creating new notifications. This confused me for a while until I remembered that outside of native applications, it wouldn't make sense for JavaScript to handle receiving notifications. Therefore, you have to use a native solution. Luckily PhoneGap allows us to do that and make use of the JavaScript API as well.
In this blog post I'll be using Android. Only the initial setup aspects though will be Android specific, The PhoneGap code we use later should work fine in iOS as well.
Note though that you will need to get your hands dirty a bit and work with Java. You don't need to actually write any Java, but this does mean that PhoneGap Build will not be an option for apps making use of notifications. I used Eclipse for my application but you can probably get away with just using the command-line tools with PhoneGap.
Part One - Eclipse/Java Setup
Ok, so let's get started. First - create an Android PhoneGap project. I used the AppLaud plugin to make it super easy. I tend to be antsy about such things so before I did anything else I confirmed it ran on my mobile device. Also, I assume you have some Parse.com application already created. I'm not talking about a mobile application I mean an application defined at Parse's web site. I made use of my CowTipLine application.
Go to the Parse downloads and get the Android SDK. Note that this SDK is just a jar file (Parse-1.1.6.jar). Copy this jar file to your PhoneGap project's libs folder:

At this point you probably want to refresh the view in Eclipse so it recognizes a new file. As we all know, Eclipse gets snooty if you dare to actually use your file system.
Now - following along the Android notifications docs, you're asked to modify your AndroidManifest.xml to add the following lines:
These lines basically act as a listener for Parse.com push notifications. They will enable your application to recognize and respond to the notifications sent out by the server.
The Parse docs then tell you to add three sets of permissions, but by default PhoneGap already has two of them set. You should only need to add the RECEIVE_BOOT_COMPLETED permission from the set below:
Ok, now you need to get into the Java a bit. When you created your application, you had to give it a package name. I called mine org.camden.test1. I ended up with a Java file called MyPhoneGapActivity.java. You can find this under the src folder.

Do not worry about the com.borismus.webintent folder. You will not have it yet and we'll come to that later.
You don't normally need to edit this file if you use the AppLaud plugin. If you built the project by hand following the PhoneGap Android guide then you have already worked with this file a bit.
Get this file open, and do the following:
- Add an import com.parse.*; below your other imports.
- Add a Parse.initailize(this, a, b) line in your onCreate method. "a" is your application key and "b" is your client key.
- Finally, add PushService.subscribe(this, "", MyPhoneGapActivity.class). Your "So and So.class" will differ depending on the name of your file. This line handles telling the application to listen in for messages from Parse. Parse supports multiple channels for filtered notifications, but the empty string represents the "broadcast" channel.
Here is my entire Java file.
Ok, at this point you want to ensure the application still compiles. Hit the nice little green arrow Eclipse button to rerun the application. In theory, you will see nothing different, but you want to ensure it at least runs ok on your device. Also, by running the application once, your application "subscribes" to push notifications from your application on Parse. That will be crucial for the next step.
Testing Notifications at Parse
I know I sound like a Parse fanboy (even though they don't seem to want to ever tweet about my blog posts ;) but I cannot stress how nice the developer tools are at Parse. Creating messages can be done with Android, iOS, REST, and the JavaScript API. But they went ahead and built in a push notifications panel on their application dashboard:

I recognize that screen shot has a lot of information on it, so let me quickly review it. You can see a list of all previously sent messages on top. Beneath it is a form to let you send messages. I mentioned above that applications can choose to subscribe to a particular channel. What channels you use are entirely dependent on your application. For now you will just ignore this and use the default Broadcast channel. In the Push Data box, keep the radio button at the default (Message) and enter something wise.

Hit the Send button and you should see - pretty darn immediately - the alert arrive on your device:

You can even close the application. If you send a new notification and select it in your Android... err.... whatever they call it (notification tray?) your application should open up.
Congratulations. You can now send notifications to your device.
Responding Intelligently to Notifications
So all of the above took me less than an hour. It was pretty cut and dry. But then I hit a pretty big roadblock. How could I make my application recognize when it was loaded via a notification and actually tell me what the notification was?
From what I read in the Android docs, it seemed to imply that you had to write a custom Java class. I wasn't opposed to this, but I really wanted a solution that would let me use JavaScript to respond to the notification.
I went back to the article I wrote back in May about Intents and PhoneGap. In that article I discussed how the WebIntents PhoneGap plugin would give us access to both creating and responding to intents with JavaScript.
I won't repeat the instructions from that article, but the basics are - you copy the jar from that plugin (remember in that first screen shot when I said you wouldn't have that particular folder?) as well as the JavaScript file and then add a script tag reference in your index.html to load it.
The WebIntents plugin has a few APIs, but the ones we care about are hasExtra and getExtra. hasExtra is used to see if extra "stuff" was passed in from the intent that loaded us and getExtra is what actually gets the data. This is where I got stuck though. The WebIntents docs show using a few constants (EXTRA_TEXT, EXTRA_SUBJECT, EXTRA_STREAM, and EXTRA_EMAIL) and I assumed I had to use one of those four. I built quick blocks of code to check for all four, updated my application on the device, sent a message, clicked on the notification, and waited to see which JavaScript block would pass the getExtra test. Unfortunately none of them did.
At this point I figured I was pretty much toast. I Googled a bit. Scratched my head. Pouted a bit too. Finally, I tried something new. In my getExtra call, I tried using what I had seen as a class related to Push Notifications:
window.plugins.webintent.hasExtra("com.parse.Data"
To my surprise, this worked! So it turns out the WebIntent plugin's JavaScript API can work with any form of intent data as long as you know the proper identifier. I quickly whipped up the following:
All I do is run the has test followed by a get call. I take the data, JSON stringify it, and log it to my console.

And that's it. Obviously real code would parse this data and do, well, whatever you want with it. As should be clear from the Parse.com form, you can send more than simple messages. Complex structures of data can be sent to your listening devices. Again, the whole Push Notification feature as a whole is very powerful. I definitely encourage you to look at it yourself, and knowing that you can use it within PhoneGap as well just makes it even better.
If you have any questions, or suggestions for improvement, just leave a comment below.

some help?
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
To your second comment - check the console in Eclipse to see what is reported.
Then I read your blog post. All I needed was the Parse.jar, code for the androidmanifest.xml, and the code that went into the main activity. I didn't need to transfer the whole package over from the files the website gave me lol.
10-23 19:57:09.824: ERROR/NotificationService(109): Ignoring notification with icon==0: Notification(contentView=com.testapp/0x1090098 vibrate=default,sound=default,defaults=0xffffffff,flags=0x10)
Any idea of what is happening?
Here's part of the AndroidManifest.xml:
--------------------------------------------
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application android:label="@string/app_name">
<activity android:name="TestActivity"
android:label="@string/app_name"
android:configChanges="orientation|keyboardHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<service android:name="com.parse.PushService" />
<receiver android:name="com.parse.ParseBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.USER_PRESENT" />
</intent-filter>
</receiver>
</application>
My Activity:
-------------------------------------------
package com.example;
import android.app.Activity;
import android.os.Bundle;
import com.parse.Parse;
import com.parse.PushService;
import org.apache.cordova.*;
public class TestActivity extends DroidGap {
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.loadUrl("file:///android_asset/www/index.html");
Parse.initialize(this, "ux9bn4dSY8R6QMVro9eN0bToXWwGSa2DMAri0pkc", "KOC2KVtrY3oIzuKKea6ejsqgZ84t3p8txO5oELPo");
PushService.subscribe(this, "", TestActivity.class);
}
}
I've spent more than 2 days on this now. I've tried the app on 4.0 emulator, 4.0 virtualbox VM and my 4.0 android phone, none of them work :(
I have just followed your tutorial and worked perfectly for me.I try to implement a score application, when I receive the notification is there a way to show the notification as a view on html inside PhoneGap?
Thank you very much,
Is there a way to send live data into Phonegap page with Parse or any other idea?
Is it possible to show the message inside Phonegap page after you clicked on the notification?
I may be misunderstanding you though. This _should_ be simple, right? (And I don't mean that to offend - I may not have done a well enough job explaining things.)
If you look at my last code block, the logic inside function(d) where I just console.log it - that's where you would add "real" code.
It will be very useful to convert this into PhoneGap + Parse tutoial?
https://www.parse.com/tutorials/parse-query-table
<uses-sdk
android:minSdkVersion="9"
android:targetSdkVersion="15" />
Apparently, when installed, it would make an alert sound, but not show the text, as Tom described. I saw it too. When changed to
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="15" />
it worked. I'm thinking maybe the Android SDK version 9 didn't support the type of push notifications Parse was sending out.
http://pusher.tenderapp.com/discussions/questions/...
it should appear to the user as concurrent) receiving PUSH notifications
from Pusher.com??
Phil's answer: When you update the database you can then publish any new or updated information through Pusher to all connected users, yes.
If you are still talking about PhoneGap though, this whole thread of ours doesn't make sense to me, as I described how to make it work (yes you go to Java, but your code app is still HTML/JS).
I am using parse notifications with PhoneGap.(cordova 2.1.0). Devices are getting registered on parse.com, but when i send the notifications, devices are not receiving these notifications
My actvity class is:
package com.phone;
import org.apache.cordova.DroidGap;
import android.os.Bundle;
import com.parse.Parse; import com.parse.PushService;
public class ParsePushActivity extends DroidGap {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.loadUrl("file:///android_asset/www/index.html");
Parse.initialize(this,"app key","client key");
PushService.subscribe(this, "", ParsePushActivity.class);
}
}
while index.html is :
<!DOCTYPE HTML>
<html> <head>
<meta name="viewport" content="width=320; user-scalable=no" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>PhoneGap</title>
<script type="text/javascript" charset="utf-8" src="cordova-2.1.0.js"></script>
</head> <body >
<h1>Welcome to Cordova!</h1>
<h2>this file is located at assets/www/index.html</h2>
</body> </html>
and manifest file :-
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.phone"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="10" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:label="@string/app_name"
android:name="com.phone.ParsePushActivity" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="com.parse.PushService" />
<receiver android:name="com.parse.ParseBroadcastReceiver"> <intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.USER_PRESENT" />
</intent-filter> </receiver>
</application>
</manifest>
Please help..
message: could not connect to push server
<supports-screens
android:largeScreens="true"
android:normalScreens="true"
android:smallScreens="true"
android:resizeable="true"
android:anyDensity="true" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
thanks
Great tutorial, but I'm having some troubles with the last part: notification on device.
In device appears "DEVICE IS READY". It also registers with PARSE.COM, but when I send a push notification from Parse's website it doesn't show on device.
I've checked all twice and twice again. I'm using Phonegap 2.5.
I'm using a Galaxy Tab 2, Android 4.0
Thank you in advance.
Best regards!
it's something with the code block below, when I comment out from the code block from where it says // start to // finish the function works (I get the alerts).
Uncommented, I do not get the alerts, which is why I thought it was the intent-filter (ie I am trying to read an intent it doesn't know about),
this script is the listed last in my header, under where all the other javascript source statements are, including the webintent.js declaration is.
<script>
alert("this script launched");
function init() {
document.addEventListener("deviceready",device_Ready,false);
}
function device_Ready() {
alert("Device Ready Fired");
// start
window.plugins.webintent.hasExtra("com.parse.Data",
function(has) {
if(has) {
window.plugins.webintent.getExtra("com.parse.Data",
function(d) {
alert("we have extra data");
//console.log(JSON.stringify(d))
}, function() {
// There was no extra supplied.
alert("we do not have extra data");
}
);
}, function() {
alert('fail');
}
);
// finish
}
</script>
Sorry
Description Resource Path Location Type
The import android.util.Log is never used WebIntent.java /testapp/src/com/borismus/webintent line 13 Java Problem
The method getContext() from the type CordovaInterface is deprecated WebIntent.java /testapp/src/com/borismus/webintent line 76 Java Problem
The method getContext() from the type CordovaInterface is deprecated WebIntent.java /testapp/src/com/borismus/webintent line 84 Java Problem
The method getContext() from the type CordovaInterface is deprecated WebIntent.java /testapp/src/com/borismus/webintent line 96 Java Problem
The method getContext() from the type CordovaInterface is deprecated WebIntent.java /testapp/src/com/borismus/webintent line 187 Java Problem
Errors:
Description Resource Path Location Type
The method getContext() is undefined for the type CordovaInterface WebIntent.java /TestApp/src/com/borismus/webintent line 76 Java Problem
The method getContext() is undefined for the type CordovaInterface WebIntent.java /TestApp/src/com/borismus/webintent line 84 Java Problem
The method getContext() is undefined for the type CordovaInterface WebIntent.java /TestApp/src/com/borismus/webintent line 96 Java Problem
The method getContext() is undefined for the type CordovaInterface WebIntent.java /TestApp/src/com/borismus/webintent line 187 Java Problem
Warnings:
The method success(PluginResult, String) from the type Plugin is deprecated WebIntent.java /TestApp/src/com/borismus/webintent line 145 Java Problem
The type Plugin is deprecated WebIntent.java /TestApp/src/com/borismus/webintent line 16 Java Problem
The type Plugin is deprecated WebIntent.java /TestApp/src/com/borismus/webintent line 30 Java Problem
Wondering what would be different to get this up and running with iOS and Javascript? Would I just get the iOs SDK or something? Help!
First is this article by my coworker, Holly. It describes the Push support available via another plugin and compatible with PhoneGap Build: http://devgirl.org/2013/01/24/push-notifications-p...
Here is another article I'd recommend by Holly: http://devgirl.org/2012/12/04/easy-phonegap-push-n...
Oh and get the latest JavaScript file as well of course.
*Pro Tip - make changes to your Eclipse project, do a project >> clean >> close Eclipse >> [navigate to your project directory and delete the bin and gen folders >> restart Eclipse.
That aside...
I feel there is an error in your javascript checking for getExtra:
window.plugins.webintent.hasExtra("com.parse.Data",
function(has) {
if(has) {
window.plugins.webintent.getExtra("com.parse.Data",
function(d) {
console.log(JSON.stringify(d))
}, function() {
// There was no extra supplied.
}
);
}, function() {
alert('fail');
}
);
it seemed like the last line is missing a closing brace before the closing parens and semi-colon.
So I modified it to this:
window.plugins.webintent.hasExtra("com.parse.Data",
function(has) {
if(has) {
window.plugins.webintent.getExtra("com.parse.Data",
function(d) {
console.log(JSON.stringify(d))
}, function() {
// There was no extra supplied.
}
);
}, function() {
alert('fail');
}
});
But then there was an error barking about the comma before the function that calls alert('fail'); so I took that out and have it working to let me know I got data!
here is my ending code sample:
<script>
function init() {
document.addEventListener("deviceready",deviceReady,false);
}
function deviceReady() {
alert("Device Ready");
window.plugins.webintent.hasExtra("com.parse.Data",
function(has) {
if(has) {
window.plugins.webintent.getExtra("com.parse.Data",
function(d) {
//console.log(JSON.stringify(d))
alert('App invoked from alert with data');
}, function() {
// There was no extra supplied.
alert('No data passed');
}
);
}
});
}
</script>
However I never get the 'No data passed' message...
Btw - I strongly recommend skipping Eclipse. Unless you like it of course. I do everything in a nicer editor like Brackets and simply build/deploy at the command line.
First of all thank you very for this tutorial. I've followed it and it works flawless.
However, I've been stuck and maybe you can help me. My question is: how could I save current user in parse installation data so that I can send to him a specific notification if I can not do it from Javascript? I mean, is there any way store it using cloud code or something like that? I know that it can be done using the parse rest api, but the problem is that in order to do that I need to know the device installation object id and I can not find the way to obtain it.
Again, thank you very much. I will be looking forward to hearing from you.
What you need to look at doing is write a basic plugin so that
HTML/JQUERY button pressed -> Calls Native Code -> Runs Native Code and Returns Success/Error - > Passes result back to Web window
At least that's how I achieved it.
For those using Phonegap, it's hard to get out of the javascript frame of mind. You can't get the device ID via Javascript. It's stored in the Installation object with the Java code or IOS code that you used to setup.
I managed to write a basic phonegap plugin in about 5 minutes (after 3 hours of research!) I will have to do the Android soon, so if you're interested bookmark and I will post it later
I achiieved this in the same way, by using javascript to grab user's ID at logon, put an A in front of it, and then pass to the subscribe function in the native code via phonegap cordova.exec() function written. Check out phonegap page for examples
Great article.
My advice to everyone who tries to follow this guide is not to use phonegap 2.7.0. Apparently deprecated org.apache.cordova.api.Plugin class was removed from this version and you will have to edit WebIntent class to extend CordovaPlugin instead of Plugin to make it work.
@hmedRagheb
If you haven't figured out already, you have to call Parse.initialize method in your application class, not in the activity class. Otherwise it takes about 10 minutes for push notification to be delivered when application is closed, gods know why.
super.loadUrl("file:///android_asset/www/index.html", 15000);
Parse.initialize(this, "bla", "bla");
PushService.setDefaultPushCallback(this, MyApp.class);
ParseInstallation.getCurrentInstallation().saveInBackground();
PushService.subscribe(this, "Broadcast", MyApp.class)
I' using cordova 2.2.0 BTW.
If this might be helpfull for other i'm glad. Second, is there anyone that found a solution for the IOS Intelligent handling. I have just pieces of information, and the Webintent is a Android specific option.
Any help would be greatly appreciated.
Also: http://devgirl.org/2012/10/19/tutorial-apple-push-...