使用jar的推送通知无效

时间:2014-04-17 07:04:03

标签: android push-notification google-cloud-messaging

首先,请不要将此问题视为重复或其他任何内容,因为所有其他问题都不能解决我的问题

push notification存在问题。我已使用push notification在我的应用中实施了gcm,并使用其源代码制作了jar。现在我已将其与我的res文件夹一起分发以进行集成。如果主机应用程序没有自己实现push notification,它的工作正常。如果主机应用程序实现了push notification,那么我的集成应用程序就无法获得推送。

我仔细阅读了这篇文章: 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>

PushLibraryBroadcastReceiver中的jar类代码:

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";
    }
}

1 个答案:

答案 0 :(得分:2)

根据您的上述说明,您需要每个广播接收器(您的库和主机应用程序的接收器)处理自己的消息并忽略用于其他广播接收器的消息。

由于您使用不同的发件人ID注册到库中和主机应用程序中的GCM,您可以使用它来确定哪个消息应该由哪个广播接收器处理。

首先,我建议您停止扩展已弃用的GCMBroadcastReceiver类。我的解决方案依赖于不使用它(尽管您可以通过更改其代码使其与旧接收器一起使用)。

然后关注接收者是基于新版官方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);
        }
    }
}

我从Demo的实现中做了两处更改:

  1. 显式获取目标服务的包名称(因为使用context.getPackageName()将返回主机应用程序的主程序包,这不是您需要的。)
  2. 比较&#34;来自&#34;消息的字段到库的发件人ID,并且仅当消息来自该发件人时才处理该消息。处理完消息后,结果将设置为Activity.RESULT_CANCEL,以防止主机应用程序的广播接收器处理广播。
  3. 如果您停止使用旧的GCMBroadcastReceiver,您应该将意图服务更改为类似的内容(同样,这取自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的新方式,android:priority在意图服务类中不需要任何处理。所有处理都将在执行注册的活动中完成,如here所示。

    最后,如果主机应用程序的广播接收器的行为与您的图书馆广播接收器的行为类似(即只处理它应该处理的消息),那么如果主机应用程序的广播接收器在您的图书馆广播接收器之前被触发。您可以通过将{{1}}属性添加到两个接收器的intent-filter,并为您的库的接收器提供更高的优先级来避免这种情况。这将确保首先触发图书馆的广播接收器。

    我必须说我从未测试过有两个广播接收器的应用程序,因此我无法保证使用优先级属性,但它应该基于我读过的文档工作:

      

    有序广播(与Context.sendOrderedBroadcast一起发送)是   一次送到一个接收器。当每个接收器执行时   转,它可以将结果传播到下一个接收器,或者它可以   完全中止广播,以便它不会被传递给其他人   接收器。运行的订单接收器可以用   android:匹配的intent-filter的priority属性;接收器   具有相同优先级的将以任意顺序运行。