【问题标题】:Android GCM and multiple tokensAndroid GCM 和多个令牌
【发布时间】:2014-06-11 04:29:32
【问题描述】:

我在 GCM 中注册 GoogleCloudMessaging.getInstance(context);并将收到的令牌保存在设备上。然后将其发送到服务器并与用户帐户相关联。如果我在没有注销的情况下卸载我的应用程序并再次安装并使用另一个用户登录,我会收到新的令牌并将其发送到服务器。当推送被发送给第一个用户时,我会在第二个用户登录时看到它们。

为什么 GCM 会向我发送不同的令牌,我该如何处理?

【问题讨论】:

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


【解决方案1】:

当您发送通知时首先发送用户 ID 并询问 ID 是否在 sharedpreference == comming 中或没有

如果您向所有用户发送通知,并且可能有人收到 2 条通知,而他应该只收到 1 条通知

在您的服务器上创建文件并使用任何数字说 0 然后当您要发送通知时发送此数字然后将其添加到此数字++ 在下一个通知中成为新号码,与每个新号码相同

在android应用程序中添加变量并让这个变量=添加通知后来自服务器的comming变量 但你需要问if(number_in_your_service!=server_number) //添加通知

您只发送一个的任意数量的通知都会出现

public class GcmIntentService extends IntentService {
  public static int openintent;
  public static final int NOTIFICATION_ID = 1;
  private static final String TAG = "GcmIntentService";

  private static String number_in_your_service="somethingneversend";
  NotificationCompat.Builder builder;

  public GcmIntentService() {
    super("GcmIntentService");
  }

  @Override
  protected void onHandleIntent(Intent intent) {
    Bundle extras = intent.getExtras();
    GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
    String messageType = gcm.getMessageType(intent);

    if (!extras.isEmpty()) { // has effect of unparcelling Bundle
      if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
      } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) {
        // 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(100);
          } catch (InterruptedException e) {
          }
        }
        Log.i(TAG, "Completed work @ " + SystemClock.elapsedRealtime());
        // Post notification of received message.
        sendNotification(extras);
        Log.i(TAG, "Received: " + extras.toString());
      }
    }
    // Release the wake lock provided by the WakefulBroadcastReceiver.
    GcmBroadcastReceiver.completeWakefulIntent(intent);
  }

  private void sendNotification(Bundle extras) {

    if((extras.getString("server_number")).equals(number_in_your_service)) {

      Intent intent = new Intent(this, Main_Page_G.class);
      intent.putExtra("frame",100);
      intent.putExtra("bundle",extras);
      final PendingIntent contentIntent = PendingIntent.getActivity(this,
            120, intent, PendingIntent.FLAG_UPDATE_CURRENT);
      NotificationManager mNotificationManager;
      NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
            GcmIntentService.this).setContentTitle("name")
            .setContentText("content")
            .setDefaults(Notification.DEFAULT_SOUND)
            .setContentInfo("Test")
            .setSmallIcon(R.drawable.rehablogo2)
            .setAutoCancel(true);
      mBuilder.setContentIntent(contentIntent);
      mNotificationManager = (NotificationManager) GcmIntentService.this
            .getSystemService(Context.NOTIFICATION_SERVICE);
      mNotificationManager.notify(id, mBuilder.build());
      id=Integer.parseInt(extras.getString("id"));
    }
  }
}

