6

Before labeling this as a duplicate:

I've read at least 15 similar threads and each and every one is either using the old Parse code (the now deprecated setDefaultPushCallback) or the problem was a result of calling Parse.initialize(...) in an activity and not in the Application class. But this is not applicable to my case. The official example (which I'm using) is evidently doing it right, so the code is already in the Application class.

I've downloaded the Push Starter example from Parse's official guides and tried it out on an emulator. I receive pushes only while the app is running. The moment's it's closed (removed from the "recent apps" list, not force killed), I no longer get pushes. Which makes the entire feature rather useless... I tried with and without GCM, the behavior is the same.

Any clues what could possible be wrong? All classes are the stock example ones, nothing overridden or added by me (except for the id/key and the ParsePush.subscribeInBackground call which I copied from the guide). Weirdly enough, the example code did not contain ParsePush.subscribeInBackground and the QuickStart does not mention it. It even gives a Test button that supposedly sends a push which I never receive, with or without subscribeInBackground. The only way I've been able to get a push so far was with subscribeInBackground and sending a push manually though the web console, and only so if the app is running. The web console also keeps telling there's 2 registered devices... which is untrue.

Manifest:

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

    <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="21"/>

    <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.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

    <!--
      IMPORTANT: Change "com.parse.starter.permission.C2D_MESSAGE" in the lines below
      to match your app's package name + ".permission.C2D_MESSAGE".
    -->
    <permission android:protectionLevel="signature"
        android:name="com.parse.starter.permission.C2D_MESSAGE" />
    <uses-permission android:name="com.parse.starter.permission.C2D_MESSAGE" />

    <application
        android:name=".ParseApplication"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:allowBackup="true">
        <activity
            android:name=".ParseStarterProjectActivity"
            android:label="@string/app_name" >
            <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>
        <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" />

                <!--
                  IMPORTANT: Change "com.parse.starter" to match your app's package name.
                -->
                <category android:name="com.parse.starter" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

ParseApplication:

package com.parse.starter;
...

public class ParseApplication extends Application {

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

        // Initialize Crash Reporting.
        ParseCrashReporting.enable(this);

        // Enable Local Datastore.
        Parse.enableLocalDatastore(this);

        ParseUser.enableAutomaticUser();

        // Add your initialization code here
        Parse.initialize(this, "***", "***");

        ParseACL defaultACL = new ParseACL();
        // Optionally enable public read access.
        // defaultACL.setPublicReadAccess(true);
        ParseACL.setDefaultACL(defaultACL, true);

        ParsePush.subscribeInBackground("", new SaveCallback() {
            @Override
            public void done(ParseException e) {
                if (e == null) {
                    Log.d("com.parse.push", "successfully subscribed to the broadcast channel.");
                } else {
                    Log.e("com.parse.push", "failed to subscribe for push", e);
                }
            }
        });
    }
}
kaqqao
  • 12,984
  • 10
  • 64
  • 118
  • Hi Kaqqao, getting push notifications via the "Parse way" will stop working whenever you kill your app from recents. This is because killing your app breaks the connection with the Parse backend servers and hence the servers cannot push anything anymore. Push notifications via GCM should work however, even if your app is killed (not forced stopped). This is because GCM works via Google Play Services, an app which is always running in the background and that can start your app when needed (and not force stopped). Your code also looks correct, so I don't really see the issue. – Jeroen Mols Feb 16 '15 at 06:51
  • I'm wondering if there is a package name conflict (because you use the same package as the example), that way there are multiple apps with the same package, but a different signature. Can you try change your package to something unique? `com.parse.kaqqao` – Jeroen Mols Feb 16 '15 at 06:55
  • @jmols OMG, it seems like your package name theory was correct! After I changed the name, I started receiving messages with the app closed. No clue why it worked with the app running, though... Anyway, would you please convert your two comments into an answer so that I can award you the bounty before it expires? – kaqqao Feb 16 '15 at 21:44
  • Great! good to hear! I've converted the posts into an answer. – Jeroen Mols Feb 17 '15 at 06:39

2 Answers2

1

Just to clarify why you are seeing this behaviour, Parse has two different ways for delivering push notifications:

  1. "Parse way": the Parse SDK has a component running in your app, which keeps a connection to the Parse backend servers. This will only work when your app is actually running, because killing it breaks the connection with the Parse backend.
  2. GCM "Google" push notifications: This works via Google Play Services, an app which is always running in the background and that can start your app when needed. This will always work, unless you force stop the application.

In your case you are there is a package name conflict: com.parse.starter is the package name that was actually included in the example. This causes GCM not to work, because it already knows the package under a different signature. Changing your package name to something unique like com.parse.kaqqao should solve the trick.

Jeroen Mols
  • 3,436
  • 17
  • 24
1

There are a few reasons for this:

  1. There are two BroadcastReceiver viz the "com.parse.ParsePushBroadcastReceiver" and "com.parse.GcmBroadcastReceiver". I believe that the first receiver is getting prioritized over the GCMBroadcastReceiver and thus the behavior is not affected by removing or keeping this receiver. It could also be due to action "com.parse.push.intent.RECEIVE", which might be handling the push messages RECEIVE action. If both the receiver perform the same task of parsing the Push message (starting the same service in background), then include the intent-filter inside one receiver and let it handle all kinds of push messages. Since GCMBroadcastReceiver holds the C2DM permission.

  2. Try changing the order of the two broadcast receiver tags in the manifest. (Keep GCMBroadcastReceiver before the ParsePushBroadcastReceiver)

  3. It could be due to android:exported="false", maybe it prevents the Receiver from listening to the push messages sent by server. Try changing to true.

Roadblock
  • 2,041
  • 2
  • 24
  • 38