GCM Android Push Notification: send OK but not delivered - android

I'm trying to send push notification to android devices. I have not problem to register the ID of the emulator or the devices, but it's impossibile to receive messages also if the send status is 200 OK.
I also try to look to firewall settings, but it's already turned off.
I tried also to use PushBots service from web: same thing. Device registered correctly, message sent, but not delivered to emulator or devices.

It was my mistake. I didn't notice the app was giving me exception when sending push from web for an error in the manifest Receiver.
Implemented the NotificationManager now I receive the push messagge into device.
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Explicitly specify that GcmMessageHandler will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),
GcmMessageHandler.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
#Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
String messageType = gcm.getMessageType(intent);
mes = extras.getString("title");
sendNotification(mes);
sendAlert(mes);
Log.i("GCM", "Received : (" +messageType+") "+extras.getString("title"));
GcmBroadcastReceiver.completeWakefulIntent(intent);
}

Related

Non deprecated GCM Cloud Endpoints example 2016

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.

How can I know the application state of an Android App to display or not a notification?

I am developping an instant messaging application that uses Google Cloud Messaging. I send a notification when a user receive a message from a contact. Everything works properly. I set up the GCMBroadcastReceiver and the GCMMessageHandler. The problem is : the notification is always displaying even if the user is currently chatting with his contact. How can I know the application state in the GCMMessageHandler to not display the notification ?
Here is the GCMBroadcastReceiver :
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Explicitly specify that GcmMessageHandler will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),
GcmMessageHandler.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
Here is the GCMMessageHandler :
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
String messageType = gcm.getMessageType(intent);
mes = extras.getString("message");
if(IM_NOT_IN_THE_CHAT_ACTIVITY)
{
showNotification(mes);
}
What I'm struggling to get is that flag : IM_NOT_IN_THE_CHAT_ACTIVITY.
How can I know this in the IntentService ?
Doing this would do the trick I guess :
ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
List< ActivityManager.RunningTaskInfo > taskInfo = am.getRunningTasks(1);
String activity_name = taskInfo.get(0).topActivity.getClassName();
if(activity_name != ACTIVITY_NAME)
showNotification(mes);

BroadcastReceiver in IntentService in WakefulBroadcastReceiver does not always work

So, I have this problem.
I'm using a dependency project that is some kind of GCM notification parser. It's a bit poorly written, however I'm forced to use it, becase of work related reasons. Anyways:
The main service (that extends IntentService) is launched with WakefulBroadcastReceiver.
After it receives message from GCM I does some magic and sends it to the main App using broadcast.
In main app I'm constantly running service with another BroadcastReceiver that catches messages and saves everything in database etc.
Why is it so complicated? Firstly - originally it was someone else's project and now I'm trying to fix bugs. Secondly - I have no access from dependency to the main application project so I pass messages with broadcasts.
And now, the fun part. I need to filter whether I want to show notification or not. While sending a message to my main AppService I check it with the history of previous messages and then I decide if I need to show this message to User or not. However, no matter what my decision is, my dependency still shows my notification.
So I added yet another broadcast, when after successful validation I launch in my dependency notification building method.
Here is the code:
My WakefulBroadcastReceiver:
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
ComponentName comp = new ComponentName(context.getPackageName(), PushService.class.getName());
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
Here is my Depencency service
public NotificationCheckerReceiver notificationCheckerReceiver;
...
#Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
String messageType = gcm.getMessageType(intent);
if (!extras.isEmpty()) {
if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
//Launch my "approval" receiving broadcast
launchBroadcastReceiver(extras, intent);
//send broadcast to main app with the message we will parse etc.
sendSmsBroadcast(...));
}
}
}
#Override
public void onDestroy() {
unregisterReceiver(notificationCheckerReceiver);
super.onDestroy();
}
//Launch to build notification
public void showNotification(Bundle extras){
...
//Basic notification builder
}
//Receive broadcast from DB if notification was already in the DB
private void launchBroadcastReceiver(Bundle extras, Intent intent){
Log.d(TAG, "Broadcast receiver loaded");
notificationCheckerReceiver = new NotificationCheckerReceiver(new NotiFlag() {
#Override
public void onReceiveApproval(Boolean flag, Intent intent, Bundle extras) {
Log.d(TAG, "Approved notification show");
showNotification(extras);
JustPushGcmBroadcastReceiver.completeWakefulIntent(intent);
}
}, intent, extras);
registerReceiver(notificationCheckerReceiver, new IntentFilter(notificationCheckerReceiver.INTENT_EVENT_NAME));
}
public void sendSmsBroadcast(String message, boolean isAppOnScreen){
...
//This works
}
}
and my "faulty" receiver:
public class NotificationCheckerReceiver extends BroadcastReceiver{
private final String TAG = getClass().getSimpleName();
public static final String INTENT_EVENT_NAME = "NOTIFLAG";
public static final String INTENT_FLAG_KEY = "FLAG";
Intent intent;
Bundle extras;
NotiFlag nofiFlag;
public NotificationCheckerReceiver(NotiFlag nofiFlag, Intent intent, Bundle extras){
Log.d(TAG, "Launched constructor NotificationChecker");
this.nofiFlag = nofiFlag;
this.intent = intent;
this.extras = extras;
}
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Launched onReceive");
Boolean bool = intent.getExtras().getBoolean(INTENT_FLAG_KEY);
Log.d(TAG, "___________Broadcast receiver got something and it is intent: "+bool);
if (bool != false) {
nofiFlag.onReceiveApproval(bool, this.intent, this.extras);
}
}
}
and lastly, what I'm sending from my main service:
public void sendNotificationCheckerBroadcast(Boolean message){
Intent flag = new Intent(NotificationCheckerReceiver.INTENT_EVENT_NAME);
flag.putExtra(NotificationCheckerReceiver.INTENT_FLAG_KEY, message);
DvLogs.d(TAG, "__________Sending intent: "+message);
sendBroadcast(flag);
}
What happens is that eveything to the point where I launch "sendNotificationCheckerBroadcast()". I get that I'm sending some kind of boolean... and that's it.
The funny part is: it SOMETIMES works.
I don't know why, but when for some reason it launches - everything is awesome.
EDIT:
When it works, because sometimes it does, I have this error:
01-15 11:20:22.204 3234-3234/pl.digitalvirgo.lafarge E/ActivityThread﹕ Service com.example.name.PushService has leaked IntentReceiver com.example.name.NotificationCheckerReceiver#43042b50 that was originally registered here. Are you missing a call to unregisterReceiver()?
android.app.IntentReceiverLeaked: Service com.example.name.PushService has leaked IntentReceiver com.example.name.NotificationCheckerReceiver#43042b50 that was originally registered here. Are you missing a call to unregisterReceiver()?
at android.app.LoadedApk$ReceiverDispatcher.<init>(LoadedApk.java:814)
at android.app.LoadedApk.getReceiverDispatcher(LoadedApk.java:610)
at android.app.ContextImpl.registerReceiverInternal(ContextImpl.java:1772)
at android.app.ContextImpl.registerReceiver(ContextImpl.java:1752)
at android.app.ContextImpl.registerReceiver(ContextImpl.java:1746)
at android.content.ContextWrapper.registerReceiver(ContextWrapper.java:479)
at com.example.name.PushService.launchBroadcastReceiver(Unknown Source)
at com.example.name.PushService.onHandleIntent(Unknown Source)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:157)
at android.os.HandlerThread.run(HandlerThread.java:61)
Maybe it's somehow related?
I know that I should unRegister this Receiver ... somewhere. Tried onStop, but as we can see - no success.
Edit2:
Weird.
I believe, that the problem is in onStop() method. Probably it's called too early (?) so my Receiver has no chance to work. When I launch app without unRegister everything works. Of course I get bug above, but still... it's something.
Any ideas guys?
Well. The problem was inside the idea of IntentService.
intentService kills itself after onHandleIntent() method.
So the solution for this problem is to change IntentService into Service remembering to handle stopping this thing.

