安卓GCM和多个令牌

17

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

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


可能是Do old GCM tokens live on even after an uninstall?的重复问题。 - Baris Akar
5个回答

11
欢迎来到谷歌云消息的重复信息奇妙世界。当这种情况发生时,GCM引擎会启用规范ID来解决此问题。这可能是因为您为同一设备注册了多个ID,或者因为在卸载应用程序时,GCM服务器没有收到unregister()调用。使用规范ID将使您的ID设置为您进行的最后一次注册。
根据GCM参考文献所述:

规范化ID

在服务器端,只要应用程序表现良好,一切都应该正常工作。但是,如果应用程序中的一个错误触发了对同一设备的多次注册,就很难协调状态,你可能会得到重复的消息。

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

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

更多信息在这里

此外,还有一个实际案例说明如何操作,这可能会有所帮助:


5

当我卸载应用程序时,尝试向未安装的应用程序发送消息(直到出现NotRegistered错误),然后重新安装时,我遇到了注册ID更改的情况。

来自Google的Costin Manolache 建议 以以下方式处理注册ID更改:

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

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

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


1

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

0

首先,在发送通知时,请将用户ID与其一起发送,并询问是否在sharedpreference == comming中或不在其中

如果您向所有用户发送通知,可能会有人收到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"));
    }
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接