Android GCM和多个令牌

时间:2014-04-25 12:39:29

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

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

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

5 个答案:

答案 0 :(得分:11)

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

根据GCM reference关于此:

  

Canonical ID

     

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

     

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

     

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

更多信息here

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

答案 1 :(得分:5)

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

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

  

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

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

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

答案 2 :(得分:1)

您可以发送Android设备ID以及注册ID。 Android设备ID是唯一的,在应用程序卸载重新安装期间保持不变,只有在设备出厂重置时才会更改。

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

答案 3 :(得分:0)

向多个设备发送推送通知与我们发送到单个设备的相同。 只需将所有已注册设备的注册令牌存储到您的服务器即可。 并且当使用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

答案 4 :(得分:0)

首先发送通知时发送用户ID并询问sharedpreference == comming中的ID是否为

如果您向所有用户发送通知,并且可能只有一个人获得2个通知,而他应该只有一个人这样做

在您的服务器上创建文件并使用任意数字表示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"));
    }
  }
}