android - 使用 jar 的推送通知不起作用

标签 android push-notification google-cloud-messaging

首先,请不要将此问题作为重复问题或其他任何问题,因为所有其他问题均未涵盖我的问题

我有一个关于推送通知的问题。我已经使用 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);
        }
    }
}

我对演示的实现做了两处更改:

  1. 显式获取 Intent 服务的包名称(因为使用 context.getPackageName() 将返回宿主应用程序的主包,这不是您需要的)。
  2. 将消息的“发件人”字段与库的发件人 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/

相关文章:

Android 4.0.1 打破了 WebView HTML 5 本地存储?

ios 10 推送通知媒体附件随机不起作用

google-cloud-messaging - Android GCM 主题订阅限制

Android GCM - 向 registration_ids 数组中的每个用户发送不同的有效负载

Android:当 Dalvik 杀死此 Activity 时,不会调用 Activity.onDestroy()

android - 我的应用程序注册 Activity (我创建的)在我的设备上不完全可见(从底部截取)

android - DPI有点迷失

PHP 苹果增强通知

javascript - 推送通知 channel Azure JS 后端

android - Firebase 云消息传递设备 ID : multiple user in same app in same device