This research log looks into the push notification capabilities of parse.com. It also gives out a few code samples to test various scenarios. I will have a formal article soon here based on this information here.

satya - 4/29/2013 3:38:40 PM

quick start guide for push

quick start guide for push

satya - 4/29/2013 4:32:48 PM

Setting up your app for starting development with push

Setting up your app for starting development with push

satya - 4/29/2013 4:34:12 PM

At a high level


Register the parse push broadcast receiver
Register the parse push service
Set push related permissions
Tell parse the app is ready for push

satya - 4/29/2013 4:45:43 PM

You can setup channels to target messages

Channels are just topic names. Clients can subscribe to them. Each channel may have a separate activity associated with them.

satya - 4/29/2013 4:55:16 PM

Can I get all the available channels for an App in parse?

Can I get all the available channels for an App in parse?

Search for: Can I get all the available channels for an App in parse?

satya - 4/29/2013 4:55:32 PM

Here is a quick discussion

Here is a quick discussion

satya - 4/29/2013 4:58:01 PM

Can push channels be created using the parse dashboard?

Can push channels be created using the parse dashboard?

Search for: Can push channels be created using the parse dashboard?

satya - 4/30/2013 9:49:54 AM

Parse error: This object has an outstanding network connection. wait

Parse error: This object has an outstanding network connection. wait

Search for: Parse error: This object has an outstanding network connection. wait

satya - 4/30/2013 9:52:39 AM

Here is some explanation from Parse for this behavior

Here is some explanation from Parse for this behavior

satya - 4/30/2013 10:59:49 AM

This seem to work


public void onCreate() {
      super.onCreate();

      Log.d(tag,"initializing with keys");
      // Add your initialization code here
      Parse.initialize(this, PARSE_APPLICATION_ID, PARSE_CLIENT_KEY);

      //This will automatically create an annonymous user
      //The data associated to this user is abandoned when it is 
      //logged out.
      //ParseUser.enableAutomaticUser();
      ParseACL defaultACL = new ParseACL();
       
      // If you would like all objects to be private by default, remove this line.
      defaultACL.setPublicReadAccess(true);
      ParseACL.setDefaultACL(defaultACL, true);
      
      //Enable to receive push
      PushService.setDefaultPushCallback(this, RespondToPushActivity.class);
      ParseInstallation pi = ParseInstallation.getCurrentInstallation();
 
      //Subscribe to a channel
      Context ctx = this.getApplicationContext();
      PushService.subscribe(ctx, "ch1", RespondToPushActivity.class);
      
      pi.saveEventually();
      Log.d(tag,"initializing app complete");
   }

satya - 5/1/2013 11:26:40 AM

Apparently the parse sdk v1.2.3 might fix some of these threading issues

for instance the parseinstallation.saveinbackground() might work with this new sdk. I havent' tried. It is always dicey when you talk to a server and Android doesn't have a natural wait so all apis are best when they are asynchronous!

So for now i will rather use saveeventually() unless i need an immediate save.

satya - 5/1/2013 11:27:15 AM

Ofcourse saveinbackground is preferred when it works with a callback.

Ofcourse saveinbackground is preferred when it works with a callback.

satya - 5/1/2013 11:36:47 AM

There are three apis to control channels


PushService.subscribe
PushService.unsubscribe
PushService.getSubscriptions

satya - 5/1/2013 11:37:20 AM

Sending client side pushes


//First enable it on the dashboard...then

ParsePush push = new ParsePush();
push.setChannel("Giants");
push.setMessage("The Giants just scored! It's now 2-2 against the Mets.");
push.sendInBackground();

satya - 5/1/2013 11:37:51 AM

Or this


LinkedList<String> channels = new LinkedList<String>();
channels.add("Giants");
channels.add("Mets");
 
ParsePush push = new ParsePush();
push.setChannels(channels); // Notice we use setChannels not setChannel
push.setMessage("The Giants won against the Mets 2-3.");
push.sendInBackground();

satya - 5/1/2013 11:43:26 AM

You can do this also


// Saving the device's owner
ParseInstallation installation = ParseInstallation.getCurrentInstallation();
installation.put("owner",ParseUser.getCurrentUser());
installation.saveInBackground();

satya - 5/1/2013 11:45:34 AM

Now that allows


// Create our Installation query
ParseQuery pushQuery = ParseInstallation.getQuery();
pushQuery.whereEqualTo("owner", "satya");
 
// Send push notification to query
ParsePush push = new ParsePush();
push.setQuery(pushQuery); // Set our Installation query
push.setMessage("Hello this is just for you!");
push.sendInBackground();

satya - 5/1/2013 1:56:21 PM

is there a limit to the length of a parse Push message?

is there a limit to the length of a parse Push message?

Search for: is there a limit to the length of a parse Push message?

satya - 5/1/2013 1:57:02 PM

Can I send a bit longer JSON data and a message through Parse Push Dashboard?

Can I send a bit longer JSON data and a message through Parse Push Dashboard?

Search for: Can I send a bit longer JSON data and a message through Parse Push Dashboard?

satya - 5/1/2013 3:08:04 PM

Nature of parsepush

A push can either have channels or a query. Setting this will unset the query.

satya - 5/1/2013 3:09:51 PM

This doesn't seem to work


public void sendMessage(View v)
   {
      ParsePush push = new ParsePush();
      String message = "Client message" + Integer.toString(i++);
      push.setMessage(message);
      push.sendInBackground();
   }

