0

am developing an android app that uses GCM to send and receive messages. am able ro register my app with GCM and receive GCM Registration Token. but am not being notified upon receiving new messages.(seems like nothing is hapenning in my MyGcmListenerService class.)

i can only see my new messages upon reloading my chat user Interface(that is clicking the back button and then clicking again my chat button. nothing is taking place in my MyGcmListenerService.java !!!!)

below are my classes and AndroidManifest.xml

AndroidManifest.xml

 <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

<permission android:name="com.me.myapp.permission.C2D_MESSAGE"
    android:protectionLevel="signature" />
<uses-permission android:name="com.me.myapp.permission.C2D_MESSAGE" />
<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme"
    android:name="android.support.multidex.MultiDexApplication"
    >

    <receiver
        android:name="com.google.android.gms.gcm.GcmReceiver"
        android:exported="true"
        android:permission="com.google.android.c2dm.permission.SEND" >
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <category android:name="com.me.myapp" />
        </intent-filter>
    </receiver>
    <service
        android:name="com.me.myapp.MyGcmListenerService"
        android:exported="false" >
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        </intent-filter>
    </service>
    <service
        android:name="com.me.myapp.MyInstanceIDListenerService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.android.gms.iid.InstanceID"/>
        </intent-filter>
    </service>

MyGcmListenerService.java

public class MyGcmListenerService extends GcmListenerService {

private static final String TAG = "MyGcmListenerService";

public static final String AC_GCM_MESSAGE_ACTION = "com.me.myapp.MyGcmListenerService.OrderedBroadcast";
public static final String INTERCEPTED = "intercepted";



/**
 * Called when message is received.
 *
 * @param from SenderID of the sender.
 * @param data Data bundle containing message data as key/value pairs.
 *             For Set of keys use data.keySet().
 */
// [START receive_message]
@Override
public void onMessageReceived(String from, Bundle data) {
    d("on receive called");
    final String message = data.getString("message");
    final String senderName = data.getString("sender");
    final String senderId = data.getString("senderId");
    final String dateCreated = data.getString("dateCreated");
    Log.d(TAG, "From: " + from);
    Log.d(TAG, "Message: " + message);

    d("Message received from "+ from);

    Intent intent = new Intent(AC_GCM_MESSAGE_ACTION);
    intent.putExtra("message", message);
    intent.putExtra("senderName", senderName);
    intent.putExtra("senderId", senderId);
    intent.putExtra("dateCreated", dateCreated);
    //dateCreated
    intent.putExtra(INTERCEPTED, false);

    sendOrderedBroadcast(intent, null, new MyBroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Bundle results = getResultExtras(true);
            d("entered onreceive");
            boolean intercepted = results.getBoolean(INTERCEPTED);
            if (!intercepted) {
                sendNotification(message, senderName, senderId);
            }
        }
    }, null, Activity.RESULT_OK, null, null);
}
// [END receive_message]

/**
 * Create and show a simple notification containing the received GCM message.
 *
 * @param message GCM message received.
 */
private void sendNotification(String message, String senderName, String senderId) {
    Intent intent = new Intent(this, ChatActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    intent.putExtra("senderId", senderId);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
            PendingIntent.FLAG_ONE_SHOT);

    Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
            .setSmallIcon(R.drawable.ic_stat_name)
            .setContentTitle(senderName)
            .setContentText(message)
            .setAutoCancel(true)
            .setSound(defaultSoundUri)
            .setContentIntent(pendingIntent);

    NotificationManager notificationManager =
            (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

    notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}

private void d(String s){
    Log.d("MyGcmListenerService", s);
}

}

My RegistrationIntentService.java

 private static final String TAG = "RegIntentService";
public RegistrationIntentService() {
    super(TAG);
}

@Override
protected void onHandleIntent(Intent intent) {
    d("onHandleIntent");

    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);

    try {
        // In the (unlikely) event that multiple refresh operations occur simultaneously,
        // ensure that they are processed sequentially.
        synchronized (TAG) {
            // [START register_for_gcm]
            // Initially this call goes out to the network to retrieve the token, subsequent calls
            // are local.
            // [START get_token]
            InstanceID instanceID = InstanceID.getInstance(this);
            String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
                    GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
            // [END get_token]
            d("GCM Registration Token: " + token);

            sendRegistrationToServer(token);

            // You should store a boolean that indicates whether the generated token has been
            // sent to your server. If the boolean is false, send the token to your server,
            // otherwise your server should have already received the token.
            sharedPreferences.edit().putBoolean(AlphaCashPreferences.SENT_TOKEN_TO_SERVER, true).apply();
            // [END register_for_gcm]
            d("registration succeeded");
        }
    } catch (Exception e) {
        d("Failed to complete token refresh", e);
        // If an exception happens while fetching the new token or updating our registration data
        // on a third-party server, this ensures that we'll attempt the update at a later time.
        sharedPreferences.edit().putBoolean(AlphaCashPreferences.SENT_TOKEN_TO_SERVER, false).apply();
    }
    // Notify UI that registration has completed, so the progress indicator can be hidden.
    Intent registrationComplete = new Intent(AlphaCashPreferences.REGISTRATION_COMPLETE);
    d("regestration intent broadcasted");
    LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete);
}

