Android GCM и несколько токенов
Я регистрируюсь в GCM с помощью GoogleCloudMessaging.getInstance(контекст); и сохранить полученный токен на устройстве. Затем отправьте его на сервер и связать с учетной записью пользователя. Если я удалю свое приложение без выхода из системы и установки снова и войдите в систему с другим пользователем, я получаю новый токен и отправлю его на сервер. И когда нажатие посылается первому пользователю, я вижу их, когда я вошел в систему со вторым пользователем.
Почему GCM отправляет мне разные токены и как я могу справиться с этим?
Ответы
Ответ 1
Добро пожаловать в чудесный мир повторяющихся сообщений от Google Cloud Messaging
. Когда это произойдет, двигатель GCM
позволяет Canonical IDs
решить проблему. Это может произойти из-за того, что вы зарегистрировались с несколькими идентификаторами для одного и того же устройства или потому, что сервер GCM
не получил вызов unregister()
, когда приложение было удалено. Используя канонические идентификаторы, ваш идентификатор станет последней регистрацией, которую вы сделали.
В соответствии с GCM reference
об этом:
Канонические идентификаторы
На стороне сервера, пока приложение ведет себя хорошо, все должно работать нормально. Однако, если ошибка в приложении вызывает несколько регистраций для одного и того же устройства, может быть сложно согласовать состояние, и вы можете получить дубликаты сообщений.
GCM предоставляет средство, называемое "идентификаторы канонической регистрации", чтобы легко восстановить из этих ситуаций. Идентификатор канонической регистрации определяется как идентификатор последней регистрации, запрошенной вашим приложением. Это идентификатор, который сервер должен использовать при отправке сообщений на устройство.
Если позже вы попытаетесь отправить сообщение с использованием другого регистрационного идентификатора, GCM будет обрабатывать запрос как обычно, но он будет содержать идентификатор канонической регистрации в поле registration_id ответа. Обязательно замените идентификатор регистрации, хранящийся на вашем сервере, этим каноническим идентификатором, так как в конечном итоге идентификатор, который вы используете, перестанет работать.
Подробнее здесь.
Также есть практический пример о том, как это сделать, может быть полезно:
Ответ 2
У меня возникли изменения идентификатора регистрации при удалении приложения, попытка отправить сообщения в приложение во время его удаления (пока я не получу ошибку NotRegistered
), а затем снова установить.
Costin Manolache от Google предлагает, чтобы обрабатывать идентификаторы регистрации таким образом:
Рекомендация/обходной путь заключается в создании вашего собственного случайного идентификатора, сохраненного в качестве общего предпочтения, например. В каждом обновлении приложения вы можете загрузить идентификатор и потенциально новый идентификатор регистрации. Это также может помочь отслеживать и отлаживать изменения обновления и регистрации на стороне сервера.
Конечно, это работает только тогда, когда приложение остается установленным (поскольку общие настройки удаляются вместе с приложением). Однако, если устройство имеет внешнее хранилище, вы можете сохранить там свой идентификатор, а когда приложение будет установлено снова, загрузите сохраненный идентификатор из внешнего хранилища. Таким образом, вы узнаете новый регистрационный идентификатор, а старый идентификатор регистрации принадлежит к тому же устройству.
Кроме того, вы должны обрабатывать ответы канонического регистрационного идентификатора от Google на своем сервере, как указано в другом ответе.
Ответ 3
Вы можете отправить идентификатор устройства Android вместе с идентификатором регистрации. Идентификатор устройства Android уникален и остается неизменным при повторной установке приложения и изменяется только в том случае, если устройство factory reset.
Пример: Как получить уникальный идентификатор устройства в Android?
Ответ 4
Отправка Push Notification на несколько устройств аналогична отправке на отдельное устройство.
Просто сохраните регистрационный токен всех зарегистрированных устройств на вашем сервере.
И при вызове 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
Ответ 5
сначала, когда вы отправляете уведомление, отправите идентификатор пользователя с ним и спросите, есть ли идентификатор в 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 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"));
}
}
}