推送通知接收器不工作
Posted
技术标签:
【中文标题】推送通知接收器不工作【英文标题】:Push Notification receiver is not working 【发布时间】:2013-07-12 23:36:54 【问题描述】:我正在我的应用程序中实现推送通知服务,我按照教程on android developers.com,但不幸的是,我没有收到任何通知。
我成功接收到注册id,但是设备没有收到后端的任何通知,虽然后端服务收到了成功的响应。
p.s :我确信从将通知发送到 Google 云服务器的后端服务的实现。
谁能帮我解决这个问题..?提前谢谢。
您可以在下面找到我的实现。
Manifest.xml
<?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>
MyReceiver.java
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 意图服务
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);
- PushHandlerActivity
>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);
【问题讨论】:
您在尝试处理推送通知之前是否运行过活动? 是的,我在从后端发送通知之前运行应用程序。 能否在 GCMIntentService 中的 onRegistered 和 onUnregistered 方法中添加日志消息,以了解应用是否连接成功? 两个都进不了,什么时候进..? 那么它一开始就没有注册。您可以显示您注册推送通知的代码吗?特别是你打电话给GoogleCloudMessaging.getInstance(context).register(SENDER_ID);
【参考方案1】:
您的清单中存在包名称不匹配的问题:
应用程序包:
package="com.ettamen.app"
在权限中,您应该使用应用程序的包,但您使用的是:
<permission
android:name="com.ettamen.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.ettamen.permission.C2D_MESSAGE" />
两者都应该是com.ettamen.app.permission.C2D_MESSAGE
。
最后是广播接收器:
<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>
类别应包含您的应用程序包名称,因此应为com.ettamen.app
。
【讨论】:
感谢通知,但是仍然没有进入onRegistered和onUnregistered方法,也没有收到推送通知。 @EslamYousefMohammed 现在我查看了您的代码,我发现它是旧 API 和新 API 的混合体。如果您使用 GCMRegistrar,请不要使用 GoogleCloudMessaging,反之亦然。如果您在后台线程中调用gcm.register
,这就足够了,您不必调用GCMRegistrar.register。使用 GoogleCloudMessaging.register 时,永远不会调用 onRegistered 和 onUnregistered。
我编辑了我的注册方法,并将我的接收器更新为与developers.android.com教程完全匹配。“帖子也更新了”。现在,我成功收到了注册ID,但是,设备没有收到来自后端的任何通知,尽管后端服务收到了成功的响应。
@EslamYousefMohammed 那是因为你忘了把<category android:name="com.ettamen.app.pushnotifications" />
改成<category android:name="com.ettamen.app" />
。
@Eran,您在 GCM 上的回答对我有很大帮助。但是我卡住了,你能看一下吗? my gcm question【参考方案2】:
经过大量试验,我发现问题是接收器可以在您喜欢的任何包中,只要清单中其意图过滤器的类别包含应用程序的主包
感谢大家的帮助和支持。
【讨论】:
【参考方案3】:当您使用 builder 构建通知时,您应该在此处设置传递给 onReceive
方法的意图,而不是您创建的方法:
mBuilder.setContentIntent(contentIntent);
完整代码:
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());
也可以应用于GCMIntentService
类。
【讨论】:
以上是关于推送通知接收器不工作的主要内容,如果未能解决你的问题,请参考以下文章
Firebase 推送通知在纱线手表中工作,但在纱线构建中不工作