Reputation: 920
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?
Upvotes: 28
Views: 33149
Reputation: 35783
Here I have written few steps for How to Get RegID and Notification starting from scratch
You can find complete tutorial in below URL link
Code snip to get Registration ID (Device Token for Push Notification).
Configure project for GCM
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/>
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.
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());
}
}
Upvotes: 2
Reputation: 11
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.
Upvotes: 0
Reputation: 2813
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.
Upvotes: 0
Reputation: 1202
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.
Upvotes: 8
Reputation: 1
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!
Upvotes: 0
Reputation: 1
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.
Upvotes: 0
Reputation: 6690
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!
Upvotes: 3
Reputation: 824
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.
Upvotes: 18