Reputation: 332
I'm implementing push notification service i my app, I followed the tutorial on Android developers.com, but unfortunately, i did not receive any notifications.
I'm receiving the registration id successfully, but,the device doesn't receive any notifications from the back end, although the back ed service receives a successful response.
p.s : I'm sure from the implementation of the back end service that sends the notification to Google cloud servers.
Could any one help me solving this problem..?, thanks in advance.
Below you can find my implementation.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ettamen.app"
android:versionCode="1"
android:versionName="1.0" >
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:resizeable="true"
android:smallScreens="true"
android:xlargeScreens="true" />
<!-- GCM connects to Internet Services. -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- GCM requires a Google account. -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<!-- Keeps the processor from sleeping when a message is received. -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- Creates a custom permission so only this app can receive its messages. -->
<permission
android:name="com.ettamen.app.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.ettamen.app.permission.C2D_MESSAGE" />
<!-- This app has permission to register and receive data message. -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<!-- Network State Permissions to detect Internet status -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Permission to vibrate -->
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.SEND_SMS" />
<application
android:hardwareAccelerated="true"
android:icon="@drawable/icon"
android:label="@string/app_name" >
<activity
android:name="Ettamen"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale"
android:label="@string/app_name"
android:theme="@android:style/Theme.Black.NoTitleBar" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name="com.ettamen.app.pushnotifications.CordovaGCMBroadcastReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.ettamen.app.pushnotifications" />
</intent-filter>
</receiver>
<service android:name="com.ettamen.app.pushnotifications.GCMIntentService" >
</service>
<activity android:name=".pushnotifications.PushHandlerActivity" >
</activity>
<service android:name="LocationUpdateService" >
</service>
</application>
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
</manifest>
import com.ettamen.app.R;
import com.google.android.gms.gcm.GoogleCloudMessaging;
/*
* Implementation of GCMBroadcastReceiver that hard-wires the intent service to be
* com.plugin.gcm.GCMIntentService, instead of your_package.GCMIntentService
*/
public class CordovaGCMBroadcastReceiver extends BroadcastReceiver {
static final String TAG = "GCMDemo";
public static final int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
Context ctx;
@Override
public void onReceive(Context context, Intent intent) {
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
ctx = context;
String messageType = gcm.getMessageType(intent);
if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
sendNotification("Send error: " + intent.getExtras().toString());
} else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED
.equals(messageType)) {
sendNotification("Deleted messages on server: "
+ intent.getExtras().toString());
} else {
sendNotification("Received: " + intent.getExtras().toString());
}
setResultCode(Activity.RESULT_OK);
}
// Put the GCM message into a notification and post it.
private void sendNotification(String msg) {
mNotificationManager = (NotificationManager) ctx
.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(ctx, 0,
new Intent(ctx, PushHandlerActivity.class), 0);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
ctx).setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("GCM Notification")
.setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
.setContentText(msg);
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
}
GCM Intent Service
import android.app.ActivityManager.RunningTaskInfo;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
public class GCMIntentService extends GCMBaseIntentService {
public static final int NOTIFICATION_ID = 237;
private static final String TAG = "GCMIntentService";
public GCMIntentService() {
super("GCMIntentService");
}
@Override
public void onRegistered(Context context, String regId) {
}
@Override
public void onUnregistered(Context context, String regId) {
}
@Override
protected void onMessage(Context context, Intent intent) {
Log.d(TAG, "onMessage - context: " + context);
// Extract the payload from the message
Bundle extras = intent.getExtras();
if (extras != null) {
createNotification(context, extras);
}
}
public void createNotification(Context context, Bundle extras) {
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
String appName = getAppName(this);
Intent notificationIntent = new Intent(this, PushHandlerActivity.class);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
notificationIntent.putExtra("pushBundle", extras);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
context).setSmallIcon(context.getApplicationInfo().icon)
.setWhen(System.currentTimeMillis()).setContentTitle(appName)
.setTicker(appName).setContentIntent(contentIntent);
String message = extras.getString("message");
if (message != null) {
mBuilder.setContentText(message);
} else {
mBuilder.setContentText("<missing message content>");
}
String msgcnt = extras.getString("msgcnt");
if (msgcnt != null) {
mBuilder.setNumber(Integer.parseInt(msgcnt));
}
mNotificationManager.notify((String) appName, NOTIFICATION_ID,
mBuilder.build());
tryPlayRingtone();
}
private void tryPlayRingtone() {
try {
Uri notification = RingtoneManager
.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone r = RingtoneManager.getRingtone(getApplicationContext(),
notification);
r.play();
} catch (Exception e) {
Log.e(TAG, "failed to play notification ringtone");
}
}
public static void cancelNotification(Context context) {
NotificationManager mNotificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.cancel((String) getAppName(context),
NOTIFICATION_ID);
}
private static String getAppName(Context context) {
CharSequence appName = context.getPackageManager().getApplicationLabel(
context.getApplicationInfo());
return (String) appName;
}
public boolean isInForeground() {
ActivityManager activityManager = (ActivityManager) getApplicationContext()
.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> services = activityManager
.getRunningTasks(Integer.MAX_VALUE);
if (services.get(0).topActivity
.getPackageName()
.toString()
.equalsIgnoreCase(
getApplicationContext().getPackageName().toString()))
return true;
return false;
}
@Override
public void onError(Context context, String errorId) {
Log.e(TAG, "onError - errorId: " + errorId);
}
}
package com.ettamen.app.pushnotifications;
import com.ettamen.app.PushNotificationWorker;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
public class PushHandlerActivity extends Activity {
private static String TAG = "PushHandlerActivity";
/*
* this activity will be started if the user touches a notification that we
* own. We send it's data off to the push plugin for processing. If needed,
* we boot up the main activity to kickstart the application.
*
* @see android.app.Activity#onCreate(android.os.Bundle)
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v(TAG, "onCreate");
boolean isPushPluginActive = PushNotificationWorker.isActive();
if (!isPushPluginActive) {
forceMainActivityReload();
}
// processPushBundle(isPushPluginActive);
GCMIntentService.cancelNotification(this);
finish();
}
/**
* Takes the pushBundle extras from the intent, and sends it through to the
* PushPlugin for processing.
*/
private void processPushBundle(boolean isPushPluginActive) {
// Bundle extras = getIntent().getExtras();
//
// if (extras != null) {
//
// Bundle originalExtras = extras.getBundle("pushBundle");
//
// if ( !isPushPluginActive ) {
// originalExtras.putBoolean("coldstart", true);
// }
//
// PushPlugin.sendExtras(originalExtras);
// }
}
/**
* Forces the main activity to re-launch if it's unloaded.
*/
private void forceMainActivityReload() {
PackageManager pm = getPackageManager();
Intent launchIntent = pm
.getLaunchIntentForPackage(getApplicationContext()
.getPackageName());
startActivity(launchIntent);
}
}
private void getRegID(CallbackContext ctx) {
new AsyncTask<CallbackContext, Void, String>() {
CallbackContext context;
@Override
protected String doInBackground(CallbackContext... params) {
// TODO Auto-generated method stub
context = params[0];
String regid = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(cordova
.getActivity());
}
regid = gcm.register(Constants.SENDER_ID);
} catch (IOException ex) {
Log.d("Exceptio:", ex.getMessage());
}
String message = "{\"ChannelURI\":\"" + regid + "\"}";
return message;
};
protected void onPostExecute(String result) {
try {
JSONObject jResult = new JSONObject(result);
context.success(jResult);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.execute(ctx);
}
Upvotes: 2
Views: 8920
Reputation: 10803
When you are building the notificaiton with builder, you should set the intent passed to the onReceive
method, not the one you created, here:
mBuilder.setContentIntent(contentIntent);
Complete code:
import com.ettamen.app.R;
import com.google.android.gms.gcm.GoogleCloudMessaging;
/*
* Implementation of GCMBroadcastReceiver that hard-wires the intent service to be
* com.plugin.gcm.GCMIntentService, instead of your_package.GCMIntentService
*/
public class CordovaGCMBroadcastReceiver extends BroadcastReceiver {
static final String TAG = "GCMDemo";
public static final int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
Context ctx;
@Override
public void onReceive(Context context, Intent intent) {
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
ctx = context;
String messageType = gcm.getMessageType(intent);
if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
sendNotification("Send error: " + intent.getExtras().toString(), intent);
} else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED
.equals(messageType)) {
sendNotification("Deleted messages on server: "
+ intent.getExtras().toString(), intent);
} else {
sendNotification("Received: " + intent.getExtras().toString(), intent);
}
setResultCode(Activity.RESULT_OK);
}
// Put the GCM message into a notification and post it.
private void sendNotification(String msg, Intent intent) {
mNotificationManager = (NotificationManager) ctx
.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
ctx).setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("GCM Notification")
.setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
.setContentText(msg);
mBuilder.setContentIntent(intent); // here passing the valid intent
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
}
It can be applied to the class GCMIntentService
too.
Upvotes: 0
Reputation: 332
After a lot of trials, i found out the problem which was that The receiver can be in whatever package you like, as long as the category of its intent filter in the manifest holds the application's main package
Thank you all for your help and support.
Upvotes: 0
Reputation: 394016
There are package name mismatches throughout your manifest :
The package of the app :
package="com.ettamen.app"
In the permissions, you should use the package of the app, but instead you used :
<permission
android:name="com.ettamen.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.ettamen.permission.C2D_MESSAGE" />
Both should be com.ettamen.app.permission.C2D_MESSAGE
.
Finally, the broadcast receiver :
<receiver
android:name="com.ettamen.app.pushnotifications.CordovaGCMBroadcastReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.ettamen.app.pushnotifications" />
</intent-filter>
</receiver>
The category should contain your app package name, so it should be com.ettamen.app
.
Upvotes: 1