首先,请不要将此问题作为重复问题或其他任何问题,因为所有其他问题均未涵盖我的问题。
我有一个关于推送通知
的问题。我已经使用 gcm
在我的应用程序中实现了 push notification
并使用其源代码制作了一个 jar
。现在我已将它与我的 res
文件夹一起分发以进行集成。如果主机应用程序不实现自己的推送通知
,它工作正常。如果主机应用自己实现推送通知
,那么我的集成应用不会收到推送。
我浏览了这篇文章: Register GCM from a library project
我在集成了我的 jar 的应用程序中使用了以下添加:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_CALENDAR" /> <uses-permission android:name="android.permission.WRITE_CALENDAR" /> <!-- 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="HOST_APP_PACKAGE.permission.C2D_MESSAGE" android:protectionLevel="signature" /> <uses-permission android:name="HOST_APP_PACKAGE.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.WRITE_EXTERNAL_STORAGE" />
下面是我的接收器:
<receiver android:name="MY_JAR_APP_PACKAGE.PushLibraryBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND" > <intent-filter> <!-- Receives the actual messages. --> <action android:name="com.google.android.c2dm.intent.RECEIVE" /> <!-- Receives the registration id. --> <action android:name="com.google.android.c2dm.intent.REGISTRATION" /> <category android:name="HOST_APP_PACKAGE" /> </intent-filter> </receiver>
jar
中我的PushLibraryBroadcastReceiver
类代码:
public class PushLibraryBroadcastReceiver extends GCMBroadcastReceiver { /** * Gets the class name of the intent service that will handle GCM messages. */ @Override protected String getGCMIntentServiceClassName(Context context) { return "MY_JAR_APP_PACKAGE.GCMIntentService"; } }
最佳答案
根据您上面的说明,您需要每个广播接收器(您的库的接收器和主机应用程序的接收器)处理自己的消息并忽略用于其他广播接收器的消息。
由于您在库和主机应用程序中使用不同的发送者 ID 注册到 GCM,因此您可以使用它来确定哪个消息应由哪个广播接收器处理。
首先,我建议您停止扩展已弃用的 GCMBroadcastReceiver
类。我的解决方案依赖于不使用它(尽管您可以通过更改其代码使其与旧接收器一起使用)。
那么下面的receiver是基于官方的新版本GCM Demo App .
public class PushLibraryBroadcastReceiver extends WakefulBroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getExtras ().get("from").equals (SENDER_ID_OF_LIBRARY) {
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(
GcmIntentService.class.getPackage().getName(),
GcmIntentService.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_CANCEL);
} else
setResultCode(Activity.RESULT_OK);
}
}
}
我对演示的实现做了两处更改:
- 显式获取 Intent 服务的包名称(因为使用
context.getPackageName()
将返回宿主应用程序的主包,这不是您需要的)。 - 将消息的“发件人”字段与库的发件人 ID 进行比较,仅当消息来自该发件人时才处理该消息。处理消息后,结果将设置为
Activity.RESULT_CANCEL
,以防止广播被主机应用程序的广播接收器处理。
如果你停止使用旧的 GCMBroadcastReceiver,你应该将你的 Intent 服务更改为这样的东西(同样,这取自 demo ):
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);
}
我假设您的 GCMIntentService
类扩展了已弃用的 GCMBaseIntentService
。您应该改为扩展 IntentService
,并将逻辑从 onMessage
移至 onHandleIntent
。
您还应该切换到使用 GoogleCloudMessaging.register
注册到 GCM 的新方法,它不需要在 Intent 服务类中进行任何处理。所有处理都将在执行注册的 Activity 中完成,如所示 here .
最后,如果主机应用程序的广播接收器的行为与您的图书馆的广播接收器不同(即只处理它应该处理的消息),如果主机应用程序的广播接收器被触发,您仍然会遇到问题在图书馆的广播接收器之前。您可以通过将 android:priority
属性添加到两个接收器的 intent-filter 并为您的库的接收器提供更高的优先级来避免这种情况。这将确保图书馆的广播接收器始终首先被触发。
我必须说我从未测试过带有两个广播接收器的应用程序,所以我不能保证使用优先级属性有效,但根据我阅读的文档它应该有效:
Ordered broadcasts (sent with Context.sendOrderedBroadcast) are delivered to one receiver at a time. As each receiver executes in turn, it can propagate a result to the next receiver, or it can completely abort the broadcast so that it won't be passed to other receivers. The order receivers run in can be controlled with the android:priority attribute of the matching intent-filter; receivers with the same priority will be run in an arbitrary order.
关于android - 使用 jar 的推送通知不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23126646/