Friday, October 23, 2015

Push notifications for Android using Parse.com

I'm writing this mainly because I spent a few hours last night trying to make this work, and the guides found at Parse.com were incomplete so things didn't work as smooth as they should've.

What this tutorial will accomplish

The final product will be a simple push notification sent from the web using Parse.com as the platform, which will make the phone get a notification of the message arrived. When the user touches the notification, the app will open.
We will do this by setting up the Parse push SDK in the application.



If you rather watch a step-by-step video of this tutorial, click on this link.

What you need for this tutorial


An account on Parse.com. A free account will work for this.
A Parse project. Any project in Parse.com will do (if this gets confusing, send me an email and I'll add these steps)
Android Studio
An android device or emulator

Get to work!

This tutorial will be done using the Parse.com guide of using an existing android project instead of a brand new project. This is because this way the tutorial will work both situations.

1. Get Parse project information
Once you create the project on Parse you should see something like this:


First of all, we'll be using Gradle to install the library so you don't need to download the .zip file. You can ignore this step.
However, since we'll be using Gradle to build our application we do care about the dependencies listed here. We will add this in the android project in a minute.

The portion below is also important since it has your Parse Application Id and Client Key.
You should get your own unique Application Id and Client Key for this Parse project, as shown here (I hid mine):

For now, just leave the web page of your Parse project open with this information. We will use it in the Android application.

2. Create an Android project, or open an existing project
If you're creating a new project, any blank project will do. I would suggest to support Android OS 4.1 and higher, but its up to you.

For this tutorial I created a new project named "Test_ParsePush", and the package name for this project is "com.eduardoflores.test_parsepush".
It doesn't matter what yours is, but we will need it in the manifest.

3. Modify your build.gradle (Module:app) file
Right now your project structure in Android Studio should look something like this:

Open the build.gradle file from your module (if you only have 1 module it'll be named "app").
At the bottom of this file, under "dependencies" we will be adding the dependencies given to you by Parse to get the Parse SDK:
    compile 'com.parse.bolts:bolts-android:1.+'
    compile 'com.parse:parse-android:1.+'
Your dependencies should look like this (you may have more or less default dependencies):
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.0.1'
    compile 'com.android.support:design:23.0.1'
    compile 'com.parse.bolts:bolts-android:1.+'
    compile 'com.parse:parse-android:1.+'
}

Now add the maven repository where you will be getting the Parse SDK tools. (note: this is not mentioned in the Parse tutorials):
buildscript {
    repositories {
        mavenCentral()
        maven { url 'https://maven.parse.com/repo' }
    }
    dependencies {
        classpath 'com.parse.tools:gradle:1.+'
    }
}
And finally add the parse plugin at the top of your build.gradle file, like this:
apply plugin: 'com.parse'
So now your entire build.gradle file should look something like this:
apply plugin: 'com.android.application'
apply plugin: 'com.parse'

buildscript {
    repositories {
        mavenCentral()
        maven { url 'https://maven.parse.com/repo' }
    }
    dependencies {
        classpath 'com.parse.tools:gradle:1.+'
    }
}

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.1"

    defaultConfig {
        applicationId "eduardoflores.com.test_parsepush"
        minSdkVersion 16
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.0.1'
    compile 'com.android.support:design:23.0.1'
    compile 'com.parse.bolts:bolts-android:1.+'
    compile 'com.parse:parse-android:1.+'
}
 
You're done with the build.gradle file.

4. Modify your manifest file
Open the manifest file of your Android application.
- In your manifest file, before your <application tag, you need add 2 things.
The first one, goes just like this:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
The second thing requires you to change the package name to the package name of your Android application:
<permission android:protectionLevel="signature"
                android:name="YOUR_PACKAGE_NAME.permission.C2D_MESSAGE" />
<uses-permission android:name="YOUR_PACKAGE_NAME.permission.C2D_MESSAGE" />
In here, you need to make sure you're changing the text "YOUR_PACKAGE_NAME" with the name of your application's package name. In my case, as mentioned on step 2, the package name is "com.eduardoflores.test_parsepush"

- Now in the same manifest file, between the last </activity> and </application> tags, you need to enter this, for GCM to receive your message:
<service android:name="com.parse.PushService" />
<receiver android:name="com.parse.ParsePushBroadcastReceiver"
          android:exported="false">
    <intent-filter>
        <action android:name="com.parse.push.intent.RECEIVE" />
        <action android:name="com.parse.push.intent.DELETE" />
        <action android:name="com.parse.push.intent.OPEN" />
    </intent-filter>
</receiver>
<receiver android:name="com.parse.GcmBroadcastReceiver"
          android:permission="com.google.android.c2dm.permission.SEND">
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
        <category android:name="YOUR_PACKAGE_NAME" />
    </intent-filter>
</receiver>
Notice how you must also enter your application's package name in the last category's name.
So with that, and the package names replaced, your entire manifest file should look something like this:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="eduardoflores.com.test_parsepush" >

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

    <application
        android:name=".StarterClass"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar" >
            <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.ParsePushBroadcastReceiver"
                  android:exported="false">
            <intent-filter>
                <action android:name="com.parse.push.intent.RECEIVE" />
                <action android:name="com.parse.push.intent.DELETE" />
                <action android:name="com.parse.push.intent.OPEN" />
            </intent-filter>
        </receiver>
        <receiver android:name="com.parse.GcmBroadcastReceiver"
                  android:permission="com.google.android.c2dm.permission.SEND">
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
                <category android:name="eduardoflores.com.test_parsepush" />
            </intent-filter>
        </receiver>
    </application>
</manifest>
You're done with the manifest file (the name=.StarterClass will be explained later).

5. Write the Android application's java code
In your initial activity you must initialize the Parse SDK with the application id and the client key, and then you tell Parse to save that in a background thread.

This is very important: YOUR APP WILL CRASH IF YOU INITIALIZE PARSE MORE THAN ONCE IN YOUR APPLICATION.

What does this mean? If you initialize Parse on the onCreate() method of your MainActivity, the application will run and you will be able to receive notifications, but only if the app is running.
Once a notification arrives the app will start, the onCreate() method will get called again and Parse will be initialized again and the app will crash with a beautiful "Unable to create service com.parse.PushService: java.lang.NullPointerException"
To avoid this, we will create a simple starter activity that will just initialize the Parse library.


Create a starter class

Create a new java file called "StarterClass.java" and in this class extend Activity.

In the StarterClass class, add ann onCreate() method, and after the super() code, add this:
Parse.initialize(this, APPLICATION_ID, CLIENT_KEY);
ParseInstallation.getCurrentInstallation().saveInBackground();

So with that, your entire StarterClass class (StarterClass.java file) will look like this:
package eduardoflores.com.test_parsepush;

import com.parse.Parse;
import com.parse.ParseInstallation;

import android.app.Application;

/**
 * @author Eduardo Flores
 */
public class StarterClass extends Application {
    @Override
    public void onCreate() {
        super.onCreate();

        // Setup Parse
        Parse.initialize(this, "application_id_from_parse", "client_key_from_parse");
        ParseInstallation.getCurrentInstallation().saveInBackground();
    }
}
This StarterClass we just created is what we defined in the Manifest file under name=".StarterClass"for the application. This way this class only gets called once, and therefore, Parse only gets initialized once.

And that folks would be all you need to setup your app for notifications using Parse.
Now let's run the app and send a message to see how this puppy works!


 

And finally, you can download the source code of this project from this link.

Eduardo Flores.

8 comments:

  1. If I'm using two SDK and one take the name in application tag in manifest file how i can deal with SDK of notification in this case ?

    ReplyDelete
  2. Are you using 2 SDKs with the same name? I guess I don't understand your question.

    ReplyDelete
  3. No not like that now I'm using SDK for VOIP service and this SDK take the name inside the application tag in Manifest file , and the SDK of Notification need to put as application also inside manifest and we can't but more than one application tag in manifest , how I can use these SDKs together or by another way like this :

    public class MainActivity extends ListActivity --> this class use VOIP SDK

    public class StarterClass extends Application --> this class use Parse SDK

    and in manifest inside Application tag the name take something like this to run the SDK of VOIP
    android:name="org.abtollc.sdk.AbtoApplication"

    and when I applied these steps of parse documentation without make Parse sdk as application I got this error " Unable to create service com.parse.PushService: java.lang.NullPointerException"
    and when I applied your tutorial on test app it's working very good but without SDK of VOIP

    Do you understand me ?

    ReplyDelete
  4. I solved that ,thank you so much any way for your great tutorial :)

    ReplyDelete
    Replies
    1. hi alaa khaled
      i have two class extend to Application...how can add them to mainfest...
      please contact me at yaqoub44@gmail.com
      thanks alooot

      Delete
  5. Thanks man, i am suffering from last 3 days but i can't find any proper solution, but your code and explanation both are good. Keep it up.

    ReplyDelete
    Replies
    1. Glad to know somebody looking for it found it, and that it helped you!

      Delete
  6. OHHH ,Thanks for the wonderful Explanation I was missing apply parse plugin last 3 months and my app s crashing as per the instruction u mentioned here.But after too much hunt I resolved it.Wonderful My Friend..Keep Going on

    ReplyDelete