使用的jar推送通知无法正常工作 [英] Push notification using jar is not working

查看:130
本文介绍了使用的jar推送通知无法正常工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,请不要使这个问题的重复或其他任何东西,因为所有其他不包括我的问题

我有一个问题,推送通知。我已经实现了我的应用程序推送通知使用 GCM 并做好与它的源$ C ​​$ C。现在,我已经分发给我的 RES 文件夹进行整合。它的工作很好,如果主机应用程序不执行推送通知自己的。如果主机应用程序实施推送通知自己的话我的集成应用程序不会接收推送。

我经历了这个帖子: 注册GCM从库项目

我已经用下面另外的应用程序中,我已经将我的jar:

 <使用-权限的Andr​​oid:名称=android.permission.INTERNET对/>
<使用-权限的Andr​​oid:名称=android.permission.READ_CALENDAR/>
<使用-权限的Andr​​oid:名称=android.permission.WRITE_CALENDAR/>
<! -  GCM需要一个谷歌帐户。 - >
<使用-权限的Andr​​oid:名称=android.permission.GET_ACCOUNTS/>
<! - 进入休眠状态保持处理器接收到消息时。 - >
<使用-权限的Andr​​oid:名称=android.permission.WAKE_LOCK/>
<! - 创建一个自定义权限所以只有这个程序可以接收它的消息。 - >
<许可
    机器人:名称=HOST_APP_PACKAGE.permission.C2D_MESSAGE
    安卓的ProtectionLevel =签名/>
<使用-权限的Andr​​oid:名称=HOST_APP_PACKAGE.permission.C2D_MESSAGE/>
<  - !此应用程序有权限注册并接收数据信息。 - >
<使用-权限的Andr​​oid:名称=com.google.android.c2dm.permission.RECEIVE/>
<! - 网络状态的权限来检测网络状态 - >
<使用-权限的Andr​​oid:名称=android.permission.ACCESS_NETWORK_STATE/>
<! - 权限振动 - >
<使用-权限的Andr​​oid:名称=android.permission.VIBRATE/>
<使用-权限的Andr​​oid:名称=android.permission.WRITE_EXTERNAL_STORAG​​E/>
 

和下面是我的接收器:

 <接收器
      机器人:名称=MY_JAR_APP_PACKAGE.PushLibraryBroadcastReceiver
      机器人:权限=com.google.android.c2dm.permission.SEND>
      <意向滤光器>
          <  - !接收的实际消息。 - >
          <作用机器人:名称=com.google.android.c2dm.intent.RECEIVE/>
          &所述;! - 接收的注册ID。 - >
          <作用机器人:名称=com.google.android.c2dm.intent.REGISTRATION/>
          <类机器人:名称=HOST_APP_PACKAGE/>
      &所述; /意图滤光器>
  < /接收器>
 

我的 PushLibraryBroadcastReceiver 类code。在

 公共类PushLibraryBroadcastReceiver扩展GCMBroadcastReceiver
{
    / **
     *获取意图服务,将处理GCM消息的类名。
     * /
    @覆盖
    保护字符串getGCMIntentServiceClassName(上下文的背景下){
        返回MY_JAR_APP_PACKAGE.GCMIntentService;
    }
}
 

解决方案

根据上述的澄清,则需要每个广播接收机(即磁带库和主机应用程序),以充分利用自身的信息服务和忽略的消息打算用于其它广播接收机。

由于您使用的是不同的发送者ID来在您的图书馆,并在你的主机应用程序注册到GCM,你可以用它来确定哪些信息应该如何处理由广播接收器。

首先,我建议你停止扩展pcated GCMBroadcastReceiver 类去$ P $。我的解决方案依赖于不使用它(虽然你可能能够使通过更改其code它与旧的接收工作)。

然后以下接收机是根据官方<一个新版本href="http://$c$c.google.com/p/gcm/source/browse/gcm-client/GcmClient/src/main/java/com/google/android/gcm/demo/app/GcmBroadcastReceiver.java"相对=nofollow> GCM演示应用。

 公共类PushLibraryBroadcastReceiver扩展WakefulBroadcastReceiver {

    @覆盖
    公共无效的onReceive(上下文的背景下,意图意图){
        如果(intent.getExtras()获得(自)。等于(SENDER_ID_OF_LIBRARY){
          //明确指定GcmIntentService会处理这个意图。
          组件名补偿=新的组件名(
            GcmIntentService.class.getPackage()。的getName(),
            GcmIntentService.class.getName());
          //启动服务,保持设备时推出清醒。
          startWakefulService(上下文,(intent.setComponent(化合物)));
          的setResult code(Activity.RESULT_CANCEL);
        } 其他
          的setResult code(Activity.RESULT_OK);
        }
    }
}
 

我从演示的实现两个转变:

  1. 获得意图服务的包名明确(因为使用 context.getPackageName()将返回主机应用程序的主包,这是不是你所需要的)
  2. 邮件的发件人字段比较图书馆的发件人ID和处理消息,只有当它来自该发件人。一旦消息被处理,结果是由主机应用程序的广播接收器正在处理设置为 Activity.RESULT_CANCEL ,以prevent广播。