【讨论】:

    【解决方案2】:

    向多个设备发送推送通知与我们向单个设备发送相同。 只需将所有注册设备的注册令牌存储到您的服务器即可。 并且在使用 curl 调用推送通知时(我假设您使用 php 作为服务器端)将所有注册 id 放入一个数组中。 这是一个示例代码

    <?php
    //Define your GCM server key here 
    define('API_ACCESS_KEY', 'your server api key');
    
    //Function to send push notification to all 
    function sendToAll($message)
    {
        $db = new DbOperation();
        $tokens = $db->getAllToken();
        $regTokens = array();
        while($row = $tokens->fetch_assoc()){
            array_push($regTokens,$row['token']);
        }
        sendNotification($regTokens,$message);
    }
    
    
    //function to send push notification to an individual 
    function sendToOne($email,$message){
        $db = new DbOperation();
        $token = $db->getIndividualToken($email);
        sendNotification(array($token),$message);
    }
    
    
    //This function will actually send the notification
    function sendNotification($registrationIds, $message)
    {
        $msg = array
        (
            'message' => $message,
            'title' => 'Android Push Notification using Google Cloud Messaging',
            'subtitle' => 'www.simplifiedcoding.net',
            'tickerText' => 'Ticker text here...Ticker text here...Ticker text here',
            'vibrate' => 1,
            'sound' => 1,
            'largeIcon' => 'large_icon',
            'smallIcon' => 'small_icon'
        );
    
        $fields = array
        (
            'registration_ids' => $registrationIds,
            'data' => $msg
        );
    
        $headers = array
        (
            'Authorization: key=' . API_ACCESS_KEY,
            'Content-Type: application/json'
        );
    
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, 'https://android.googleapis.com/gcm/send');
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
        $result = curl_exec($ch);
        curl_close($ch);
    
        $res = json_decode($result);
    
        $flag = $res->success;
        if($flag >= 1){
            header('Location: index.php?success');
        }else{
            header('Location: index.php?failure');
        }
    }
    

    在上面的代码中,我们从 mysql 表中获取注册令牌。要发送到所有设备,我们需要所有令牌。要发送单个设备,我们只需要该设备的令牌。

    来源:Google Cloud Messaging Example

    【讨论】:

      【解决方案3】:

      您可以将 Android 设备 ID 与注册 ID 一起发送。 Android 设备 ID 是唯一的,并且在应用程序卸载重新安装期间保持不变,并且仅在设备恢复出厂设置时才会更改。

      示例:How to get unique device hardware id in Android?

      【讨论】:

        【解决方案4】:

        我在卸载应用程序时遇到了注册 ID 更改,尝试在应用程序卸载时向应用程序发送消息(直到我收到 NotRegistered 错误)然后再次安装。

        来自 Google suggests 的 Costin Manolache 以这种方式处理注册 ID 更改:

        建议/解决方法是生成您自己的随机标识符,例如保存为共享首选项。在每次应用升级时,您都可以上传标识符和可能的新注册 ID。这也可能有助于跟踪和调试服务器端的升级和注册更改。

        当然,这仅在应用程序保持安装状态时才有效(因为共享首选项已随应用程序一起删除)。但是,如果设备有外部存储,您可以将您的标识符存储在那里,当再次安装应用程序时,从外部存储加载存储的标识符。这样您就可以知道新的注册 ID 和旧的注册 ID 属于同一设备。

        此外,您应该在您的服务器中处理来自 Google 的规范注册 ID 响应,如另一个答案中所述。

        【讨论】:

          【解决方案5】:

          欢迎来到来自Google Cloud Messaging 的重复消息的奇妙世界。发生这种情况时,GCM 引擎启用Canonical IDs 来解决它。这可能是因为您为同一设备注册了多个 ID,或者因为在卸载应用程序时 GCM 服务器没有收到 unregister() 调用。使用规范 ID 会将您的 ID 设置为您进行的最后一次注册。

          根据GCM reference 的说法:

          规范 ID

          在服务器端,只要应用程序运行良好,一切都应该正常工作。但是,如果应用程序中的错误触发同一设备的多个注册,则可能很难协调状态,并且您最终可能会收到重复的消息。

          GCM 提供了一种称为“规范注册 ID”的工具,可以轻松地从这些情况中恢复。规范注册 ID 定义为您的应用程序请求的最后一次注册的 ID。这是服务器在向设备发送消息时应使用的 ID。

          如果稍后您尝试使用不同的注册 ID 发送消息,GCM 将照常处理请求,但它会在响应的 registration_id 字段中包含规范注册 ID。请务必使用此规范 ID 替换存储在您服务器中的注册 ID,因为最终您使用的 ID 将停止工作。

          更多信息here

          还有一个关于如何进行的实际案例,它可能会有所帮助:

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-12-14
            • 1970-01-01
            • 2015-07-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多