it-swarm.com.ru

Android GCM и несколько токенов

Я регистрируюсь в GCM с помощью GoogleCloudMessaging.getInstance (context); и сохранить полученный токен на устройстве. Затем отправьте его на сервер, и он будет связан с учетной записью пользователя. Если я удалю свое приложение, не выйдя из системы и не установив его снова, а войду с другим пользователем, я получу новый токен и отправлю его на сервер. И когда нажимает на отправку первому пользователю, я вижу их, когда я вошел со вторым пользователем.

Почему GCM отправляет мне разные токены и как я могу с этим справиться?

15
earsonheart

Добро пожаловать в удивительный мир повторяющихся сообщений от Google Cloud Messaging. Когда это происходит, механизм GCM позволяет Canonical IDs решить его. Это может произойти из-за того, что вы зарегистрировались под несколькими идентификаторами для одного и того же устройства или из-за того, что сервер GCM не получил вызов unregister() при удалении приложения. Использование канонических идентификаторов сделает ваш идентификатор последней зарегистрированной вами регистрацией.

Согласно GCM reference об этом:

Канонические идентификаторы

На стороне сервера, пока приложение ведет себя хорошо, все должно работать нормально. Однако, если ошибка в приложении вызывает несколько регистраций для одного и того же устройства, может быть трудно согласовать состояние, и вы можете получить дубликаты сообщений.

GCM предоставляет средство, называемое «канонические регистрационные идентификаторы», чтобы легко восстанавливаться после этих ситуаций. Канонический регистрационный идентификатор определяется как идентификатор последней регистрации, запрошенной вашей заявкой. Это идентификатор, который сервер должен использовать при отправке сообщений на устройство.

Если позже вы попытаетесь отправить сообщение с использованием другого регистрационного идентификатора, GCM обработает запрос как обычно, но он будет включать канонический регистрационный идентификатор в поле registration_id ответа. Обязательно замените регистрационный идентификатор, хранящийся на вашем сервере, на этот канонический идентификатор, так как в конечном итоге используемый вами идентификатор перестанет работать.

Больше информации здесь .

Также есть практический пример того, как продолжить, это может быть полезно:

11
nKn

Я столкнулся с изменением регистрационного идентификатора при удалении приложения, попытке отправить сообщения приложению, пока оно удалено (до тех пор, пока я не получу ошибку NotRegistered), а затем снова установить.

Костин Манолаш из Google предлагает обработать изменения регистрационного идентификатора следующим образом:

Предложение/обходной путь заключается в создании собственного случайного идентификатора, сохраненного, например, в качестве общего предпочтения. При каждом обновлении приложения вы можете загружать идентификатор и потенциально новый регистрационный идентификатор. Это также может помочь в отслеживании и отладке обновлений и изменений регистрации на стороне сервера.

Конечно, это работает только тогда, когда приложение остается установленным (поскольку общие настройки удаляются вместе с приложением). Однако, если устройство имеет внешнее хранилище, вы можете сохранить свой идентификатор там, а когда приложение будет установлено снова, загрузить сохраненный идентификатор из внешнего хранилища. Таким образом, вы будете знать, что новый регистрационный идентификатор и старый регистрационный идентификатор принадлежат одному и тому же устройству.

Кроме того, вы должны обрабатывать ответы канонического регистрационного идентификатора от Google на своем сервере, как указано в другом ответе.

5
Eran

Вы можете отправить идентификатор устройства Android вместе с идентификатором регистрации. Идентификатор устройства Android является уникальным и остается неизменным во время переустановки приложения и изменяется только в случае сброса настроек устройства. 

Пример: Как получить уникальный идентификатор устройства в Android?

1
Said Ali Samed

Отправка Push-уведомлений на несколько устройств такая же, как и отправка на отдельное устройство. Просто сохраните регистрационный токен всех зарегистрированных устройств на свой сервер. И при вызове Push-уведомления с помощью curl (я предполагаю, что вы используете php на стороне сервера) Поместите все регистрационные идентификаторы в массив. Это пример кода 

<?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 

0
Reyaan Roy

сначала при отправке уведомления отправьте с ним идентификатор пользователя и спросите, есть ли идентификатор в sharedpreference == comming или нет 

если вы отправляете уведомления всем пользователям и, возможно, кто-то получит 2 уведомления, тогда как он должен сделать только одно, сделайте это

Создайте файл на своем сервере и с любым номером, скажем, 0, затем, когда вы хотите отправить уведомление, отправьте это число вместе с ним, а затем добавьте одно к этому номеру ++ , Чтобы оно было новым номером в следующем уведомлении, аналогичном каждому новому. 

В приложении Android добавьте переменную и пусть эта переменная = переменная пришествия с сервера после добавления уведомления , Но вам нужно запросить if(number_in_your_service!=server_number)//add уведомление

любое количество отправленных вами уведомлений будет отображаться только одно

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"));
    }
  }
}
0
Mohamed Atef