问题
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
回答1:
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!!
来源:https://stackoverflow.com/questions/32948741/unable-to-receive-messages-from-gcm