如果您停止使用旧GCMBroadcastReceiver,你应该改变你的意图的服务,这样的事情(同样,这是从<一个href="http://$c$c.google.com/p/gcm/source/browse/gcm-client/GcmClient/src/main/java/com/google/android/gcm/demo/app/GcmIntentService.java"相对=nofollow>演示):

 保护无效onHandleIntent(意向意图){
    捆绑额外= intent.getExtras();
    GoogleCloudMessaging GCM = GoogleCloudMessaging.getInstance(本);
    //该getMessageType()的意图参数必须是您收到的意图
    //你的BroadcastReceiver。
    字符串为messageType = gcm.getMessageType(意向);

    如果(!extras.isEmpty()){//具有unparcelling捆绑的效果
        / *
         *根据消息类型过滤消息。因为它是可能的GCM将
         *延伸并与新的消息类型的未来,只是忽略你的任何消息类型
         *不感兴趣,或者说,你不承认。
         * /
        如果(GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(为messageType)){
            sendNotification的(发送错误:+ extras.toString());
        }否则,如果(GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(为messageType)){
            sendNotification的(在服务器上删除的邮件:+ extras.toString());
        //如果这是一个普通的GCM消息,做了一些工作。
        }否则,如果(GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(为messageType)){
            //这个循环再presents服务做一些工作。
            的for(int i = 0;我小于5;我++){
                Log.i(TAG,工作......+(I + 1)
                        +/ 5 @+ SystemClock.elapsedRealtime());
                尝试 {
                    视频下载(5000);
                }赶上(InterruptedException异常E){
                }
            }
            Log.i(TAG,已完成的工作@+ SystemClock.elapsedRealtime());
            收到消息的//邮政通知。
            sendNotification的(收到:+ extras.toString());
            Log.i(TAG,收稿日期:+ extras.toString());
        }
    }
    //释放由WakefulBroadcastReceiver提供的唤醒锁。
    GcmBroadcastReceiver.completeWakefulIntent(意向);
}
 

我假设你的 GCMIntentService 类扩展pcated去$ P $ GCMBaseIntentService 。您应该延长 IntentService 代替,并从的onMessage 将逻辑 onHandleIntent

您也应该切换到注册到GCM,使用 GoogleCloudMessaging.register ,它不需要在意向服务类的任何处理的新途径。所有的处理将在该执行注册的活性来完成,这表现<一个href="http://$c$c.google.com/p/gcm/source/browse/gcm-client/GcmClient/src/main/java/com/google/android/gcm/demo/app/DemoActivity.java"相对=nofollow>这里。

最后,如果主机应用程序的广播接收器不以类似于图书馆的广播接收机(即仅处理邮件是应该处理),你仍然有一个问题,如果主机应用程序的广播接收器被触发在你的图书馆的广播接收器。您可避免添加安卓优先属性两个接收机的意图过滤器,并给予您的图书馆的接收器更高的优先级。这将确保该库的广播接收器总是首先触发。

我必须说,我从来没有测试有两个广播接收器的应用程序,所以我不能保证使用的优先级属性的工作原理,但它应该工作的基础上我阅读文档:

  

有序播放(带Context.sendOrderedBroadcast发送)是   发送到一个接收器的时间。由于每个接收器将执行   转,它可以传播的结果到下一个接收器,或它可以   完全中止该广播,以便它不会被传递到其他   接收器。订单接收器运行在可以与被控制   机器人:匹配意图过滤器的优先级属性;接收器   具有相同优先级可以为任意的顺序来运行。

First of all please don't make this question as duplicate or anything else because all other don't cover my issue.

I have an issue with push notification. I have implemented push notification in my app using gcm and make a jar with its source code. Now I have distributed it with my res folder for integration. Its working fine if host app don't implement push notification its own. If host app implement push notification its own then my integrated app doesn't receive push.

I went through this post : Register GCM from a library project

I have used below addition in the app in which I have integrated my 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" />

And below is my receiver:

<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>

My PushLibraryBroadcastReceiver class code in 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";
    }
}

解决方案

Based on your clarification above, you need each broadcast receiver (that of your library and that of the host app) to take care of its own messages and ignore messages intended for the other broadcast receiver.

Since you are using different sender IDs to register to GCM in your library and in your host app, you can use that to determine which message should be handled by which broadcast receiver.

First of all, I'd suggest that you stop extending the deprecated GCMBroadcastReceiver class. My solution relies on not using it (though you might be able to make it work with the old receiver by changing its code).

Then following receiver is based on the new version of the official 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);
        }
    }
}

I made two changes from the Demo's implementation :

  1. get the package name of the intent service explicitly (since using context.getPackageName() will return the main package of the host app, which is not what you need).
  2. compare the "from" field of the message to the sender ID of the library and handle the message only if it comes from that sender. Once the message is handled, the result is set to Activity.RESULT_CANCEL, to prevent the broadcast from being handled by the broadcast receiver of the host app.

If you stop using the old GCMBroadcastReceiver, you should change your intent service to something like this (again, this is taken from the 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);
}

I'm assuming your GCMIntentService class extends the deprecated GCMBaseIntentService. You should extend IntentService instead, and move the logic from onMessage to onHandleIntent.

You should also switch to the new way of registering to GCM, using GoogleCloudMessaging.register, which doesn't require any handling in the intent service class. All the handling will be done in the activity that performs the registration, as demonstrated here.

Finally, if the broadcast receiver of the host app doesn't behave similarly to your library's broadcast receiver (i.e. handling only the messages it is supposed to handle), you would still have a problem if the host app's broadcast receiver is triggered before your library's broadcast receiver. You can avoid that by adding the android:priority attribute to the intent-filter of both receivers, and giving your library's receiver a higher priority. That would ensure that the library's broadcast receiver is always triggered first.

I must say that I never tested an app with two broadcast receivers, so I can't guarantee that using the priority attribute works, but it should work based on the documentation I read :

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.

这篇关于使用的jar推送通知无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