Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/188.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android GCM和多个令牌_Android_Push Notification_Google Cloud Messaging - Fatal编程技术网

Android GCM和多个令牌

Android GCM和多个令牌,android,push-notification,google-cloud-messaging,Android,Push Notification,Google Cloud Messaging,我使用GoogleCloudMessaging.getInstance(上下文)在GCM中注册;并将收到的令牌保存在设备上。然后将其发送到服务器,并将其与用户帐户关联。如果我卸载我的应用程序而不注销,然后再次安装并与其他用户登录,我将收到新令牌并将其发送到服务器。当推送被发送给第一个用户时,我会在和第二个用户登录时看到它们 为什么GCM会向我发送不同的令牌,我如何处理这些令牌?欢迎来到谷歌云消息的重复消息的奇妙世界。发生这种情况时,GCM引擎将启用规范ID来解决此问题。这可能是因为您为同一设备注

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


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

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

根据《GCM参考资料》,关于这一点:

规范ID

在服务器端,只要应用程序运行良好,一切都应该正常工作。然而,如果应用程序中的一个bug触发了同一设备的多个注册,则很难协调状态,最终可能会出现重复消息

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

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

更多信息

此外,还有一个关于如何处理的实际案例,可能会有所帮助:


我在卸载应用程序时遇到注册ID更改,试图在卸载应用程序时向应用程序发送消息(直到出现
未注册
错误),然后再次安装

谷歌的Costin Manolache以这种方式处理注册ID变更:

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

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


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

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


示例:

向多个设备发送推送通知与向单个设备发送推送通知相同。 只需将所有已注册设备的注册令牌存储到服务器。 当使用curl调用push通知时(我假设您使用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');
    }
}

发送通知时,首先发送用户id,并询问
SharedReference==comming
中的id或否

如果您向所有用户发送通知,可能有人会收到2个通知,而他应该只收到一个

在您的服务器上创建一个文件,使用任何数字,比如0,然后当您要发送通知时,使用它发送此numebr,然后将一个添加到此数字++ 下一次通知中的新编号与每个新编号相同

在android应用程序中,添加变量,并让此变量=添加通知后来自服务器的提交变量 但您需要询问
是否(您服务中的号码!=服务器号码)
//添加通知

您发送的任何数量的通知(仅一个)都将出现

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"));
    }
  }
}
公共类gcminentservice扩展了IntentService{
公共静态开放意图;
公共静态最终整数通知_ID=1;
私有静态最终字符串TAG=“gcminentservice”;
您的\u服务中的私有静态字符串编号\u=“somethingneversend”;
通知建筑商;
公共GCMinentService(){
超级(“GCMinentService”);
}
@凌驾
受保护的手部内容无效(意图){
Bundle extras=intent.getExtras();
GoogleCloudMessaging gcm=GoogleCloudMessaging.getInstance(this);
字符串messageType=gcm.getMessageType(intent);
如果(!extras.isEmpty()){//具有解包的效果
if(GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)){
}else if(GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)){
//如果是常规GCM消息,请执行一些操作。
}else if(GoogleCloudMessaging.MESSAGE\u TYPE\u MESSAGE.equals(messageType)){
//此循环表示正在执行某些工作的服务。
对于(int i=0;i<5;i++){
Log.i(标记“Working…”+(i+1)+“/5@”+SystemClock.elapsedRealtime());
试一试{
睡眠(100);
}捕捉(中断异常e){
}
}
Log.i(标记“Completed work@”+SystemClock.elapsedRealtime());
//接收到消息的Post通知。
发送通知(临时通知);
Log.i(标记“Received:+extras.toString());