/**
 * Persist registration to third-party servers.
 *
 * Modify this method to associate the user's GCM registration token with any server-side account
 * maintained by your application.
 *
 * @param token The new token.
 */
private void sendRegistrationToServer(String token) {
    d("Send registration token to server");
    // Add custom implementation, as needed.
    Context c = getApplication();
    SaveRegistrationIdRequest req = new SaveRegistrationIdRequest();
    req.setCredentials(Installation.createCredentials(c));
    req.setRegId(token);
    Installation installation = Installation.getInstance(c);
    SendGcmRegistrationIdTask task = new SendGcmRegistrationIdTask(new ApiTask.ResultListener() {
        @Override
        public void successHook(Object o) {
            //TODO After registration of the gcm id
        }
    }, installation, req);

    task.execute();
    d("successflly sent");
}

private void d(String s){
    Log.d("RegIntentService", s);
}

private void d(String s, Exception e){
    Log.d("RegIntentService", s, e);
}

}

QUESTION

How can i solve my problem and be able to receive messages instantly without going back and forth ?

AFTER DEBUGGING MY APPLICATION, THIS ARE THE WARNINGS AM GETTING FROM THE LOGCAT

com.me.myapp W/dalvikvm﹕ VFY: unable to resolve virtual method 247: Landroid/app/
Notification$Builder;.setLocalOnly (Z)Landroid/app/Notification$Builder;
10-05 16:18:11.594  32178-32178/com.me.myapp W/dalvikvm﹕ VFY: unable to resolve instance field 18
10-05 16:18:11.603  32178-32178/com.me.myapp W/dalvikvm﹕ VFY: unable to resolve virtual method 1507: Landroid/os/UserManager;.getApplicationRestrictions (Ljava/lang/String;)Landroid/os/Bundle;
10-05 16:18:11.605  32178-32178/com.me.myapp E/dalvikvm﹕ Could not find class 'android.app.AppOpsManager', referenced from method com.google.android.gms.common.GooglePlayServicesUtil.zzb
Edijae Crusar
  • 3,473
  • 3
  • 37
  • 74
  • So you mean you are getting messages? Just that they are not displayed on time or without refreshing the page? – Skynet Oct 05 '15 at 12:39
  • @Skynet Exactly men. my notification mechanism is not been triggered! – Edijae Crusar Oct 05 '15 at 12:42
  • @Skynet Where do you think am going wrong? i have struggled with this for almost 2 weeks! – Edijae Crusar Oct 05 '15 at 12:53
  • Your code is lengthy, it would take longer to comprehend. What I suggest in the meantime is to break the problem into small units and test. Debugging is your best friend here. – Skynet Oct 05 '15 at 12:54
  • @Skynet i have debugged my app. and i have edited my question to include debug results at the end. do you think they have anything to do my problem? please have a look at them(very few) – Edijae Crusar Oct 05 '15 at 13:29
  • To begin with, though this may not be the fix to your issue, your manifest has a few differences with the [demo](https://github.com/googlesamples/google-services/blob/master/android/gcm/app/src/main/AndroidManifest.xml) one. See if that permissions tag is even necessary. You may even want to clone the demo to test if that works fine for you. – Koh Oct 05 '15 at 18:23
  • Pls take a look at [my answer here](http://stackoverflow.com/questions/32932935/sending-push-notification-using-google-gcm/32940082#32940082) in which you will find 2 working links to my sample code, hope this helps – BNK Oct 05 '15 at 22:03
  • @BNK never worked men, i dont know where am going wrong – Edijae Crusar Oct 07 '15 at 11:39
  • What is the response message that your server-side app received after sending message to clients? – BNK Oct 07 '15 at 13:41
  • @BNK what do you mean by response message? because when i look at logs from my app server, i can't see any error. or is it something i can see at my google developer console? – Edijae Crusar Oct 07 '15 at 13:49
  • When server app sends msg to clients, it will got the reponse msg from Google server saying if that msg sent successfully or not. – BNK Oct 07 '15 at 13:55
  • For example { "failure": 0, "results": [ { "message_id": "0:144...." } ] , "sucess":1, "multicast_id": 3763...., "canonical_ids": 0} – BNK Oct 07 '15 at 13:58
  • @BNK there is something i have realized, I AM NOT SENDING REGISTRATION TOKEN TO MY APP SERVER! do you think that could be the problem? how can i send reg token gotten from GCM server to my app server ? do you know a working example? – Edijae Crusar Oct 07 '15 at 14:10
  • There are both working sample code for basic server app and client app in my above link, with step-by-step, you should read again. – BNK Oct 07 '15 at 14:32

1 Answers1

0

I finally solved my problem which was occurring because i wasn't sending GCM registration ID after getting it from GCM server to my app server.

But after sending it to my app server, my client app was able to receive notifications upon receiving a new message.

any one who is experiencing same problem. that is Your app isn't receiving notifications or messages(or both)from GCM please make sure you have (programmatically) sent GCM registration token to your app server

Something like this

public class RegistrationIntentService extends IntentService {
 public static final String GCM_SENDER_ID = "Your ProjectID";//your project id
 private static final String TAG = "RegIntentService";
 public static final String SENT_TOKEN_TO_SERVER = "sentTokenToServer";
 public static final String REGISTRATION_COMPLETE = "registrationComplete";
 public static final long GCM_TIME_TO_LIVE = 60L * 60L * 24L * 7L * 4L; // 4 Weeks

private static final String TAG = "RegIntentService";

public RegistrationIntentService() {
    super(TAG);

}
String regId;
@Override
protected void onHandleIntent(Intent intent) {
    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);

    try {
        // [START register_for_gcm]
        // Initially this call goes out to the network to retrieve the token, subsequent calls
        // are local.
        // [START get_token]
        InstanceID instanceID = InstanceID.getInstance(this);
        String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
                GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
        regId = token;
        // [END get_token]
        Log.i(TAG, "GCM Registration Token: " + token);

        // TODO: Implement this method to send any registration to your app's servers.
        sendRegistrationToServer(token);


        // You should store a boolean that indicates whether the generated token has been
        // sent to your server. If the boolean is false, send the token to your server,
        // otherwise your server should have already received the token.
        sharedPreferences.edit().putBoolean(SENT_TOKEN_TO_SERVER, true).apply();
        // [END register_for_gcm]
    } catch (Exception e) {
        Log.d(TAG, "Failed to complete token refresh", e);
        // If an exception happens while fetching the new token or updating our registration data
        // on a third-party server, this ensures that we'll attempt the update at a later time.
        sharedPreferences.edit().putBoolean(SENT_TOKEN_TO_SERVER, false).apply();
    }
    // Notify UI that registration has completed, so the progress indicator can be hidden.
    Intent registrationComplete = new Intent(REGISTRATION_COMPLETE);
    LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete);
}


/**
 * Sends the registration ID to the 3rd party server via an upstream 
 * GCM message. Ideally this would be done via HTTP to guarantee success or failure 
 * immediately, but it would require an HTTP endpoint.
 */

private void sendRegistrationToServer(String token) {

String name = token
new AsyncTask<String, Void, String>()
{
    @Override
    protected String doInBackground(String... params)
    {
    String msg = "";
    try
    {
        Bundle data = new Bundle();
        data.putString("name", params[0]);
        data.putString("action", "com.antoinecampbell.gcmdemo.REGISTER");
        String id = Integer.toString(msgId.incrementAndGet());
        gcm.send(GCM_SENDER_ID + "@gcm.googleapis.com", id,GCM_TIME_TO_LIVE, data);
        msg = "Sent registration";
    }
    catch (IOException ex)
    {
        msg = "Error :" + ex.getMessage();
    }
    return msg;
    }

    @Override
    protected void onPostExecute(String msg)
    {
    Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
    }
 }.execute(name);
 }
}