It is targeting no channels. So no clients seem match this criteria.

wonder what happens if I subscribe to a channel which is an empty string!

satya - 5/1/2013 3:10:13 PM

I will try this with a query to see if that can query all users!

I will try this with a query to see if that can query all users!

satya - 5/1/2013 3:15:26 PM

Here is what a serverside push structure looks like


Targeting : channels includes "ch1"
deviceType is "android"
Sending date : May 1st, 2013 at 3:13 PM
Expiration : None
Full target : { "channels": { "$in": [ "ch1" ] }, "deviceType": "android" }
Full data : {"alert"=>"Client message0"}

satya - 5/1/2013 3:20:00 PM

You have to enable client side push to see the channel subscriptions to work!

You have to enable client side push to see the channel subscriptions to work!

satya - 5/1/2013 3:30:29 PM

What is the limit (180) to the amount data that can be sent on a push message in Parse?

What is the limit (180) to the amount data that can be sent on a push message in Parse?

Search for: What is the limit (180) to the amount data that can be sent on a push message in Parse?

satya - 5/1/2013 3:45:19 PM

Looks like you can do this


public void sendMessageAsData(View v)
   {
      JSONObject data = getJSONDataMessage();
      ParsePush push = new ParsePush();
      push.setChannel("ch1");
      push.setData(data);
      push.sendInBackground();
   }
   
   private JSONObject getJSONDataMessage()
   {
      try
      {
         JSONObject data = new JSONObject();
         data.put("alert", "Main Message");
         data.put("customdata", "custom data value");
         return data;
      }
      catch(JSONException x)
      {
         throw new RuntimeException("Something wrong with JSON", x);
      }
   }

satya - 5/2/2013 12:21:48 PM

Read up on sending notifications in Android

Read up on sending notifications in Android

satya - 5/2/2013 1:54:19 PM

Here is how you send data using an intent


private JSONObject getJSONDataMessageForIntent()
   {
      try
      {
         JSONObject data = new JSONObject();
         //Notice alert is not required
         //data.put("alert", "Message from Intent");
         //instead action is used
         data.put("action", TestBroadcastReceiver.ACTION);
         data.put("customdata", "custom data value");
         return data;
      }
      catch(JSONException x)
      {
         throw new RuntimeException("Something wrong with JSON", x);
      }
   }
   public void sendMessageAsIntent(View v)
   {
      JSONObject data = getJSONDataMessageForIntent();
      ParsePush push = new ParsePush();
      push.setChannel("ch1");
      push.setData(data);
      push.sendInBackground();
      reportTransient("Sent as data");
   }

notice how "action" is used instead of "alert". If you use both you will get both behaviors: your broadcast receiver will be invoked. You also get the alert as a notification.

Instead if you just use the action, the broadcast receive can then notify if needed or be silent if appropriate!

satya - 5/2/2013 1:55:09 PM

Here is the TestBroadcastReceiver


public class TestBroadcastReceiver 
extends BroadcastReceiver 
{
   public static final String ACTION="com.androidbook.parse.TestPushAction";
   public static final String PARSE_EXTRA_DATA_KEY="com.parse.Data";
   public static final String PARSE_JSON_ALERT_KEY="alert";
   public static final String PARSE_JSON_CHANNELS_KEY="com.parse.Channel";
      
   private static final String TAG = "TestBroadcastReceiver";
    
   @Override
   public void onReceive(Context context, Intent intent) 
   {
      try 
      {
         String action = intent.getAction();
         
         //"com.parse.Channel"
         String channel = 
            intent.getExtras()
               .getString(PARSE_JSON_CHANNELS_KEY);
         
         JSONObject json = 
            new JSONObject(
                  intent.getExtras()
                     .getString(PARSE_EXTRA_DATA_KEY));
    
         Log.d(TAG, "got action " + action + " on channel " + channel + " with:");
         Iterator itr = json.keys();
         while (itr.hasNext()) 
         {
            String key = (String) itr.next();
            Log.d(TAG, "..." + key + " => " + json.getString(key));
         }
         notify(context,intent,json);
      } 
      catch (JSONException e) 
      {
         Log.d(TAG, "JSONException: " + e.getMessage());
       }
   }
   private void notify(Context ctx, Intent i, JSONObject dataObject)
   throws JSONException
   {
         NotificationManager nm = (NotificationManager)        
            ctx.getSystemService(Context.NOTIFICATION_SERVICE);
         
         int icon = R.drawable.robot;
         String tickerText = 
            dataObject.getString("alert");
         long when = System.currentTimeMillis();         
         Notification n = new Notification(icon, tickerText, when);
         
         //Let the intent invoke the respond activity
         Intent intent = new Intent(ctx, RespondToPushActivity.class);
         //Load it with parse data
         intent.putExtra("com.parse.Data", 
               i.getExtras().getString("com.parse.Data"));
         
         PendingIntent pi = PendingIntent.getActivity(ctx, 0, intent, 0);

         n.setLatestEventInfo(ctx, "Parse Alert", tickerText, pi);
            
         nm.notify(1, n);         
   }
}//eof-class

satya - 5/2/2013 2:02:15 PM

There is a bug above

getting an alert string from the json object will throw an exception if the incoming message doesn't have it. So put enough checks for robust behavior!