Android device performance drop when display is off

I am currently developing an app that uses GCM to send a notification to a number of devices that starts a service to start polling a RabbitMQ message queue and do some processing on each message received. I am using a WakefulBroadcastReceiver to keep the device awake once the service has started but I am seeing a significant performance hit if the device(s) screens are off as opposed to if I keep them on. I have also unchecked the 'Wi-Fi Optimization' option and made sure that 'Keep Wi-Fi on during sleep' is set to Always.
Is there something else I am missing? The service doesn't stop completely, it just slows down whenever the screen goes off. Whether I press the standby button or I let it go off after the set time. The devices are running a mix of Jelly Bean (4.2.2) and Kit Kat (4.4.2)
Thanks in advance!
Added code snippets below. The Worker class mentioned just calls another class that performs some data processing:
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(), GcmIntentServicece.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
Intent Service 'onHandleIntent' method
#Override
protected void onHandleIntent(Intent intent)
{
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
String messageType = gcm.getMessageType(intent);
if (!extras.isEmpty())
{
if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType))
{
String message = extras.getString("message");
if (message.equals(START_PROCESSING))
{
Worker worker = new Worker(this, queueServerUrl, Integer.parseInt(queueServerPort), queueName, fileServerUrl);
Map<String, Integer> results = worker.StartWorking();
// Update the results
update(results, jobId);
}
}
}
// Release the wake lock provided by the WakefulBroadcastReceiver.
GcmBroadcastReceiver.completeWakefulIntent(intent);
}

Stop IntentService from inside my application?

I'm building some kind of chat program that uses GCM to notify the user that a message is available. I followed the gcm client example using a WakefulBroadcastReceiver and IntentService and everything works as expected.
The BroadcastReceiver:
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);
}
}
and the IntentService:
public class GcmIntentService extends IntentService {
public static final int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
public GcmIntentService() {
super("GcmIntentService");
}
public static final String TAG = "IOAN";
#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
if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
// Post notification of received message.
sendNotification(extras.getString("sender"), extras.getString("message"));
Log.i(TAG, "Received: " + extras.toString());
}
}
// Release the wake lock provided by the WakefulBroadcastReceiver.
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
//... more stuff
}
So the IntentService sends a notification to my application.
Now, when the user closes my application (back button -> are you sure you want to exit? -> yes), I want to also have a check box "do you still want to receive messages?" (or something like that), and if the user chooses not to receive messages, I want to stop the service that handles the gcm message and restart it when the app runs again.
How do I do that?
Edit: I tried stopService(new Intent(MainActivity.this,GcmIntentService.class)); but I still get the notifications.
Edit 2: Seems like a boolean value in SharedPreferences works fine... any better solution?

Categories

Resources