Give it a try!!

Edijae Crusar
  • 3,473
  • 3
  • 37
  • 74
  • Please let me know what is msgId which is at String id = Integer.toString(msgId.incrementAndGet()); then in below line what is gcm and GCM_TIME_TO_LIVE? at gcm.setnd(GCM_SENDER_ID + "@gcm.googleapis.com", id, GCM_TIME_TO_LIVE, data); and where we have to give our third party server url ? Please let me know.... – shripal Dec 21 '15 at 09:09
  • i am not getting error but not getting any notification from server...just i want to make sure is my application registering at the server side or not? OR i have to call any webservices to send token to the server side? – shripal Dec 21 '15 at 12:27
  • @shripal i have some good tutorials that i use and think will be of help to you [This one](http://javapapers.com/android/google-cloud-messaging-gcm-for-android-and-push-notifications/) and [this one](http://www.cs.dartmouth.edu/~campbell/cs65/lecture24/lecture24.html) – Edijae Crusar Dec 21 '15 at 14:18
  • Thanks gikarasojo... in new GCM is it required to call server (request through webservice). i am not getting how client app and server will be connected? please answer me this que....you have share link that is nice but i think it is for old GCM....there is new GCM introduce by Google from 20th Oct 2015...plz refer this https://developers.google.com/android/c2dm/?csw=1 – shripal Dec 21 '15 at 14:20
  • @shripal want to know how server and client app communicate? here's how. first, you register your app with google gcm servers. when you register, google gives you a specific id(numbers + strings) **which is an id that identifies your app server at google** after getting that id, **there is a programmatic process(which is very easy by the way) that you follow to register any copy of your app installed in any android device** to gcm connection servers to get a specific gcm id **which will be used to identify the copy of your app installed in that device**. – Edijae Crusar Dec 22 '15 at 07:54
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/98652/discussion-between-gikarasojo-kinene-and-shripal). – Edijae Crusar Dec 22 '15 at 07:56