【问题标题】:Weird push message received on app start应用启动时收到奇怪的推送消息
【发布时间】:2015-08-09 08:37:50
【问题描述】:

我的推送服务捕获了一条奇怪的推送消息:

Bundle[{CMD=RST_FULL, from=google.com/iid, android.support.content.wakelockid=1}]

昨天才开始发生,我真的无法确定是哪个代码更改造成的。有没有人以前看过这条消息,也许知道它来自哪里以及为什么?

【问题讨论】:

  • 您能否详细说明...这是您收到的日志消息吗?您是否在使用某些第三方 API 或库?
  • 上面的 Bundle 是来自调试器的复制/粘贴——它是我用接收器捕获的意图中的一个对象。我用intent.getExtras() 得到它,期待一个类型和一个消息,而不是得到上面的地图。我正在使用一些第三方库,例如 Picasso 和 Okhttp,但在这方面没有什么太晦涩难懂的地方。不使用除 Google 之外的任何第三方 API(分析、存储、gcm)
  • 另外,我似乎只在应用程序的第一次运行时收到此消息。强制停止应用并清除数据不会使消息重新出现
  • 它似乎也只发生在调试版本上(正如你所说,在第一次运行时)。我认为我更新谷歌播放服务库可能会导致这种情况,但我尝试了几个版本(7327000、6171000、5089000、4323030、4242000 和 4132500)有/没有互联网连接,并且每次第一次运行时都会重现,在调试版本中...此外,意图操作是“com.google.android.c2dm.intent.RECEIVE”
  • 我收到了同样的信息,似乎是一个新的“功能”

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


【解决方案1】:

我今天意识到了同样的问题。首先,此消息必须来自 google 本身(from=google.com/iid),否则 from 属性将是您的项目在 google 开发者控制台中的 id(即 475832179747)。但可以肯定的是,我关闭了我们的应用服务器,我仍然收到了消息。

当我在 Google Cloud Messaging 服务器上新注册时,我总是会收到它。这不是一个大问题,因为您可以通过意图操作过滤消息,但我真的很想知道它的目的。

