Last year when you added a Cloud Endpoints plus GCM module to an Android Studio project, the IDE created some sample code both in the backend and the app that showed how to use GCM with Cloud Endpoints.
However, with the newer versions of Android Studio you only get the backend part added for you. So I went back into my old projects and dug up some of the convenient app code which registered, and sent GCM push notifications in Android.
Here is what that code looks like:
GcmBroadcastReceiver.java
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);
}
}
GcmIntentService.java
public class GcmIntentService extends IntentService {
android.support.v4.app.NotificationCompat.Builder notification;
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)) {
Logger.getLogger("GCM_RECEIVED").log(Level.INFO, extras.toString());
showToast(extras.getString("message"));
sendNotification(extras.getString("message"));
}
}
//call to the API and get new data.
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();
}
});
}
private void sendNotification(String msg) {
notification = new android.support.v4.app.NotificationCompat.Builder(this);
//set number of notifications count
//notification.setNumber(x);
//cancels notification when app is opened.
notification.setAutoCancel(true);
//build the notification
notification.setSmallIcon(R.drawable.greenicon);
notification.setTicker("This is the ticker!");
//set time
notification.setWhen(System.currentTimeMillis());
notification.setContentTitle("New message!");
notification.setContentText(msg);
notification.setSound((Settings.System.DEFAULT_NOTIFICATION_URI));
//LED
notification.setLights(Color.RED, 3000, 3000);
// intent
Intent intent = new Intent(this, MainActivity.class);
//give phone access to perform this intent b/c they may be in another part of their phone.
//aka gives phone access to the intents in our app
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
//what to do when notification is clicked:
notification.setContentIntent(pendingIntent);
//Builds notification and issues it (sends it to device). Can build and send out notifcations
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
//send out notification with uniqueID
nm.notify(2158, notification.build());
}
}
GcmRegistrationAsyncTask
class GcmRegistrationAsyncTask extends AsyncTask<Void, Void, String> {
private static Registration regService = null;
private GoogleCloudMessaging gcm;
private Context context;
// TODO: change to your own sender ID to Google Developers Console project number, as per instructions above
private static final String SENDER_ID = "1026567774990";
public GcmRegistrationAsyncTask(Context context) {
this.context = context;
}
#Override
protected String doInBackground(Void... params) {
if (regService == null) {
Registration.Builder builder = new Registration.Builder(AndroidHttp.newCompatibleTransport(),
new AndroidJsonFactory(), null)
// Need setRootUrl and setGoogleClientRequestInitializer only for local testing,
// otherwise they can be skipped
.setRootUrl("https://push-notif-45657747.appspot.com/_ah/api/")
.setGoogleClientRequestInitializer(new GoogleClientRequestInitializer() {
#Override
public void initialize(AbstractGoogleClientRequest<?> abstractGoogleClientRequest)
throws IOException {
abstractGoogleClientRequest.setDisableGZipContent(true);
}
}) ;
// end of optional local run code
regService = builder.build();
}
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context);
}
String 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.
regService.register(regId).execute();
} catch (IOException ex) {
ex.printStackTrace();
msg = "Error: " + ex.getMessage();
}
return msg;
}
#Override
protected void onPostExecute(String msg) {
Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
Logger.getLogger("REGISTRATION").log(Level.INFO, msg);
}
}
However, I am getting some deprecated errors in Android Studio now:
gcm.register(SENDER_ID); is deprecated and so is GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.
This GCM stuff is pretty confusing to begin with and while there is some information here on how to use it, I was wondering if anyone had any currently working non-deprecated examples or maybe you could suggest some edits to the above code if you know what you are doing...? Much thanks!
Wanted to give people a little guide here in case they were lost.
First check out and stay up to date with this Google Cloud Messaging Android example:
https://github.com/google/gcm
To make it work you will have to generate a google-services.json file which you can do here:
https://developers.google.com/mobile/add
Make sure you are logged into the google developers console before you go that link. It will load your projects for you and automatically set up the gcm api key for you in your projects credentials.
Copy/paste the google-services.json into the /app directory of your Android project.
Add a cloud endpoints with gcm module to the android project.
Enter your gcm api key (which you can view on your credentials page on developers console) into the webapp-WEB_INF/appengine-web.xml file in your cloud endpoints backend:
<property name="gcm.api.key" value="your-api-key-here"/>
This way, inside the Android client and MessagingEndpoint the code will automatically get the api key (in the endpoint it will be the line Sender sender = new Sender(API_KEY); for example, which will just retrieve it for you).
Run the sample gcm android project and it should work. Send a push notification with the API's explorer you deployed.
BIG NOTE: when you are ready to use the sample code in your own app make sure the RegistrationIntentService is in the root of your package or it won't work! Took a while to figure that out... Not sure if it is a bug or what.
Related
I'm implementing GCM in Android P.
But I cannot receive the broadcasting from GCM.
What's wrong in Android P?
By the way, working well in Android O.
Intent registrationIntent = new Intent("com.google.android.c2dm.intent.REGISTER");
registrationIntent.setPackage("com.google.android.gsf");
registrationIntent.putExtra("sender", sender_id);
registrationIntent.putExtra("app", PendingIntent.getBroadcast(this, 0, new Intent(), 0));
public class GCMBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
String messageType = gcm.getMessageType(intent);
Log.e("GCM", "action=" + intent.getAction() + " registration_id="+intent.getStringExtra("registration_id"));
}
}
You must be using an older version of GCM.
Upgrade to GCM 11 or higher. (The latest is 15.0.1: com.google.android.gms:play-services-gcm:15.0.1), or even better, migrate to FCM. (GCM is now deprecated)
the documentation states ...
As of April 10, 2018, Google has deprecated GCM. The GCM server and client APIs are deprecated and will be removed as soon as April 11, 2019. Migrate GCM apps to Firebase Cloud Messaging (FCM), which inherits the reliable and scalable GCM infrastructure, plus many new features. See the migration guide to learn more.
therefore, you might (sooner or later) have to migrate to FCM.
since recently, there's also Firebase In-App Messaging.
I solved this problem myself by using GCM 3.0 way like below:
public void getInstanceIdToken() {
if (checkPlayServices()) {
// Start IntentService to register this application with GCM.
Intent intent = new Intent(this, RegistrationIntentService.class);
startService(intent);
}
}
public class RegistrationIntentService extends IntentService {
private static String TAG = RegistrationIntentService.class.getSimpleName();
public RegistrationIntentService() {
super(TAG);
}
String senderId = "YourSenderId";
#Override
protected void onHandleIntent(#Nullable Intent intent) {
InstanceID instanceID = InstanceID.getInstance(this);
try {
String token = instanceID.getToken(senderId,
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
} catch (IOException e) {
e.printStackTrace();
}
}
}
I am trying to use FCM to send UpStream Message, so I followed the tutorial on google and it works.
As shown in the code below in MainActivity, I send Upstream message when the button is clicked, then in MyAndroidFirebaseMsgService I should see a Log message as shown
below in MyAndroidFirebaseMsgService.
But what happen is, the Log messages in MyAndroidFirebaseMsgService in onMessageSent in do not get displayed even I kept pressing the button several times.
the Log message in MyAndroidFirebaseMsgService in onMessageSent can be displayed only if sent a downstream messagefrom FCM to the App, in this case, both the Logs in
in MyAndroidFirebaseMsgService will be displayed.
Please let me know why the Log message in onMessageSent is not getting displayed once there is an UpStream message sent?and how to fix it.
Mainactivity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBtnSendUpstreamMsg = (Button) findViewById(R.id.btn_send_upstream_message);
mBtnSendUpstreamMsg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FirebaseMessaging fm = FirebaseMessaging.getInstance();
fm.send(new RemoteMessage.Builder("673xxxxx" + "#gcm.googleapis.com")
.setMessageId("2")
.addData("my_message", "Hello World")
.addData("my_action","SAY_HELLO")
.build());
}
});
}
MyAndroidFirebaseMsgService:
public class MyAndroidFirebaseMsgService extends FirebaseMessagingService {
private final static String TAG = MyAndroidFirebaseMsgService.class.getSimpleName();
#Override
public void onMessageSent(String s) {
super.onMessageSent(s);
Log.d(TAG, "onMessageSent: upstream message");
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(TAG, "onMessageReceived: downstream message");
//Log data to Log Cat
Log.d(TAG, "onMessageReceived->From: " + remoteMessage.getFrom());
Log.d(TAG, "onMessageReceived->Notification Message Body: " + remoteMessage.getNotification().getBody());
//create notification
createNotification(remoteMessage.getNotification().getBody());
}
private void createNotification( String messageBody) {
Intent intent = new Intent( this , ResultActivity.class );
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent resultIntent = PendingIntent.getActivity( this , 0, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri notificationSoundURI = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder mNotificationBuilder = new NotificationCompat.Builder( this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Android Tutorial Point FCM Tutorial")
.setContentText(messageBody)
.setAutoCancel( true )
.setSound(notificationSoundURI)
.setContentIntent(resultIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, mNotificationBuilder.build());
}
}
Yes, is possible to send a Firebase messaging push notification and receive it in all app life cycles using onMessageReceived.
But is necessary to change the default Firebase behaviour, intercepting the intent request before everything else.
** IMPORTANT NOTE **
This was a pretty stupid idea from Firebase by remove the developers processment capability when the FCM message arives with the notification message format, but not for data message.
This created a bunch of "workarounds" in many solutions, which made the analythics and everything else being messed up.
If I had designed this solution, I would always call the onMessageReceived method with a completion handle. Let the developer decide what to do (free tip for you, Firebase).
Use onMessageReceived is the correct way to do. This method is the only one who brings RemoteMessage object, that have every information what you need. It was designed for it. You are on correct path.
** HOW TO DO **
In your Firebase Class MyAndroidFirebaseMsgService, which extends FirebaseMessagingService, override the public method handleIntent to intercep the intent request before Firebase catch it.
#Override
public void handleIntent(Intent intent){
if(intent.hasExtra("google.message_id")){
intent = handleFirebaseIntent(intent);
}
super.handleIntent(intent);
}
After, transform the notification message package into an data message, removing all "gcm.notification.%" and "gcm.n.%" extras from intent, and translating "gcm.notification.title", "gcm.notification.body" and "gcm.notification.image" elements into what you need:
// Thank you Google, for that brilliant idea to treat notification message and notification data
// differently on Android, depending of what app life cycle is. Because of that, all the developers
// are doing "workarounds", using data to send push notifications, and that's not what you planned for.
// Let the developers decide what to do on their apps and ALWAYS deliver the notification
// to "onMessageReceived" method. Its simple, is freedom and its what the creative ones need.
private Intent handleFirebaseIntent(Intent intent){
//printIntentExtras(intent);
String FCM_TITLE_KEY = "gcm.notification.title";
String FCM_BODY_KEY = "gcm.notification.body";
String FCM_IMAGE_KEY = "gcm.notification.image";
String title = intent.getStringExtra(FCM_TITLE_KEY);
String body = intent.getStringExtra(FCM_BODY_KEY);
String image = intent.getStringExtra(FCM_IMAGE_KEY);
// Remove the key extras that identifies an Notification type message
Bundle bundle = intent.getExtras();
if (bundle != null) {
for (String key : bundle.keySet()) {
if (key.startsWith("gcm.notification.") || key.startsWith("gcm.n."))
{
intent.removeExtra(key);
}
}
}
Boolean isTitleEmpty = StringUtils.isNullOrEmpty(title);
Boolean isBodyEmpty = StringUtils.isNullOrEmpty(body);
Boolean isImageEmpty = StringUtils.isNullOrEmpty(image);
// Notification title and body has prevalence over Data title and body
if(
!isTitleEmpty || !isBodyEmpty || !isImageEmpty
){
// This is my personalized translation method, designed for my solution.
// Probably you gonna need to do it by your own
String contentData = intent.getStringExtra(Definitions.PUSH_NOTIFICATION_CONTENT);
Map<String, Object> content;
if(StringUtils.isNullOrEmpty(contentData)){
content = new HashMap<String, Object>();
content.put(Definitions.NOTIFICATION_ID, new Random().nextInt(65536) - 32768);
content.put(Definitions.NOTIFICATION_CHANNEL_KEY, "basic_channel" );
} else {
content = JsonUtils.fromJson(new TypeToken<Map<String, Object>>(){}.getType(),contentData);
}
if(!isTitleEmpty) content.put(Definitions.NOTIFICATION_TITLE, title);
if(!isBodyEmpty) content.put(Definitions.NOTIFICATION_BODY, body);
if(!isImageEmpty){
content.put(Definitions.NOTIFICATION_BIG_PICTURE, image);
content.put(Definitions.NOTIFICATION_LAYOUT, NotificationLayout.BigPicture.toString());
}
contentData = JsonUtils.toJson(content);
intent.putExtra(Definitions.PUSH_NOTIFICATION_CONTENT, contentData);
}
//printIntentExtras(intent);
return intent;
}
private void printIntentExtras(Intent intent){
Bundle bundle;
if ((bundle = intent.getExtras()) != null) {
for (String key : bundle.keySet()) {
System.out.println(key + " : " + (bundle.get(key) != null ? bundle.get(key) : "NULL"));
}
}
}
You can check my entire solution here.
I'm using GCM to get notified when an image is posted, and then I download and process it:
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
DataUtils.log("In GcmBroadcastReceiver! threadname is " + Thread.currentThread().getName());
// 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);
}
}
This is the beginning of my GcmIntentService:
public class GcmIntentService extends IntentService
{
public static final int NOTIFICATION_ID = 1;
public GcmIntentService()
{
super("GcmIntentService");
}
#Override
protected void onHandleIntent(Intent intent)
{
DataUtils.log("In GcmIntentService onHandleIntent(), threadname is " + Thread.currentThread().getName());
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))
{
DataUtils.log("In GcmIntentService - Send error: " + extras.toString());
} else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType))
{
DataUtils.log("In GcmIntentService - Deleted messages on server: " + extras.toString());
// If it's a regular GCM message, do some work.
} else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType))
{
String notificationType = extras.getString(MyAppApi.GCM_MSG_TYPE_KEY);
if(DataUtils.isEmpty(notificationType)) {
DataUtils.log("In GcmIntentService - notificationType is empty!");
} else if(notificationType.equalsIgnoreCase(MyAppApi.GCM_IS_NEW_WALLPAPER)) {
//We're about to receive a new image!
DataUtils.log("In GcmIntentService - Receiving a new image!");
processNewWallpaper();
} else if(notificationType.equalsIgnoreCase(MyAppApi.GCM_IS_FRIEND_NOTIFICATION)) {
//We're about to receive a friend notification
DataUtils.log("In GcmIntentService - Receiving a friend notification!");
processFriendNotification();
} else {
//Unknown
DataUtils.log("In GcmIntentService - Receiving unknown message type! " + notificationType);
}
} else {
DataUtils.log("In GcmIntentService - Unknown GCM message: " + extras.toString());
}
}
//Release the wake lock provided by the WakefulBroadcastReceiver.
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
}
It seems that randomly the service will die. From the log:
01-13 20:00:44.436: I/ActivityManager(375): Process com.grakk.android (pid 23227) has died.
01-13 20:00:44.444: W/ActivityManager(375): Scheduling restart of crashed service com.grakk.android/.GcmIntentService in 11426ms
What the code does when it receives a GCM message is to download an image, then it shows the user a notification (this is similar to a normal chat app).
A tester told me that once he received an image but didn't get the notification, which means that the service itself is started and does part of the work, but doesn't complete it.
The notification code is run in processNewWallpaper(), along with the download and processing of the image. Here's the code:
...
if(senderContact == null) {
sendNotification(null, message, true);
} else {
sendNotification(senderContact.getName(), message.trim(), false);
}
...
Notification method:
...
// 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.
#SuppressWarnings("deprecation")
#TargetApi(16)
private void sendNotification(String name, String message, boolean isAnonymous)
{
Context context = GcmIntentService.this;
NotificationManager mNotificationManager = (NotificationManager)this.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, ContactsActivity.class), 0);
Notification.Builder mBuilder = new Notification.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(context.getString(R.string.app_name));
String textToShow = null;
if(DataUtils.isEmpty(message))
{
if(isAnonymous) {
textToShow = context.getString(R.string.notification_text_anonymous);
} else {
textToShow = String.format(getResources().getString(R.string.notification_text_friend), name);
}
} else {
textToShow = message;
}
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
mBuilder.setStyle(new Notification.BigTextStyle().bigText(textToShow));
}
mBuilder.setContentText(textToShow);
mBuilder.setAutoCancel(true);
Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
mBuilder.setSound(alarmSound);
mBuilder.setContentIntent(contentIntent);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
} else {
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.getNotification());
}
}
I am able to reproduce this by sending myself an image, and then pressing the Android back button repeatedly until I am no longer in the app. I can follow the log messages that show that the image is downloaded, however it dies before the notification is shown.
This doesn't always happen. Sometimes the notification is shown, sometimes it's not.
I'm not sure what are probable causes, nor how to debug this. Any tips?
Have you called the OnCreate() in the GcmIntentService class?
Some sample code below:
public class GcmIntentService extends IntentService {
String mes;
private Handler mHandler;
public GcmIntentService() {
super("GcmIntentService");
}
#Override
public void onCreate() {
super.onCreate();
mHandler = new Handler();
}
#Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
String messageType = gcm.getMessageType(intent);
mes = extras.getString("title");
showToast();
Log.i("GCM", "Recevied: (" + messageType + ") " + extras.getString("title"));
GcmReceiver.completeWakefulIntent(intent);
}
public void showToast() {
mHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), mes, Toast.LENGTH_LONG).show();
}
});
}
}
EDIT: Add useful youtube tutorial for GCM here.
Sorry that I'm using answer (I can't comment yet).
I would try extracting the call to sendNotification from processNewWallpaper to right after processNewWallpaper(). If that didn't work you should post your code in processNewWallpaper(). My guess is that in some cases your code crashes inside processNewWallpaper and skips the sendNotification but since its being handled it wouldn't throw anything.
Also I have noticed that apps act differently if they'v been open in background or completely closed (use running apps key and close your app there). If you can consistently reproduce the problem it will be easier to solve it.
Is that all the logcat you have? Any exceptions or stack traces from the "crashed" service?
However, an idea, are you downloading images asynchronously and in a callback creating the notification?
You are releasing the wake lock at the end of onHandleIntent which will be called before any async code is executed. Releasing the wake lock will kill the service if the screen is off.
What you would need to do is conditionally release the wake lock in onHandleIntent only if no async work needs to be done. And in the callback for any async work release the wake lock. Just make sure there's no execution path that doesn't release the wake lock!
Hope that's it!
I am embedding GCM for push notification in my app. I'm facing a very weird problem, on first run I'm not able to get GCM registration token, but when you run my app second time you will get the registration ID printing on the console. I don't know what am I doing worng. Here is what I have done so far.
This is my onCreate() method where I want to print GCM regID:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final String regId = GCMRegistrar.getRegistrationId(this);
GCM_regID = regId;
System.out.println("GCM regId: "+GCM_regID);
Doing the following code inside onCreate():
/**
* Google Cloud Messaging - Getting server Url and device ID to send it
* across Google server for the notification..
*/
mGCMReceiver = new GCMReceiver();
mOnRegisteredFilter = new IntentFilter();
mOnRegisteredFilter.addAction(Constants.ACTION_ON_REGISTERED);
if (Constants.SENDER_ID == null) {
// mStatus.setText("Missing SENDER_ID");
return;
}
if (Constants.SERVER_URL == null) {
// mStatus.setText("Missing SERVER_URL");
return;
}
GCMRegistrar.checkDevice(this);
GCMRegistrar.checkManifest(this);
if (!regId.equals("")) {
sendIdToServer(regId);
} else {
GCMRegistrar.register(getApplicationContext(), Constants.SENDER_ID);
}
sendIdToServer(regId);
}
Sending GCM_regId to server via these method as guided in one of the tutorial:
/**
* GCM - sending the data in json format to server db
* */
public void sendIdToServer(String regId) {
(new SendRegistrationIdTask(regId)).execute();
GCM_regID = regId;
}
private class GCMReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String regId = intent
.getStringExtra(Constants.FIELD_REGISTRATION_ID);
token = regId;
}
}
private final class SendRegistrationIdTask extends
AsyncTask<String, Void, HttpResponse> {
// private String mRegId;
public SendRegistrationIdTask(String regId) {
// mRegId = regId;
}
#Override
protected HttpResponse doInBackground(String... regIds) {
// String url = Constants.SERVER_URL + "/register";
return null;
}
#Override
protected void onPostExecute(HttpResponse response) {
if (response == null) {
return;
}
StatusLine httpStatus = response.getStatusLine();
if (httpStatus.getStatusCode() != 200) {
Log.e(Constants.TAG, "Status: " + httpStatus.getStatusCode());
return;
}
}
}
I don't think so, GCMIntentService class is needed here for my problem. Please look into this and help me in getting out of this issue.
I'm able to print in GCMIntentService class, on onRegistered(). Here it goes:
#Override
protected void onRegistered(Context context, String regId) {
Intent intent = new Intent(Constants.ACTION_ON_REGISTERED);
intent.putExtra(Constants.FIELD_REGISTRATION_ID, regId);
context.sendBroadcast(intent);
}
I have to print the regId on MainActivity, on onCreate().
Registering the device will take some time.. So if you will try to retrieve the registration id immediately after registering the device in onCreate() then every time it will return a null value.. So try to register your device inside onCreate() and retrieve the id in any different activity/Service (You can retrieve the Id from GCMIntentService class the api from GCM). Note method of GCM Intent Service class.
protected void onRegistered(Context arg0, String arg1) {
Logger.d(arg0, "REG ID="+arg1);
regID = arg1;
}
This is method is called after Reg is done.
So for my case the regID i took this as a static string and am accessing it else.
OR Like u want the regID on Activity B it is preferred to Register it on Activity A and retrieve it via the static string in the above method from the GCMIntent Class.
The reason that you are not getting the regID the first time you run your app is because your app does not have a regID yet, it needs to ask the GCM servers for it. So when you call final String regId = GCMRegistrar.getRegistrationId(this); the first time it will return an empty string. However once you have been registered with GCM the next time you make that call (the next time your app starts) your regID will be returned. The GCM jar simply stores the regID as a string in the app prefs.
When the GCM servers register your device, you will know about it when GCMIntentService.OnRegistered() is called. In your code you are broadcasting an intent with your regID in the GCMIntentService.OnRegistered() which I assume you want to handle with your GCMReceiver (?) although in the code sample you have shown I do not see you creating an instance of the class or registering it as a receiver.
What I think you will want to in GCMReceiver.onReceive() is call sendIdToServer() with the regID that you got from the intent. e.g.
#Override
public void onReceive(Context context, Intent intent) {
String regId = intent
.getStringExtra(Constants.FIELD_REGISTRATION_ID);
Log.i("regID: ", regId);
sendIdToServer(regId);
}
We have a GCM/Airbop client sample that you might want to look at. It is based on the GCM Demo app which you should take a look at.
If you are not logged into a Google account in the emulator will not work. Try logging in with a valid account of Google ( gmail ) and see .
I want to implement push notification in Android using Phonegap. I have successfully created an app using https://github.com/marknutter/GCM-Cordova.
I have also created my app id and sender id using https://code.google.com/apis/console/.
Can anyone suggest where I should put these keys in my project?
I also use the plugin.
Not sure about the app id, but the send ID you pass in the function for registering:
GCM.register(STRING_YOUR_SENDER_ID, "GCM_Event", GCM_Success, GCM_Fail );
Check the GCM documentation here, here is a code snippet (I modified a bit from the original example in the documentation):
public class GCMIntentService extends GCMBaseIntentService {
private static final String SENDER_ID = ""; // Your project ID from the API Console
public GCMIntentService() {
super(SENDER_ID);
}
#Override
public void onCreate() {
super.onCreate();
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");
}
}
#Override
protected void onError(Context context, String error) {
}
#Override
protected void onMessage(Context context, Intent message) {
//String value = message.getExtras().getString("message");
}
#Override
protected void onRegistered(Context context, String resId) {
// You should save the resId to use it when sending a message from your server
}
#Override
protected void onUnregistered(Context arg0, String msg) {
// Delete the resId from your server
}
}
To test it you need first to call the above service to register your device with GCM service (and get a registration id that you will use when sending the message), you can do something like:
Intent registrationIntent = new Intent(
"com.google.android.c2dm.intent.REGISTER");
registrationIntent.putExtra("app",
PendingIntent.getBroadcast(context, 0, new Intent(), 0));
// registrationIntent.putExtra("sender", "Your sender id"); // Better than keep the sender id hard coded in the service
context.startService(registrationIntent);
To send a message you can have a simple Java application as below (you can do it from other languages as well):
public static void sendMessage(String msg) throws IOException {
String myApiKey = "Your Browser API Key";
String regId = "Registeration id"; // the value you received in
// onRegistered() in the above
// onRegistered class
Sender sender = new Sender(myApiKey);
Message message = new Message.Builder().addData("message", msg).build();
Result result = sender.send(message, regId, 5); // 5 is the maximum number of trials to deliver your message
if (result.getMessageId() != null) {
System.out.println("Message sent");
String canonicalRegId = result.getCanonicalRegistrationId();
if (canonicalRegId != null) {
// This means that the registration id got updated, so use the new one for future messages
System.out.println("canonicalRegId: " + canonicalRegId);
}
} else {
System.out.println("error: " + result.getErrorCodeName());
}
}
use the plugin
cordova plugin add phonegap-plugin-push --variable SENDER_ID="XXXXXXX"
replace the xxxxxx with your sender id
sender id is the project id/project number in google console
in your javascript add the following code for registering
var push = PushNotification.init({
android: {
senderID: "XXXXXXXX" //add your sender id here
},
ios: {
alert: "true",
badge: "true",
sound: "true"
},
windows: {}
});
push.on('registration', function(data) {
consol.log(data.registrationId); //this function give registration id from the GCM server if you dont want to see it please comment it
document.getElementById("gcm_id").value= data.registrationId; //showing registration id in our app. If it shows our registration process is suscess
//$("#gcm_id").val(data.registrationId); if you are using jquery
});
if you want to get more detail in how to implement push notification in cordova please go through the following link
http://phonegaptut.com/2016/05/31/how-to-send-push-notifications-in-phonegap-application/