I recently began working with Google Cloud Messaging for push notifications. I have an app that I have not released a signed apk for (information provided in case there is some detection of dev builds) and have not reinstalled the app in any way shape or form.
My app requests a registration ID, I store it manually while the server side is being worked on, and test with a small bit of code on the server that is set up to send push notifications. It works for the bulk of the day but the following morning I get a response "{ error: 'NotRegistered' }".
I have taken no actions to unregister the device and the app version has not changed.
[edit] Added relevant bits from Android Manifest
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- Stuff for push notifications -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<permission android:name="com.my.package.permission.C2D_MESSAGE"
android:protectionLevel="signature"/>
<uses-permission android:name="com.my.package.permission.C2D_MESSAGE" />
<!-- end push notifications stuff -->
public void onResume(){
super.onResume();
/**
* Check for Google Play Services APK
*/
if(myApp.checkPlayServices(this)){
gcm = GoogleCloudMessaging.getInstance(this);
regid = getRegistrationId(getApplicationContext());
if( regid == null || regid.isEmpty() || (myApp.getSP().getInt(Constants.PROPERTY_APP_VERSION,-1) <= getAppVersion(this)) ){
registerInBackground();
} else {
L.i("Using GCM ID:" + regid);
}
} else {
L.i("No valid Google Play Services APK found.");
}
IntentFilter intentFilter = new IntentFilter("com.google.android.c2dm.intent.RECEIVE");
gcmReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
String[] params = {extras.getString("imgUrl"), gcm.getMessageType(intent), extras.toString()};
new GCMReceiverTask().execute(params);
}
};
this.registerReceiver(gcmReceiver,intentFilter);
}
/**
* Stuff pertaining to push notifications
*/
String SENDER_ID = null;
String regid = null;
GoogleCloudMessaging gcm;
/**
* Gets the current registration ID for application on GCM service.
* <p>
* If result is empty, the app needs to register.
*
* #return registration ID, or empty string if there is no existing
* registration ID.
*/
private String getRegistrationId(Context context) {
final SharedPreferences prefs = myApp.getSP();
String registrationId = prefs.getString(Constants.PROPERTY_REG_ID, "");
if (registrationId.isEmpty()) {
L.i("Registration not found.");
return "";
}
// Check if app was updated; if so, it must clear the registration ID
// since the existing registration ID is not guaranteed to work with
// the new app version.
int registeredVersion = prefs.getInt(Constants.PROPERTY_APP_VERSION, Integer.MIN_VALUE);
int currentVersion = getAppVersion(context);
if (registeredVersion != currentVersion) {
L.i("App version changed.");
return "";
}
return registrationId;
}
/**
* #return Application's version code from the {#code PackageManager}.
*/
private static int getAppVersion(Context context) {
try {
PackageInfo packageInfo = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0);
return packageInfo.versionCode;
} catch (PackageManager.NameNotFoundException e) {
// should never happen
throw new RuntimeException("Could not get package name: " + e);
}
}
/**
* Registers the application with GCM servers asynchronously.
* <p>
* Stores the registration ID and app versionCode in the application's
* shared preferences.
*/
private void registerInBackground() {
new GCMRegistrationTask().execute(null, null, null);
}
/**
* Sends the registration ID to your server over HTTP, so it can use GCM/HTTP
* or CCS to send messages to your app. Not needed for this demo since the
* device sends upstream messages to a server that echoes back the message
* using the 'from' address in the message.
*/
private void sendRegistrationIdToBackend() {
// Your implementation here.
L.i("WOULD SEND REGISTRATION TO SERVER... " + regid);
}
/**
* Stores the registration ID and app versionCode in the application's
* {#code SharedPreferences}.
*
* #param regId registration ID
*/
private void storeRegistrationId(String regId) {
final SharedPreferences prefs = myApp.getSP();
int appVersion = getAppVersion(this);
L.i("Saving regId on app version " + appVersion);
SharedPreferences.Editor editor = prefs.edit();
editor.putString(Constants.PROPERTY_REG_ID, regId);
editor.putInt(Constants.PROPERTY_APP_VERSION, appVersion);
editor.commit();
}
/**
* Unregisters the application with GCM servers asynchronously.
* <p>
* Removes the registration ID and app versionCode from the application's
* shared preferences.
*/
private void unRegisterInBackground() {
new GCMRegistrationTask(true).execute(null, null, null);
}
private class GCMReceiverTask extends AsyncTask<String, Void, String>{
#Override
protected String doInBackground(String... params) {
// Expect params[0] to be image URL, params[1] to be messageType
String imageUrl = params[0];
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(Main.this);
// The getMessageType() intent parameter must be the intent you received
// in your BroadcastReceiver.
String messageType = params[1];
// Stringified extras as last param
String extrasString = params[params.length - 1];
/*
* 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)) {
L.e("Send error: " + extrasString);
} else if (GoogleCloudMessaging.
MESSAGE_TYPE_DELETED.equals(messageType)) {
L.i("Deleted messages on server: " +
extrasString);
// If it's a regular GCM message, do some work.
} else if (GoogleCloudMessaging.
MESSAGE_TYPE_MESSAGE.equals(messageType)) {
// retrieve image
try {
L.i("Got image URL: " + imageUrl);
String[] parts = imageUrl.split("/");
String fileName = parts[parts.length - 1];
if (imageUrl.isEmpty()) {
throw new Exception("No Image URL supplied.");
}
ServerCall sc = new ServerCall(imageUrl, ServerCall.POST);
String path = Environment.getExternalStorageDirectory() + File.separator + getPackageName().toString() + File.separator + "user_images";
sc.saveByteArrayToLocalFile(path, fileName);
} catch (Exception e) {
L.e("ERROR writing image to storage: " + Log.getStackTraceString(e));
}
// Post notification of received message.
L.i("Received: " + extrasString);
}
return null;
}
#Override
protected void onPostExecute(String msg){
Button proceed = (Button)findViewById(R.id.button4);
if( proceed != null ){
proceed.setEnabled(true);
}
}
}
private class GCMRegistrationTask extends AsyncTask<Void, Void, String> {
private boolean unregistering = false;
GCMRegistrationTask() {
this(false);
}
GCMRegistrationTask(boolean unregister) {
super();
this.unregistering = unregister;
}
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(getApplicationContext());
}
if( unregistering ) {
gcm.unregister();
myApp.getSP()
.edit()
.remove(Constants.PROPERTY_REG_ID)
.commit();
} else {
SENDER_ID = myApp.getSP().getString(Constants.GCM_SENDER_ID,null);
if( SENDER_ID != null ) {
regid = gcm.register(SENDER_ID);
msg = "Device registered, registration ID=" + regid;
// You should send the registration ID to your server over HTTP,
// so it can use GCM/HTTP or CCS to send messages to your app.
// The request to your server should be authenticated if your app
// is using accounts.
sendRegistrationIdToBackend();
// For this demo: we don't need to send it because the device
// will send upstream messages to a server that echo back the
// message using the 'from' address in the message.
// Persist the registration ID - no need to register again.
storeRegistrationId(regid);
} else {
L.e("SHOULD NOT GET HERE, GCM_SENDER_ID SHOULD NOT BE NULL! " + myApp.getSP().getString(Constants.GCM_SENDER_ID,"[[EMPTY]]"));
}
}
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
// If there is an error, don't just keep trying to register.
// Require the user to click a button again, or perform
// exponential back-off.
}
return msg;
}
#Override
protected void onPostExecute(String msg) {
// handle postExecute - Nothing to do?
}
}
This is intentional.
Registration IDs will expire after some time. Client should detect that and request another ID.
http://developer.android.com/google/gcm/client.html
As stated above, an Android app must register with GCM servers and get a registration ID before it can receive messages. A given registration ID is not guaranteed to last indefinitely, so the first thing your app should always do is check to make sure it has a valid registration ID (as shown in the code snippets above).
Related
Implicit intents with startService are not safe: Intent { act=com.google.android.c2dm.intent.REGISTRATION (has extras) } android.content.ContextWrapper.startService:494 in.demo.gcm.MainActivity$1.onClick:29 android.view.View.performClick:4438
I am getting above error,i add gcm.jar in my project but still my error not clear.
Please give me any other suggestion.
Thanks in advance.
I don't know about the error you are getting, but gcm.jar is obsolete. The recommended way to register to GCM is via the GoogleCloudMessaging.register method of the Google Play Services library.
The registration code (taken from the official GCM demo app) looks like this :
/**
* Registers the application with GCM servers asynchronously.
* <p>
* Stores the registration ID and the app versionCode in the application's
* shared preferences.
*/
private void registerInBackground() {
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context);
}
regid = gcm.register(SENDER_ID);
msg = "Device registered, registration ID=" + regid;
// You should send the registration ID to your server over HTTP, so it
// can use GCM/HTTP or CCS to send messages to your app.
sendRegistrationIdToBackend();
// For this demo: we don't need to send it because the device will send
// upstream messages to a server that echo back the message using the
// 'from' address in the message.
// Persist the regID - no need to register again.
storeRegistrationId(context, regid);
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
// If there is an error, don't just keep trying to register.
// Require the user to click a button again, or perform
// exponential back-off.
}
return msg;
}
#Override
protected void onPostExecute(String msg) {
mDisplay.append(msg + "\n");
}
}.execute(null, null, null);
}
I'm following the android GCM tutorial provided by google, and I get the following errors:
on the line:
private void sendRegistrationIdToBackend() {
// Your implementation here.
}
Syntax error on Token "Void", # expected.
Syntax error insert "enum Identifier" to complete EnumHeader.
Using, compiler 1.6
Thank you so much.
The entire function:
private void registerInBackground() {
new AsyncTask() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context);
}
regid = gcm.register(SENDER_ID);
msg = "Device registered, registration ID=" + regid;
// You should send the registration ID to your server over HTTP,
// so it can use GCM/HTTP or CCS to send messages to your app.
// The request to your server should be authenticated if your app
// is using accounts.
sendRegistrationIdToBackend();
// For this demo: we don't need to send it because the device
// will send upstream messages to a server that echo back the
// message using the 'from' address in the message.
// Persist the regID - no need to register again.
storeRegistrationId(context, regid);
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
// If there is an error, don't just keep trying to register.
// Require the user to click a button again, or perform
// exponential back-off.
}
return msg;
}
#Override
protected void onPostExecute(String msg) {
mDisplay.append(msg + "\n");
}
}.execute(null, null, null);
/**
* Sends the registration ID to your server over HTTP, so it can use GCM/HTTP
* or CCS to send messages to your app. Not needed for this demo since the
* device sends upstream messages to a server that echoes back the message
* using the 'from' address in the message.
*/
private void sendRegistrationIdToBackend() {
// Your implementation here.
}
}
It seems you forgot to close the registerInBackground() method.
Add } after }.execute(null, null, null);
Another way to look at it is that you put private void sendRegistrationIdToBackend() {} inside the registerInBackground() method, which is wrong.
hello i am following the official documentation of android to send the push notification as the old method is deprecated but im facing problem in implementing GCM Client
http://developer.android.com/google/gcm/client.html
the tutorial is written here, scroll down and see
private void registerInBackground()
when i write this function on my app it gives me this error
Syntax error on token "void", # expected
i have googled it and i know the error now that this method is trying to create a method inside a method but still im confused because it is the official documentation i must have done something wrong, can anybody point out plz?
here is the method on this tutorial:
private void registerInBackground() {
new AsyncTask() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context);
}
regid = gcm.register(SENDER_ID);
msg = "Device registered, registration ID=" + regid;
// You should send the registration ID to your server over HTTP,
// so it can use GCM/HTTP or CCS to send messages to your app.
// The request to your server should be authenticated if your app
// is using accounts.
sendRegistrationIdToBackend();
// For this demo: we don't need to send it because the device
// will send upstream messages to a server that echo back the
// message using the 'from' address in the message.
// Persist the regID - no need to register again.
storeRegistrationId(context, regid);
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
// If there is an error, don't just keep trying to register.
// Require the user to click a button again, or perform
// exponential back-off.
}
return msg;
}
#Override
protected void onPostExecute(String msg) {
mDisplay.append(msg + "\n");
}
}.execute(null, null, null);
...
/**
* Sends the registration ID to your server over HTTP, so it can use GCM/HTTP
* or CCS to send messages to your app. Not needed for this demo since the
* device sends upstream messages to a server that echoes back the message
* using the 'from' address in the message.
*/
private void sendRegistrationIdToBackend() {
// Your implementation here.
}
}
now see that sendRegistrationIdToBackend is inside a method itself, any help plz?
here is the solution i found for it and disappointed that 33 people viewed it but nobody bother to ans anyways here is the code
private void registerInBackground() {
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context);
}
regid = gcm.register(SENDER_ID);
msg = "Device registered, registration ID=" + regid;
// You should send the registration ID to your server over HTTP, so it
// can use GCM/HTTP or CCS to send messages to your app.
sendRegistrationIdToBackend();
// For this demo: we don't need to send it because the device will send
// upstream messages to a server that echo back the message using the
// 'from' address in the message.
// Persist the regID - no need to register again.
storeRegistrationId(context, regid);
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
// If there is an error, don't just keep trying to register.
// Require the user to click a button again, or perform
// exponential back-off.
}
return msg;
}
#Override
protected void onPostExecute(String msg) {
mDisplay.append(msg + "\n");
}
}.execute(null, null, null);
}
I,m developing GCM app and recieve "error:AUTHENTICATION_FAILED". I,m using my samsung tab device.My code is below:
private void registerInBackground() {
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
Log.i(TAG, "11111");
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context);
Log.i(TAG, "11dfsfsd111");
}
Log.i(TAG, "11dfsfsd111fsdfsdf");
regid = gcm.register(SENDER_ID);
Log.i(TAG, "id = :"+regid);
Log.i(TAG, "2222");
msg = "Device registered, registration ID=" + regid;
// You should send the registration ID to your server over HTTP, so it
// can use GCM/HTTP or CCS to send messages to your app.
// sendRegistrationIdToBackend();
// For this demo: we don't need to send it because the device will send
// upstream messages to a server that echo back the message using the
// 'from' address in the message.
// Persist the regID - no need to register again.
// storeRegistrationId(context, regid);
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
// If there is an error, don't just keep trying to register.
// Require the user to click a button again, or perform
// exponential back-off.
}
return msg;
}
#Override
protected void onPostExecute(String msg) {
Log.i(TAG, "sdfdsfs:" + msg);
mDisplay.append(msg + "\n");
}
}.execute(null, null, null);
}
i Get this msg when the control comes in postExecute function and print the "msg" variable. I searched for the error and found that this error come due to wrong password of gmail sync acount, But i checked it and my password is correct. Kindly help
public void registerClient() {
try {
// Check that the device supports GCM (should be in a try / catch)
GCMRegistrar.checkDevice(viewLogin);
// Check the manifest to be sure this app has all the required
// permissions.
GCMRegistrar.checkManifest(viewLogin);
// Get the existing registration id, if it exists.
regId = GCMRegistrar.getRegistrationId(viewLogin);
if (regId.equals("")) {
registrationStatus = "Registering...";
// register this device for this project
GCMRegistrar.register(viewLogin, GCMIntentService.PROJECT_ID);
regId = GCMRegistrar.getRegistrationId(viewLogin);
registrationStatus = "Registration Acquired";
// This is actually a dummy function. At this point, one
// would send the registration id, and other identifying
// information to your server, which should save the id
// for use when broadcasting messages.
} else {
registrationStatus = "Already registered";
}
Log.d(TAG, regId);
sendRegistrationToServer();
} catch (Exception e) {
e.printStackTrace();
registrationStatus = e.getMessage();
}
Log.d(TAG, registrationStatus);
// This is part of our CHEAT. For this demo, you'll need to
// capture this registration id so it can be used in our demo web
// service.
}
please use this..its working in my project.
add in your manifestfile:
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
I think you are using old GCM implementation. New GCM implementation code is available on developer site(http://developer.android.com/google/gcm/client.html). Account authentication and other type of authentication is properly handled here
I have created a application that uses the GCM functionality. When I am posting the message from the server to the device in response i am getting the message id. After sending the message from the server when I am again running the application then I am getting the response on the device. It is not coming as a notification like GMAIL notification once app is installed when the server sends message it will show notification. I am posting my complete server and client code.Please help me to resolve the issue.
Issue I got: When I am running again my android application then what I have send from the server side on the that time it is showing the message but I want it to be as a notification what I am sending from the server ...
Server-side Code
/**
* Servlet implementation class GCMBroadcast
*/
#WebServlet("/GCMBroadcast")
public class GCMBroadcast extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final String SENDER_ID = "";
private static final String ANDROID_DEVICE = "";
private List<String> androidTargets = new ArrayList<String>();
public GCMBroadcast() {
super();
androidTargets.add(ANDROID_DEVICE);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String collapseKey = "";
String userMessage = "";
try {
userMessage = request.getParameter("Message");
collapseKey = request.getParameter("CollapseKey");
} catch (Exception e) {
e.printStackTrace();
return;
}
Sender sender = new Sender(SENDER_ID);
Message message = new Message.Builder()
.collapseKey(collapseKey)
.timeToLive(30)
.delayWhileIdle(true)
.addData("message", userMessage)
.build();
try {
MulticastResult result = sender.send(message, androidTargets, 1);
System.out.println("Response: " + result.getResults().toString());
if (result.getResults() != null) {
int canonicalRegId = result.getCanonicalIds();
if (canonicalRegId != 0) {
System.out.println("response " +canonicalRegId );
}
} else {
int error = result.getFailure();
System.out.println("Broadcast failure: " + error);
}
} catch (Exception e) {
e.printStackTrace();
}
request.setAttribute("CollapseKey", collapseKey);
request.setAttribute("Message", userMessage);
request.getRequestDispatcher("index.jsp").forward(request, response);
}
}
DemoActivity Code
public class DemoActivity extends Activity {
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 static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
/**
* Substitute you own sender ID here. This is the project number you got
* from the API Console, as described in "Getting Started."
*/
String SENDER_ID = "";
/**
* Tag used on log messages.
*/
static final String TAG = "GCM Demo";
TextView mDisplay;
GoogleCloudMessaging gcm;
AtomicInteger msgId = new AtomicInteger();
Context context;
String regid;
#SuppressLint("NewApi")
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDisplay = (TextView) findViewById(R.id.display);
context = getApplicationContext();
// Check device for Play Services APK. If check succeeds, proceed with GCM registration.
if (checkPlayServices()) {
gcm = GoogleCloudMessaging.getInstance(this);
regid = getRegistrationId(context);
Log.d("Registration id ", regid+"");
if (regid.isEmpty()) {
registerInBackground();
}
} else {
Log.i(TAG, "No valid Google Play Services APK found.");
}
}
#Override
protected void onResume() {
super.onResume();
// Check device for Play Services APK.
checkPlayServices();
}
/**
* Check the device to make sure it has the Google Play Services APK. If
* it doesn't, display a dialog that allows users to download the APK from
* the Google Play Store or enable it in the device's system settings.
*/
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.i(TAG, "This device is not supported.");
finish();
}
return false;
}
return true;
}
/**
* Stores the registration ID and the app versionCode in the application's
* {#code SharedPreferences}.
*
* #param context application's context.
* #param regId registration ID
*/
private void storeRegistrationId(Context context, String regId) {
final SharedPreferences prefs = getGcmPreferences(context);
int appVersion = getAppVersion(context);
Log.i(TAG, "Saving regId on app version " + appVersion);
SharedPreferences.Editor editor = prefs.edit();
editor.putString(PROPERTY_REG_ID, regId);
editor.putInt(PROPERTY_APP_VERSION, appVersion);
editor.commit();
}
/**
* Gets the current registration ID for application on GCM service, if there is one.
* <p>
* If result is empty, the app needs to register.
*
* #return registration ID, or empty string if there is no existing
* registration ID.
*/
#SuppressLint("NewApi")
private String getRegistrationId(Context context) {
final SharedPreferences prefs = getGcmPreferences(context);
String registrationId = prefs.getString(PROPERTY_REG_ID, "");
if (registrationId.isEmpty()) {
Log.i(TAG, "Registration not found.");
return "";
}
// Check if app was updated; if so, it must clear the registration ID
// since the existing regID is not guaranteed to work with the new
// app version.
int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
int currentVersion = getAppVersion(context);
if (registeredVersion != currentVersion) {
Log.i(TAG, "App version changed.");
return "";
}
return registrationId;
}
/**
* Registers the application with GCM servers asynchronously.
* <p>
* Stores the registration ID and the app versionCode in the application's
* shared preferences.
*/
private void registerInBackground() {
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context);
}
regid = gcm.register(SENDER_ID);
Log.d("registration Id", regid+"");
msg = "Device registered, registration ID=" + regid;
// You should send the registration ID to your server over HTTP, so it
// can use GCM/HTTP or CCS to send messages to your app.
sendRegistrationIdToBackend();
// For this demo: we don't need to send it because the device will send
// upstream messages to a server that echo back the message using the
// 'from' address in the message.
// Persist the regID - no need to register again.
storeRegistrationId(context, regid);
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
// If there is an error, don't just keep trying to register.
// Require the user to click a button again, or perform
// exponential back-off.
}
return msg;
}
#Override
protected void onPostExecute(String msg) {
mDisplay.append(msg + "\n");
}
}.execute(null, null, null);
}
// Send an upstream message.
public void onClick(final View view) {
if (view == findViewById(R.id.send)) {
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
Bundle data = new Bundle();
data.putString("my_message", "Hello World");
data.putString("my_action", "com.google.android.gcm.demo.app.ECHO_NOW");
String id = Integer.toString(msgId.incrementAndGet());
gcm.send(SENDER_ID + "#gcm.googleapis.com", id, data);
msg = "Sent message";
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
}
return msg;
}
#Override
protected void onPostExecute(String msg) {
mDisplay.append(msg + "\n");
}
}.execute(null, null, null);
} else if (view == findViewById(R.id.clear)) {
mDisplay.setText("");
}
}
#Override
protected void onDestroy() {
super.onDestroy();
}
/**
* #return Application's version code from the {#code PackageManager}.
*/
private static int getAppVersion(Context context) {
try {
PackageInfo packageInfo = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0);
return packageInfo.versionCode;
} catch (NameNotFoundException e) {
// should never happen
throw new RuntimeException("Could not get package name: " + e);
}
}
/**
* #return Application's {#code SharedPreferences}.
*/
private SharedPreferences getGcmPreferences(Context context) {
// This sample app persists the registration ID in shared preferences, but
// how you store the regID in your app is up to you.
return getSharedPreferences(DemoActivity.class.getSimpleName(),
Context.MODE_PRIVATE);
}
/**
* Sends the registration ID to your server over HTTP, so it can use GCM/HTTP or CCS to send
* messages to your app. Not needed for this demo since the device sends upstream messages
* to a server that echoes back the message using the 'from' address in the message.
*/
private void sendRegistrationIdToBackend() {
// Your implementation here.
}
}
GCMBroadCastReciver
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);
}
}
GCMIntentServicve
public class GcmIntentService extends IntentService {
public static final int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
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) {
}
}
Log.i(TAG, "Completed work # " + SystemClock.elapsedRealtime());
// Post notification of received message.
sendNotification("Received: " + extras.toString());
Log.i(TAG, "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) {
mNotificationManager = (NotificationManager)
this.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, DemoActivity.class), 0);
Log.d("Notification Message==", msg);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_stat_gcm)
.setContentTitle("Iween Notification")
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(msg))
.setContentText(msg);
Uri notificationSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
mBuilder.setSound(notificationSound);
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
}
Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright 2013 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License"); you may not
- use this file except in compliance with the License. You may obtain a copy
- of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- License for the specific language governing permissions and limitations
- under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.newgcmproject" android:versionCode="1" android:versionName="1.0">
<!-- GCM requires Android SDK version 2.2 (API level 8) or above. -->
<!-- The targetSdkVersion is optional, but it's always a good practice
to target higher versions. -->
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="16"/>
<!-- 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" />
<!--
Creates a custom permission so only this app can receive its messages.
NOTE: the permission *must* be called PACKAGE.permission.C2D_MESSAGE,
where PACKAGE is the application's package name.
-->
<permission android:name="com.example.newgcmproject.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.example.newgcmproject.permission.C2D_MESSAGE" />
<!-- This app has permission to register and receive data message. -->
<uses-permission
android:name="com.google.android.c2dm.permission.RECEIVE" />
<!-- Main activity. -->
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:name=".DemoActivity"
android:label="#string/app_name"
android:configChanges="orientation|keyboardHidden|screenSize"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--
WakefulBroadcastReceiver that will receive intents from GCM
services and hand them to the custom IntentService.
The com.google.android.c2dm.permission.SEND permission is necessary
so only GCM services can send data messages for the app.
-->
<receiver
android:name=".GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<!-- Receives the actual messages. -->
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.google.android.gcm.demo.app" />
</intent-filter>
</receiver>
<service android:name=".GcmIntentService" />
</application>
</manifest>
I am not getting any notifications on my device even if I am getting the message id when I am sending from the server side.
Edit
Now I have done some changes in my code. I am getting the exception that the service is not available
My understanding of the parameters you are adding to the message is as follows:
The timeToLive is set to 30 seconds which is how long it will reside on the server before being deleted.
The delay_while_idle is set to true so that if the phone is locked or asleep, then the GCM server does not attempt to deliver the message.
So if you send the message and your phone is not woken up or unlocked for 30 seconds then you will never get that message.
Whilst developing your app I would delete both of these arguments, so that they default to the values of 4 weeks and false. When you have established that messages do come through, you can experiment with different values for them.
In the manifest
I think that you receiver category is wrong. It shouldn't be
<category android:name="com.avilyne.android.gcmclient" />
It should match the top level package name:
package="com.example.gcmttestproject"
If i understand correctly you want to display the notification on the device, then open your app when you click it. To do this you can use the following code (replace MyActivity with your own on the intent):
//Issues a notification to inform the user that server has sent a message.
private static void generateNotification(Context context, String message, String title,) {
int icon = R.drawable.logo;
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent notificationIntent = new Intent(context, MyActivity.class);
// set intent so it does not start a new activity
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent intent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
Uri defaultSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Notification notification = new NotificationCompat.Builder(context)
.setContentTitle(title)
.setContentText(message)
.setContentIntent(intent)
.setSmallIcon(icon)
.setLights(Color.YELLOW, 1, 2)
.setAutoCancel(true)
.setSound(defaultSound)
.build();
notificationManager.notify(0, notification);
}
This can be called on the onMessage() method on GCMBaseIntentService.