【讨论】:

    【解决方案2】:

    至少在华硕平板电脑上也发生了同样的事情

    可能在更多设备上,但我没有机会查看

    我正在 Intent.getExtras() 中寻找一些特定的字符串,所以修复很简单,如果它们不存在则忽略整个事情。

    来自 Google 的人员出现并解释发生了什么的可能性有多大?

    【讨论】:

    • Google 人员出现并解释发生了什么的可能性有多大? - 那就太好了……
    【解决方案3】:

    对于扩展 WakefulBroadcastReceiver 的现有应用,Google 建议迁移到 GCMReceiver 和 GcmListenerService。到 迁移:

    • 在应用清单中,将您的 GcmBroadcastReceiver 替换为“com.google.android.gms.gcm.GcmReceiver”,并替换当前 将 IntentService 扩展到新的服务声明 GcmListenerService
    • 从您的客户端代码中删除 BroadcastReceiver 实现
    • 重构当前 IntentService 服务实现以使用 GcmListenerService 详情请参见示例清单。

    谷歌似乎将 GCMIntentService 拆分为两个服务,它扩展了 IntentService 以处理 gcms,一个扩展了 GcmListenerService 来处理接收到的消息,另一个则分别过滤 iid.InstanceID 以过滤掉首次安装时收到的通知, 这是来自新的 gcm android 指南

    <service
        android:name="com.example.MyGcmListenerService"
        android:exported="false" >
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        </intent-filter>
    </service>
    <service
        android:name="com.example.MyInstanceIDListenerService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.android.gms.iid.InstanceID"/>
        </intent-filter>
    </service>
    

    https://developers.google.com/cloud-messaging/android/client

    【讨论】:

      【解决方案4】:

      您的应用收到此消息是因为它已从备份中恢复了数据。由于备份可能包含注册令牌,因此会发送此广播通知您的应用获取新令牌,因为备份的令牌将不起作用。

      这适用于新的GCM APIs,它将导致调用您的 InstanceIdListenerService 实现的 onTokenRefresh() 方法,您的应用应再次获取其所有令牌。

      很遗憾,如果您正在编写自己的 BroadcastReceiver,这些消息将出乎意料,并可能导致您的应用崩溃。正确的做法是过滤“发件人”字段,如果您看到其中一条消息,请再次向 GCM 注册,因为您的令牌可能无效。

      如果您在重新安装应用数据正在恢复的情况下收到这些消息,请发布到android-gcm 邮件列表。

      【讨论】:

      • 你答案的备份部分不清楚。为什么即使应用程序清单通过将 allowBackup 设置为 false 来明确禁止备份,也会出现这样的通知?
      • @GiulioPiancastelli 根据GCM Sample Code中的cmets,这个令牌刷新通知是Called if InstanceID token is updated. This may occur if the security of the previous token had been compromised.
      • @mpkuth 抱歉,我看不出安全性受损可能与我想讨论的从备份恢复数据用例有什么关系。
      • @GiulioPiancastelli 在链接的示例代码中,MyInstanceIDListenerService 用于处理来自 google.com/iid 的通知。该文件中的 cmets 似乎表明无论出于何种原因更新令牌时都会发送相关通知,而不仅仅是从备份中恢复。它将安全性受损列为可能的原因,但似乎并未排除任何其他原因。
      • @mpkuth 哦,对,我明白了。感谢您的澄清!
      【解决方案5】:

      按照@morepork 的建议查看更新后的GCM API Docs

      对于扩展 WakefulBroadcastReceiver 的现有应用,Google 建议迁移到 GCMReceiver 和 GcmListenerService。到 迁移:

      在应用清单中,将您的 GcmBroadcastReceiver 替换为“com.google.android.gms.gcm.GcmReceiver”,并将当前将 IntentService 扩展为新 GcmListenerService 的服务声明替换

      从您的客户端代码中删除 BroadcastReceiver 实现

      重构当前 IntentService 服务实现以使用 GcmListenerService

      有关详细信息,请参阅此页面中的示例清单和代码示例。

      从他们的sample code,很容易理解。

      AndroidManifest.xml

      <receiver
          android:exported="true"
          android:name="com.google.android.gms.gcm.GcmReceiver"
          android:permission="com.google.android.c2dm.permission.SEND">
          <intent-filter>
              <action android:name="com.google.android.c2dm.intent.RECEIVE"/>
              <category android:name="com.example.client"/>
          </intent-filter>
      </receiver>
      
      <service
          android:name=".MyGcmListenerService"
          android:exported="false">
          <intent-filter>
              <action android:name="com.google.android.c2dm.intent.RECEIVE"/>
          </intent-filter>
      </service>
      
      <service
          android:name=".MyInstanceIdListenerService"
          android:exported="false">
          <intent-filter>
              <action android:name="com.google.android.gms.iid.InstanceID"/>
          </intent-filter>
      </service>
      
      <service
          android:name=".MyGcmRegistrationService"
          android:exported="false">
      </service>
      

      MyGcmListenerService.java

      public class MyGcmListenerService extends GcmListenerService {
          @Override
          public void onMessageReceived(String from, Bundle data) {
              final String message = data.getString("message");
              makeNotification(message);
          }
      }
      

      MyGcmRegistrationService.java

      public class MyGcmRegistrationService extends IntentService {
          private static final String TAG = "MyRegistrationService";
          private static final String GCM_SENDER_ID = "XXXXXXXXXXXX";
          private static final String[] TOPICS = {"global"};
      
          public MyGcmRegistrationService() {
              super(TAG);
          }
      
          @Override
          protected void onHandleIntent(Intent intent) {
              try {
                  synchronized (TAG) {
                      InstanceID instanceID = InstanceID.getInstance(this);
                      String token = instanceID.getToken(GCM_SENDER_ID,
                              GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
                      sendTokenToServer(token);
                      subscribeTopics(token);
                  }
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      
          private void subscribeTopics(String token) throws IOException {
              for (String topic : TOPICS) {
                  GcmPubSub pubSub = GcmPubSub.getInstance(this);
                  pubSub.subscribe(token, "/topics/" + topic, null);
              }
          }
      }
      

      MyInstanceIdListenerService.java

      public class MyInstanceIdListenerService extends InstanceIDListenerService {
          public void onTokenRefresh() {
              Intent intent = new Intent(this, MyGcmRegistrationService.class);
              startService(intent);
          }
      }
      

      然后您可以将旧的注册码替换为

      Intent intent = new Intent(this, MyGcmRegistrationService.class);
      startService(intent);
      

      【讨论】:

      【解决方案6】:

      我在迁移 GCM->FCM 时遇到了这个问题,仅从以下位置接收 wakelockid 元素:

      • firebase 控制台
      • 由邮递员复制请求,请求如下:

      { "to": "<your token from FirebaseInstanceId.getInstance().getToken()>", "notification": { "body": "Hello", "title": "This is test message." } }

      我还从 google quickstart firebase messaging 复制了所有代码。 一切都应该没问题。但是,经过所有测试后,我决定仔细检查我的 gradle libs 版本。所以我将它们增加到最新的数字。从那时起,我开始正确接收消息。

      我建议从 GitHub 下载项目并尝试这是否适合您的最快解决方案。下一步是将此代码复制到您的项目中。如果在一个项目中一切正常,您至少有一个站立/工作点可以开始。

      有传言说 android studio 导致了这个问题 - 但事实并非如此。我查过了。

      确实,您可以使用相同的旧令牌(来自 gcm)而不接收消息,但如果您有与我一样的情况,即 migrating,那么令牌应该刷新为新令牌并且您应该处理它..

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-28
        • 1970-01-01
        • 2020-07-16
        • 2012-10-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多