When implementing xmpp over the Cloud Connection Server of Google i receive messages that will start an WakefulBroadcastReceiver.
Manifest.xml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.USE_CREDENTIALS"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<permission
android:name="com.tag.xmppandroid.permission.C2D_MESSAGE"
android:protectionLevel="signature"/>
<uses-permission android:name="com.tag.xmppandroid.permission.C2D_MESSAGE"/>
<receiver
android:name=".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="com.tag.xmppandroid"/>
</intent-filter>
</receiver>
<service android:name=".GcmIntentService"></service>
WakefulBroadcastReceiver
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(), GcmIntentService.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
Now this WakefulBroadcastReceiver will start an Intent service called GcmIntentService.class. The purpose of this intentService is receiving the message and directly send a message back as xmpp to the server that send the message. Actually this works, i send the message back with gcm.send(...) and the server receives the messages. But only when im debugging.
The server won't receive the message when the application is not in debugging mode. When the application is in debug mode it will send the message to the xmpp server. It looks like the thread shuts down to early and the message could not be send back to the server. But when im debugging i prevent the service from sleeping and it has time to send the message or anything. Does anyone know why this happens?
Code of my Intentservice:
#Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
final GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
// The getMessageType() intent parameter must be the intent you received
// in your BroadcastReceiver.
String messageType = gcm.getMessageType(intent);
String message_id = null;
String time_to_live = null;
if (!extras.isEmpty()) // has effect of unparcelling Bundle
{
if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
sendNotification("Send error: " + extras.toString(), null);
} else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
// Get values from intent send over xmpp
message_id = ((intent.getExtras() == null) ? "Empty Bundle" : intent.getExtras().getString("message_id"));
String message = ((intent.getExtras() == null) ? "Empty Bundle" : intent.getExtras().getString("message"));
time_to_live = ((intent.getExtras() == null) ? "Empty Bundle" : intent.getExtras().getString("time_to_live"));
Bundle data = new Bundle();
data.putString("hello", "world");
data.putString("delivered", "true");
try {
gcm.send(Constants.GCM_SENDER_ID + "#gcm.googleapis.com", message_id, Constants.GCM_TIME_TO_LIVE, data);
} catch (IOException e) {
e.printStackTrace();
}
// Send data to the view
sendToView(message_id, message, time_to_live);
// Show notification
sendNotification("Received: " + message, extras);
// Show toast on main thread
Handler mHandler = new Handler(getMainLooper());
mHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), Constants.GCM_SENDER_ID, Toast.LENGTH_SHORT).show();
}
});
}
} else {
sendToView("empty_bundle", null, null);
}
// Release the wake lock provided by the WakefulBroadcastReceiver.
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
I hope someone can explain me why this happens, or what i do wrong since i really want to understand why this happens.
Related
Currently I'm creating an application that supports chatting between users using GCM, everything is working fine except that when i click on the message received via a notification, the chat activity opens with null data.
I've registered the GCM broadcast receiver in the manifest as follows:
<receiver
android:name=".GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<!-- Receives the registration id. -->
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="xxx.xxx.xxx" />
</intent-filter>
</receiver>
And on the chat activity, I have something like this:
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle b = intent.getExtras();
String message = b.getString("message");
Log.i(TAG, " Received in Activity " + message + ", NAME = "
+ chattingToName + ", dev ID = " + chattingToDeviceID);
// this demo this is the same device
ChatPeople curChatObj = addToChat(chattingToName, message,
"Received");
addToDB(curChatObj); // adding to db
populateChatMessages();
}
};
I guess this part is not called since on the chat history is not updated with the received message.
Any idea guys?
Thanks in advance.
This is my GcmBroadcastReceiver
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),
GcmIntentService.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
Bundle extras = intent.getExtras();
Intent i = new Intent("CHAT_MESSAGE_RECEIVED");
i.putExtra("message", extras.getString("message"));
context.sendBroadcast(i);
}
}
It looks that you are not handling the User Notification received from the chat app in the correct manner. Please take a look at this official Google Documentation that deals with the User Notification on GCM.
Also please take a look at this tutorial that has code for the chat application.
Hope that Helps!!
We have implemented GCM to show notifications in android application but only some messages not receiving in devices sent by server to google? Server is sending messages without collapse_key so every message should reach in device without collapsed. Please suggest me to proceed further.
Thanks
Receiver code is below:
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),
GcmIntentService.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
service code is below:
public class GcmIntentService extends IntentService {
NotificationCompat.Builder builder;
public GcmIntentService() {
super("GcmIntentService");
}
public static final String TAG = "GCM Demo";
#Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
// The getMessageType() intent parameter must be the intent you received
// in your BroadcastReceiver.
String messageType = gcm.getMessageType(intent);
if (!extras.isEmpty()) { // has effect of unparcelling Bundle
/*
* Filter messages based on message type. Since it is likely that GCM will be
* extended in the future with new message types, just ignore any message types you're
* not interested in, or that you don't recognize.
*/
if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
//sendNotification("Send error: " + extras.toString());
} else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) {
//sendNotification("Deleted messages on server: " + extras.toString());
// If it's a regular GCM message, do some work.
} else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
// This loop represents the service doing some work.
for (int i = 0; i < 5; i++) {
Log.i(TAG, "Working... " + (i + 1)
+ "/5 # " + SystemClock.elapsedRealtime());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
}
generateNotification(this, name, id, message);
}
}
// Release the wake lock provided by the WakefulBroadcastReceiver.
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
}
Manifest file is below
<permission
android:name="MY_PACKAGE_NAME.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="MY_PACKAGE_NAME.permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<receiver android:name=".GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="MY_PACKAGE_NAME" />
</intent-filter>
</receiver>
<service android:name=".GcmIntentService" />
You need to create a Google account in that device (Settings -> Accounts -> Google). So please check whether it's logged with Google or not :)
I have created a GCM Intent service and the device is getting registered successfully and server successfully send the message. but device don't get any notifications.
Below the log i see,
10-29 18:26:09.599: V/GCMBroadcastReceiver(30775): onReceive: com.google.android.c2dm.intent.RECEIVE
10-29 18:26:09.599: V/GCMBroadcastReceiver(30775): GCM IntentService class: com.eye.hor.GCMIntentService
10-29 18:26:09.599: V/GCMBaseIntentService(30775): Acquiring wakelock
Below is the code for GCMBroadcastReceiver,
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i(context.getPackageName(), intent.getExtras().toString());
Log.d("brdR", "askd");
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(), GcmIntentService.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
Below is the code for GCMIntentService,
public class GcmIntentService extends IntentService {
public static final int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
public GcmIntentService() {
super("GcmIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
// The getMessageType() intent parameter must be the intent you received
// in your BroadcastReceiver.
String messageType = gcm.getMessageType(intent);
if (!extras.isEmpty()) { // has effect of unparcelling Bundle
/*
* Filter messages based on message type. Since it is likely that
* GCM will be extended in the future with new message types, just
* ignore any message types you're not interested in, or that you
* don't recognize.
*/
if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
// sendNotification("Send error: " + extras.toString());
} else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) {
// sendNotification("Deleted messages on server: " +
// extras.toString());
// If it's a regular GCM message, do some work.
} else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
// This loop represents the service doing some work.
// for (int i = 0; i < 5; i++) {
// Log.d("", "Working... " + (i + 1) + "/5 # " +
// SystemClock.elapsedRealtime());
// try {
// Thread.sleep(5000);
// } catch (InterruptedException e) {
// }
// }
Log.d("true", "Completed work # " + SystemClock.elapsedRealtime());
// Post notification of received message.
sendNotification(extras.getString("msg"), extras.getString("title"), extras.getString("id"));
Log.d("true", "Received: " + extras.toString());
}
}
// Release the wake lock provided by the WakefulBroadcastReceiver.
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
// Put the message into a notification and post it.
// This is just one simple example of what you might choose to do with
// a GCM message.
private void sendNotification(String msg, String title, String id) {
mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
int notification_id = Integer.parseInt(id);
// PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new
// Intent(this, CommonUtils.class), 0);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this).setSmallIcon(R.drawable.icon).setContentTitle(title)
.setStyle(new NotificationCompat.BigTextStyle().bigText(msg)).setContentText(msg);
// mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(notification_id, mBuilder.build());
}
}
This is manifest,
<!-- GCM requires a Google account. -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<!-- Keeps the processor from sleeping when a message is received. -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- Creates a custom permission so only this app can receive its messages. -->
<permission
android:name="com.eye.hor.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.eye.hor.permission.C2D_MESSAGE" />
<!-- This app has permission to register and receive data message. -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<!-- Permission to vibrate -->
<uses-permission android:name="android.permission.VIBRATE" />
Receiver Code in Manifest,
<receiver
android:name="com.google.android.gcm.GCMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<!-- Receives the actual messages. -->
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<!-- Receives the registration id. -->
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.eye.hor.service" />
</intent-filter>
</receiver>
<service android:name="com.eye.hor.service.GCMIntentService" />
My main package name is com.eye.hor but i placed GCMIntentService and GCMBroadcastReceiver java files in the com.eye.hor.service package. i already put log in these two classes but they not reach.
please help
Looks like you already know you have a problem with the package names :
The following looks for your service class in the wrong package :
ComponentName comp =
new ComponentName(context.getPackageName(), // this is the main package of
// your app - com.eye.hor
GcmIntentService.class.getName());
Change it to :
ComponentName comp =
new ComponentName(GcmIntentService.class.getPackage().getName(),
GcmIntentService.class.getName());
You should also change the category in your manifest to the main package :
<category android:name="com.eye.hor.service" />
to
<category android:name="com.eye.hor" />
<category android:name="com.eye.hor.service" />
This is not supposed to be the package your broadcastreceiver is in, this is the package defined in the google developers console.
I'm willing to bet in your google developers console you defined the package has com.eye.hor, in which case you would have to change this line to:
<category android:name="com.eye.hor" />
What is device on which you developed your app? On different devices there are exotic settings influence on background working, check such setting in your device ("autostart", "push notification" and other, they can called different on some devices like Xiamo, Huawei and other).
Are you sure that your push server uses correct "sender id" and "api key" parameters, which you can check in developer console?
Check that Google Play services installed correct.
I keep getting this message in LogCat whenever I try to send a message from the demo GoogleAppEngine page that's built into Android Studio.
:GCM message com.objectivetruth.uoitlibrarybooking >0:1408853167972751%99d31532f9fd7ecd
:broadcast intent callback: result=CANCELLED forIntent { act=com.google.android.c2dm.intent.RECEIVE pkg=com.objectivetruth.uoitlibrarybooking (has extras) }
:Unregister application com.objectivetruth.uoitlibrarybooking for user 0
:Implicit intents with startService are not safe: Intent { act=com.google.android.c2dm.intent.UNREGISTER (has extras) } android.content.ContextWrapper.startService:494 ftg.a:1607 ftg.a:361
I'm about to rip my hair out after following this guide from google twice from scratch to make sure I followed it perfectly and I keep getting the same errors on my device
What's crazy is that its growing, If i send another message, there will be a cascade of calls from, what I assume is, all the previous messages that haven't been dealt with as yet. I tried a local GAE instance then I uploaded it to the cloud and still same issue. The registration works fine AFAIK.
I have a toast that tells me the resulting registration code which I assume means its success.
Also, the local server shows me every time a new registration occurs so I think that's fine as well
Here's my app Manifest's relevant parts which I've quadruple checked:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<permission
android:name="com.objectivetruth.uoitlibrarybooking.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.objectivetruth.uoitlibrarybooking.permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission
android:name="com.google.android.c2dm.permission.RECEIVE" />
<receiver
android:name=".GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.objectivetruth.uoitlibrarybooking" />
</intent-filter>
</receiver>
<service android:name=".GcmIntentService" />
and the GcmBroadcastReceiver
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Timber.i("Please please call me!");
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),
GcmIntentService.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
Here's the GcmIntentService
public class GcmIntentService extends IntentService {
public GcmIntentService() {
super("GcmIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
// The getMessageType() intent parameter must be the intent you received
// in your BroadcastReceiver.
String messageType = gcm.getMessageType(intent);
if (extras != null && !extras.isEmpty()) { // has effect of unparcelling Bundle
// Since we're not using two way messaging, this is all we really to check for
if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
Timber.i(extras.toString());
showToast(extras.getString("message"));
}
}
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
protected void showToast(final String message) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
}
});
}
}
The AsyncGcmRegistration is copy/pasted from the guide
Really not sure what else might be wrong..
OMG, if anyone stumbles upon this in the future and is tearing their hair out like I was, the reason you get result=canceled is because there's a legitamate issue with where the intent is going.
DO NOT IGNORE IT.
In my case I had the receive declarations outside my tags so it was not recognizing the pkg correctly.
Do not ignore the manifest, if you have issues with receiving very high chance its because of it.
UPDATE: I fixed the problems in the code below so this makes a nice basic working example of how to use GCM
So, I'm trying to implement Android GCM into my app. Here are the relevant parts I've added to the manifest:
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="20" />
<permission
android:name=".permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name=".permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
...
<receiver
android:name="com.google.android.gcm.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="com.badbob.app.gmctestapp" />
</intent-filter>
</receiver>
<service android:name=".GCMIntentService" />
I've added the following code to the onCreate of my main activity:
GCMRegistrar.checkDevice( this );
GCMRegistrar.checkManifest( this );
final String regId = GCMRegistrar.getRegistrationId( this );
if( regId.equals( "" ) ) {
GCMRegistrar.register( this, GCM_SENDER_ID );
}
else {
Log.v( LOG_TAG, "Already registered" );
}
I've also created the GCMIntenetService class like so:
public class GCMIntentService extends GCMBaseIntentService {
private static final String LOG_TAG = "GetAClue::GCMIntentService";
public GCMIntentService() {
super( GCM_SENDER_ID );
// TODO Auto-generated constructor stub
Log.i( LOG_TAG, "GCMIntentService constructor called" );
}
#Override
protected void onError( Context arg0, String errorId ) {
// TODO Auto-generated method stub
Log.i( LOG_TAG, "GCMIntentService onError called: " + errorId );
}
#Override
protected void onMessage( Context arg0, Intent intent ) {
// TODO Auto-generated method stub
Log.i( LOG_TAG, "GCMIntentService onMessage called" );
Log.i( LOG_TAG, "Message is: " + intent.getStringExtra( "message" ) );
}
#Override
protected void onRegistered( Context arg0, String registrationId ) {
// TODO Auto-generated method stub
Log.i( LOG_TAG, "GCMIntentService onRegistered called" );
Log.i( LOG_TAG, "Registration id is: " + registrationId );
}
#Override
protected void onUnregistered( Context arg0, String registrationId ) {
// TODO Auto-generated method stub
Log.i( LOG_TAG, "GCMIntentService onUnregistered called" );
Log.i( LOG_TAG, "Registration id is: " + registrationId );
}
}
When I run this I get this in LogCat:
07-11 11:28:46.340: V/GCMRegistrar(27435): Registering receiver
07-11 11:28:46.370: D/GCMRegistrar(27435): resetting backoff for com.badbob.app.getacluebeta
07-11 11:28:46.380: V/GCMRegistrar(27435): Registering app com.badbob.app.getacluebeta of senders 128205395388
From what I've gleaned from other posts I should get a registration ID in LogCat but I"m not. Also onRegistered() in GCMIntentService never gets called. So what am I doing wrong?
this is incorrect
protected GCMIntentService( String senderId ) {
super(senderId);}
As it states in the documentation. you must declare a PUBLIC, NO ARGUMENT constructor for GCMIntentService. Otherwise the GCMIntentService can't be instantiated properly by background intent services.
public GCMIntentService(){
super(senderID);}
the senderID can be a hard coded constant string because it will no longer change with the new GCM.
It's also very important you use the correct senderID. 24 hours is long enough for yours to be active so if my above solution doesn't work you are using the incorrect senderID. Everything else looks great.
The senderID is in the URL of your web browser when you are browsing the Google API access page. Click on GCM and a 12 digit number will be present in the browser URL. That is the correct key to use. NOT your API key. That is used on the App server side.
I also had this ANNOYing bug, til now. The Problem was, that i declared the intentservice inside another package... even if i declared the name in the android manifest and no classnotfound exception had been place... no error at all could be found... so i made sure the intentservice is in the root package.
I think you have some issues in the code.
You should do the registration of your own broadcast receiver in the manifest file and that receiver will trigger the <service android:name=".GCMIntentService" />.
Therefore you must do something like I write below.
The receiver must be declared like:
<receiver
android:name="your.package.name.YourBroadCastReceiver"
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" />
</intent-filter>
Your broadcast receiver that will start the service.
public class YourBroadCastReceiver extends BroadcastReceiver {
#Override
public final void onReceive(Context context, Intent intent) {
GCMIntentService .runIntentInService(context, intent);
setResult(Activity.RESULT_OK, null, null);
}
}
I advice you to take a look at the official GCM documentation where you can find a good example.
And... don't forget to enable the Google Cloud Messaging service in the main Google APIs Console page.
Let me know if it helps!
See below tutorial for GCM:-
http://www.androidhive.info/2012/10/android-push-notifications-using-google-cloud-messaging-gcm-php-and-mysql/
Here I have written few steps for How to Get RegID and Notification starting from scratch
Create/Register App on Google Cloud
Setup Cloud SDK with Development
Configure project for GCM
Get Device Registration ID
Send Push Notifications
Receive Push Notifications
You can find complete tutorial in below URL link
Getting Started with Android Push Notification : Latest Google Cloud
Messaging (GCM) - step by step complete tutorial
Code snip to get Registration ID (Device Token for Push Notification).
Configure project for GCM
Update AndroidManifest file
For enable GCM in our project we need to add few permission in our manifest file
Go to AndroidManifest.xml and add below code
Add Permission
<uses-permission android:name="android.permission.INTERNET”/>
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name=“.permission.RECEIVE" />
<uses-permission android:name=“<your_package_name_here>.permission.C2D_MESSAGE" />
<permission android:name=“<your_package_name_here>.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
Add GCM Broadcast Receiver declaration
add GCM Broadcast Receiver declaration in your application tag
<application
<receiver
android:name=".GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" ]]>
<intent-filter]]>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="" />
</intent-filter]]>
</receiver]]>
<application/>
Add GCM Servie declaration
<application
<service android:name=".GcmIntentService" />
<application/>
Get Registration ID (Device Token for Push Notification)
Now Go to your Launch/Splash Activity
Add Constants and Class Variables
private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
public static final String EXTRA_MESSAGE = "message";
public static final String PROPERTY_REG_ID = "registration_id";
private static final String PROPERTY_APP_VERSION = "appVersion";
private final static String TAG = "LaunchActivity";
protected String SENDER_ID = "Your_sender_id";
private GoogleCloudMessaging gcm =null;
private String regid = null;
private Context context= null;
Update OnCreate and OnResume methods
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launch);
context = getApplicationContext();
if (checkPlayServices())
{
gcm = GoogleCloudMessaging.getInstance(this);
regid = getRegistrationId(context);
if (regid.isEmpty())
{
registerInBackground();
}
else
{
Log.d(TAG, "No valid Google Play Services APK found.");
}
}
}
#Override protected void onResume()
{
super.onResume(); checkPlayServices();
}
# Implement GCM Required methods (Add below methods in LaunchActivity)
private boolean checkPlayServices() {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
GooglePlayServicesUtil.getErrorDialog(resultCode, this,
PLAY_SERVICES_RESOLUTION_REQUEST).show();
} else {
Log.d(TAG, "This device is not supported - Google Play Services.");
finish();
}
return false;
}
return true;
}
private String getRegistrationId(Context context)
{
final SharedPreferences prefs = getGCMPreferences(context);
String registrationId = prefs.getString(PROPERTY_REG_ID, "");
if (registrationId.isEmpty()) {
Log.d(TAG, "Registration ID not found.");
return "";
}
int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
int currentVersion = getAppVersion(context);
if (registeredVersion != currentVersion) {
Log.d(TAG, "App version changed.");
return "";
}
return registrationId;
}
private SharedPreferences getGCMPreferences(Context context)
{
return getSharedPreferences(LaunchActivity.class.getSimpleName(),
Context.MODE_PRIVATE);
}
private static int getAppVersion(Context context)
{
try
{
PackageInfo packageInfo = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0);
return packageInfo.versionCode;
}
catch (NameNotFoundException e)
{
throw new RuntimeException("Could not get package name: " + e);
}
}
private void registerInBackground()
{ new AsyncTask() {
Override
protected Object doInBackground(Object... params)
{
String msg = "";
try
{
if (gcm == null)
{
gcm = GoogleCloudMessaging.getInstance(context);
}
regid = gcm.register(SENDER_ID); Log.d(TAG, "########################################");
Log.d(TAG, "Current Device's Registration ID is: "+msg);
}
catch (IOException ex)
{
msg = "Error :" + ex.getMessage();
}
return null;
} protected void onPostExecute(Object result)
{ //to do here };
}.execute(null, null, null);
}
Note : please store REGISTRATION_KEY, it is important for sending PN Message to GCM
also keep in mine this will be unique for all device, by using this only GCM will send Push Notification.
Receive Push Notifications
Add GCM Broadcast Receiver Class
As we have already declared “GcmBroadcastReceiver.java” in our Manifest file, So lets create this class
update receiver class code this way
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{ ComponentName comp = new ComponentName(context.getPackageName(),
GcmIntentService.class.getName()); startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
Toast.makeText(context, “wow!! received new push notification", Toast.LENGTH_LONG).show();
}
}
Add GCM Service Class
As we have already declared “GcmBroadcastReceiver.java” in our Manifest file, So lets create this class
update receiver class code this way
public class GcmIntentService extends IntentService
{ public static final int NOTIFICATION_ID = 1; private NotificationManager mNotificationManager; private final static String TAG = "GcmIntentService"; public GcmIntentService() {
super("GcmIntentService");
} #Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
Log.d(TAG, "Notification Data Json :" + extras.getString("message"));
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
String messageType = gcm.getMessageType(intent); if (!extras.isEmpty()) { if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR
.equals(messageType)) {
sendNotification("Send error: " + extras.toString());
} else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED
.equals(messageType)) {
sendNotification("Deleted messages on server: "
+ extras.toString()); // If it's a regular GCM message, do some work.
} else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE
.equals(messageType)) {
// This loop represents the service doing some work.
for (int i = 0; i < 5; i++) {
Log.d(TAG," Working... " + (i + 1) + "/5 # "
+ SystemClock.elapsedRealtime()); try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
}
Log.i(TAG, "Completed work # " + SystemClock.elapsedRealtime());
sendNotification(extras.getString("message"));
}
} // Release the wake lock provided by the WakefulBroadcastReceiver.
GcmBroadcastReceiver.completeWakefulIntent(intent);
} // Put the message into a notification and post it.
// This is just one simple example of what you might choose to do with
// a GCM message.
private void sendNotification(String msg) { mNotificationManager = (NotificationManager) this
.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, LaunchActivity.class), 0);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder( this)
.setSmallIcon(R.drawable.icon)
.setContentTitle("Ocutag Snap")
.setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
.setContentText(msg)
.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE);
mBuilder.setContentIntent(contentIntent); mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
}
Not sure if this is related to your specific problem, however, I was experiencing the same issue. Everything was setup correctly, as far as I could tell, but the onRegistered() handler was never called.
I had the standard onCreate(), onStart() and onDestroy() service methods as part of my GCMIntentService class. Once I removed them, the handler was called, as expected.
My assumption is that by overriding these methods, I was by-passing needed code initialization.
After reading ClouDeveloper's post I removed onCreate(), onDestroy(), and the other onXXX() callback methods. Also, my GCMIntentService.onRegistered(Context, regId) is called with the regId.
Thank you ClouDeveloper!
You also need to register with your application server in the GCMBaseIntentService.onRegistered() callback. Otherwise you will not be able to send your app messages.
You should really checkout Google's GCM demo client as it provides a working sample with all of the correct code. We also have a working sample up on github: airbop-client. It provides a slightly more complete example given that it has working interactions with an application server, which is necessary for a GCM enabled app. It works with the AirBop servers (which I helped create) which are free up to 1000 devices.
If you are not getting response from the registration, one of the main reason is your manifest file is not configured correctly - especially give the "package_name" (your app package name like com.xxx.yyy) in the <permission> and <intent filter> correctly.