I have created a sample project in Google Console. Referring the sample from this site, http://code.google.com/p/blog-samples/downloads/detail?name=gcm_sample_update1.rar&can=2&q=#makechanges I got my registration Id. Now I don't know what to do next, how I can implement push notification in my app. I want to use Urban Airship to send push to my app. I have created a app in Urban Airship, by giving the package name, API key obtained through Google console. To my server I need to send the Apid to get the messages. But i don't know how to get the Apid.
It is explained here: http://developer.android.com/guide/google/gcm/gs.html
Writing the Android Application
You have to download and add gcm libraries.
Then make changes in manifest:
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="xx"/>
and
<permission android:name="my_app_package.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="my_app_package.permission.C2D_MESSAGE" />
inserting Your package name in "my_app_package".
Add other permissions
<!-- App receives GCM messages. -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<!-- GCM connects to Google Services. -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 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" />
receiver
<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="my_app_package" />
</intent-filter>
</receiver>
Again write Your package name in "my_app_package".
Then declare your service
<service android:name=".GCMIntentService" />
You have to create a class named GCMIntentService. This class is going to handle the push notifications.
It should look like this:
class GCMIntentService extends com.google.android.gcm.GCMBaseIntentService{
public void onRegistered(Context context, String regId){}
public void onUnregistered(Context context, String regId){}
public void onError(Context context, String errorId){}
public void onMessage(Context context, Intent intent){}
}
In onMessage() you will have to handle the push message. You can use notifications.
Then in Your starting Activity you will have to put this
GCMRegistrar.checkDevice(this);
GCMRegistrar.checkManifest(this);
final String regId = GCMRegistrar.getRegistrationId(this);
if (regId.equals("")) {
GCMRegistrar.register(this, SENDER_ID);
} else {
Log.v(TAG, "Already registered");
}
in onCreate().
SENDER_ID is the String containing all numbers that you got from the google console.
Well.. There are 3 steps to get APID
1. Run the application
2. Open logcat
3. Find the APID
Note first time you may get APID(Android Push ID) null so run it again you will get
If you want to use Urbanairship you have to use their SDK for user registration (look here), cause UA create a new id for each device and not using Google registration Id when pushing message using their API.
Not sure why they doing it like that but that it... =\
Related
I'm trying to implement push notification in an Android app.
As I understand, we need a sender and receiver installed on the device.
I googled on GCM an found that I need to create a Project in Google dev console.
I got a project ID and an API key.
I found there are third party applications (mixpanel) which can send
push notifications with the information above. Can I use Google Play to
send notifications to all app users?
On the programming side, I got permissions required in the Manifest.xml file
<uses-permission android:name="android.permission.INTERNET" />
<!-- GCM connects to Internet Services. -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 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.androidexample.gcm.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.androidexample.gcm.permission.C2D_MESSAGE" />
<!-- This app has permission to register and receive data message. -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<!-- Network State Permissions to detect Internet status -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Permission to vibrate -->
<uses-permission android:name="android.permission.VIBRATE" />
And a broadcast receiver
<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.androidexample.gcm" />
</intent-filter>
</receiver>
<service android:name="com.androidexample.gcm.GCMIntentService" />
From here on, I got confused about the "sender" and "receiver" parts.
Do I have to implement GCMBroadcastReceiver?
If I want to implement only the Receiving notification part, how does it look like ?
Any reference to a working code example will be good.
Yes, you have to implement GcmBroadcastReceiver class to catch messages from GCM service. The purpose of the receiver is to start the intent service even if the app is off. Here is the most common implementation:
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);
}
}
The purpose of the intent service is doing something with the caught GCM message:
public class GCMIntentService extends IntentService {
#Override
protected void onHandleIntent(Intent intent) {
// Getting GCM message fields
Bundle extras = intent.getExtras();
// Doing something with the message.
// E.g. showing push notification
}
}
You can see e.g. this article for details.
Is there anyways in sending a location based push notification for android devices with out using a third party push notification service such as Parse? I would like to send push notification to my users without the annoyance of getting a notification that doesn't relate to that specific user because they are not in a certain area. Also, I could get the users location based on a time interval but I would rather do it a different way then that, if possible.
Yes, this is entirely possible, as long as I'm correctly interpreting what you are asking.
To accomplish this, you would send the GCM push notification to all of your users (unless you had a way, server-side of filtering some of them out). Then in your application, instead of just creating a Notification and passing it to the notification manager, you would first use the LocationManager (or the newer LocationServices API) to determine if the user is within the proper location first, and then just discard the GCM notification if they're not.
You'll need to take care of several things in order to do this:
Your AndroidManifest.xml will require several permission changes, both for the GCM changes, and for the Location access:
<!-- Needed for processing notifications -->
<permission android:name="com.myappname.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="com.myappname.permission.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<!-- Needed for Location -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
You'll also need to set up a Notification Receiver in the <application> section of the manifest:
<receiver android:name="com.myappname.NotificationReceiver" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.myappname" />
</intent-filter>
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.myappname" />
</intent-filter>
</receiver>
In addition, you'll need write your NotificationReceiver java class, and override the onReceive function:
public class NotificationReceiver extends BroadcastReceiver {
public void onReceive(final Context context, final Intent intent) {
if ("com.google.android.c2dm.intent.REGISTRATION".equals(intent.getAction())) {
handleRegistration(context, intent); // you'll have to write this function
} else if ("com.google.android.c2dm.intent.RECEIVE".equals(intent.getAction())) {
// the handle message function will need to check the user's current location using the location API you choose, and then create the proper Notification if necessary.
handleMessage(context, intent);
}
}
Although I try other answer about this problem, it can't be solved.
Sender ID is correct, permissions are added, API key is true.
I use this post for creating the project:
http://developer.android.com/guide/google/gcm/gs.html#server-app
GCMRegistrar.checkDevice(this);
GCMRegistrar.checkManifest(this);
String regId = GCMRegistrar.getRegistrationId(this);
if (regId.equals("")) {
GCMRegistrar.register(this, SENDER_ID);
regId = GCMRegistrar.getRegistrationId(this);
} else {
Log.v(TAG, "Already registered");
}
String did = getDeviceID();
it returns empty string.
Do you have GCMIntentService defined correctly at the root package of your app?
<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="my_app_package" />
</intent-filter>
</receiver>
Make sure that "my_app_package" is identical to the main package of your app, or your id will return an empty string.
Also notice that
GCMRegistrar.register(this, "...");
is asynchronous. Therefore, calling GCMRegistrar.getRegistrationId(this) immediately after that is not reliable, so you should avoid it.
The id will arrive via broadcast callback to your GCMIntentService, as a part of the registration procedure. from there you can then store the gcm/fcm key anywhere you like, and use it in other parts of the application (usually on the server).
If your application launches first time, you have to wait for OnRegistered callback on your GCMIntentService.java file.
GCMRegistrar.register(this, SENDER_ID);
// Android does NOT wait for registration ends and executes immediately line below
// So your regId will be empty.
regId = GCMRegistrar.getRegistrationId(this);
GCMIntentService.java:
#Override
protected void onRegistered(Context c, String regId) {
// You can get it here!
}
Edit: Newer version of GCM library (which bundled with google play services library) waits for response and returns the Registration ID. So this answer is for older GCM libraries.
I have same problem after 1 day struggle I find solution. First i Put my GCM Related Code in To My Main Package and make change according to My Package in androidManifest.xml
i give you simple example. My project name is GCMExample and i have Three package 1. com.examle.GCMExample(Main Package) , 2. com.examle.GCMExample.activity(Second Package) , 3. com.example.GCMExample.adapter(Third Package)
I am not Getting Registration Id When My GCM Related Class File Into My Second Package
My GCM Related class like 1. GCMIntentService , 2. ServerUtilities , 3. CommonUtilities 4. WakeLocker put Into My Main Package com.example.GCMExample
also my androidManifest.xml
<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" />
<permission android:name="com.example.GCMExample.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.example.GCMExample.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<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.example.GCMExample" />
</intent-filter>
</receiver>
<service android:name="com.example.GCMExample.GCMIntentService" />
Registering app com.example.ilkgcm of senders "my_sender_id" -- This error suggests you haven't changed your 'my_sender_id' to a valid sender id which would be a 12-letter code.
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 and correctly.
For example your receiver class name is : "MyCustomIntentService.java" , just change this name as "GCMIntentService.java" then try it again. This is simple solution. Just change your file name on the SRC area.
I have tried some forum pages and searched through stackoverflow for the same thing, but I did not find the solution.
I have used the below code to generate registration ID for GCM notification. But I get an empty string as a registration ID:
GCMRegistrar.checkDevice(this);
GCMRegistrar.checkManifest(this);
if (GCMRegistrar.isRegistered(this)) {
Log.d("info", GCMRegistrar.getRegistrationId(this));
}
regId = GCMRegistrar.getRegistrationId(this);
Log.v("log", " register id oslo : " + regId);
if (regId.equals("")) {
// replace this with the project ID
GCMRegistrar.register(this, "718437041388");
Log.d("info", GCMRegistrar.getRegistrationId(this));
} else {
Log.d("info", "already registered as" + regId);
}
Please help me with this, tell me if I got anything wrong.
Thank you in advance,
Nirav.
You should not get the registrationId just after GCMRegistrar.register(this, "718437041388");
In fact, do you have a correct GCMIntentService.java which receive the regId?
If yes, you can get the regId from the onRegistered inside GCMIntentService.java
#Override
protected void onRegistered(Context context, String registrationId) {
Log.i(TAG, "Device registered: regId = " + registrationId);
Log.d("GCMIntentService", "in GCMIntentService");
displayMessage(context, getString(R.string.gcm_registered));
ServerUtilities.register(context, registrationId);
}
Notice that
GCMRegistrar.register(this, "...");
is asynchronous. Therefore, calling GCMRegistrar.getRegistrationId(this) immediately after that is not reliable, so you should avoid it.
The id will arrive via broadcast callback to your GCMIntentService, as a part of the registration procedure. from there you can than store the gcm key anywhere you like, and use it in other parts of the application (usually on the server).
Notice that GCMIntentService should be defined at the root package of your app for it to work.
Try using emulator with Google API and also sync with a Google account.
I have same problem after 1 day struggle I find solution.
First i Put my GCM Related Code in To My Main Package and make change according to My Package in androidManifest.xml
i give you simple example. My project name is GCMExample and i have Three package
1. com.examle.GCMExample(Main Package) ,
2. com.examle.GCMExample.activity(Second Package) ,
3. com.example.GCMExample.adapter(Third Package)
I am not Getting Registration Id When My GCM Related Class File Into My Second Package
My GCM Related class like 1. GCMIntentService , 2. ServerUtilities , 3. CommonUtilities 4. WakeLocker put Into My Main Package com.example.GCMExample
also my androidManifest.xml
<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" />
<permission android:name="com.example.GCMExample.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.example.GCMExample.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<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.example.GCMExample" />
</intent-filter>
</receiver>
<service android:name="com.example.GCMExample.GCMIntentService" />
Add GCM jar file in your project's lib folder
I am attempting to register my device with C2DM and am having major issues. I have followed several tutorials, all of which are very similar. I believe the issue has to do with the registration intent that it sends to the C2DM server. Does anyone have any suggestions. The following is the relevant code:
Manifest: The permissions (outside my application tag):
<!-- Used for C2DM -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="com.companyname.parade.permission.C2D_MESSAGE" />
This is the Intent registration (inside my application tag):
<receiver
android:name=".C2DMReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<!-- Receive the actual message -->
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.companyname.parade" />
</intent-filter>
<!-- Receive the registration id -->
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.companyname.parade" />
</intent-filter>
</receiver>
The following is what I call to register my device to the C2DM server (it starts the service that contacts the C2DM servers that is suppose to send back a registration Intent with my registartionID in it). It is located in a file called C2DMessaging:
public static void register(Context context) {
Intent registrationIntent = new Intent(REQUEST_REGISTRATION_INTENT);
registrationIntent.putExtra(EXTRA_APPLICATION_PENDING_INTENT,
PendingIntent.getBroadcast(context, 0, new Intent(), 0));
registrationIntent.putExtra(EXTRA_SENDER, SENDER_ID);
ComponentName name = context.startService(registrationIntent);
if(name == null){
// FAIL!
Log.d(TAG, "FAIL");
}else{
// SUCCESS
Log.d(TAG, "Success");
}
}
The ComponentName info is the following:
com.google.android.gsf/com.google.android.gsf.gtalkservice.PushMessagingRegistrar
There is no logcat output. My receiver (named C2DMReceiver) is the following:
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (C2DMessaging.INTENT_REGISTRATION_CALLBACK.equals(action)) {
// Registration Intent
Log.w(TAG, "Registration Receiver called");
handleRegistration(context, intent);
} else if (action.equals(C2DMessaging.INTENT_RECEIVED_MESSAGE_CALLBACK)) {
Log.w(TAG, "Message Receiver called");
handleMessage(context, intent);
} else if (action.equals(C2DMessaging.INTENT_C2DM_RETRY)) {
C2DMessaging.register(context);
}
}
This does not get called at all.
Edit: This whole thing was a stupid mistake on my part. I simply forgot a step somehow in the tutorials I read. I need to add this to my permissions:
<permission android:name="com.companyname.parade.permission.C2D_MESSAGE" android:protectionLevel="signature" />
Thanks to MisterSquonk for the response.
From the Google docs for C2DM for Creating the Manifest, the manifest needs a <permission> entry to complement the <uses-permission> entry for C2D_MESSAGE.
Something like this...
<permission android:name="com.companyname.parade.permission.C2D_MESSAGE" android:protectionLevel="signature" />
This tutorial worked for me in getting me up to speed:
http://www.vogella.com/articles/AndroidCloudToDeviceMessaging/article.html
I'm not sure why you have two intent filters. I only needed one - com.google.android.c2dm.intent.REGISTRATION (see tutorial above for a complete example manifest)
I'd check your manifest is correctly referencing the receiver class - perhaps try a fully-qualified reference to the class. I had an issue at one point where I moved receiver class in my project structure and all messages stopped.
I'd also check that the C2DM account is set up right, and with the right package name.
I'd also try it on another device, as in my experience some Android devices fall off C2DM and just don't receive messages for a period of time. I find sometimes flicking to airplane mode and back sorts it out, but I found testing on several devices essential to rule out problems with a specific device.