我使用 GoogleCloudMessaging.getInstance(context); 在GCM中注册并将接收到的令牌保存在设备上。然后将其发送到服务器并与用户帐户关联。如果我卸载应用程序而不注销并重新安装,然后使用另一个用户登录,我会收到新的令牌并将其发送到服务器。当推送被发送到第一个用户时,我登录第二个用户后也能看到他们。
GCM 为什么会发送不同的令牌,我该如何处理?
我使用 GoogleCloudMessaging.getInstance(context); 在GCM中注册并将接收到的令牌保存在设备上。然后将其发送到服务器并与用户帐户关联。如果我卸载应用程序而不注销并重新安装,然后使用另一个用户登录,我会收到新的令牌并将其发送到服务器。当推送被发送到第一个用户时,我登录第二个用户后也能看到他们。
GCM 为什么会发送不同的令牌,我该如何处理?
规范化ID
在服务器端,只要应用程序表现良好,一切都应该正常工作。但是,如果应用程序中的一个错误触发了对同一设备的多次注册,就很难协调状态,你可能会得到重复的消息。
GCM提供了一个名为“规范化注册ID”的功能,可以轻松地从这些情况中恢复过来。规范化注册ID被定义为应用程序请求的最后一个注册ID。这是服务器在向设备发送消息时应使用的ID。
如果以后您尝试使用不同的注册ID发送消息,GCM将像往常一样处理请求,但它将在响应的registration_id字段中包含规范化的注册ID。请务必使用此规范化ID替换存储在服务器中的注册ID,因为您正在使用的ID最终将停止工作。
更多信息在这里。
此外,还有一个实际案例说明如何操作,这可能会有所帮助:
当我卸载应用程序时,尝试向未安装的应用程序发送消息(直到出现NotRegistered
错误),然后重新安装时,我遇到了注册ID更改的情况。
来自Google的Costin Manolache 建议 以以下方式处理注册ID更改:
建议/解决方法是生成自己的随机标识符,例如保存为共享首选项。在每次应用程序升级时,您可以上传标识符和可能的新注册ID。这也有助于跟踪和调试服务器端的升级和注册更改。
当然,这仅适用于应用程序保持安装状态的情况(因为共享首选项会随应用程序被删除而删除)。但是,如果设备具有外部存储,则可以将标识符存储在那里,并在重新安装应用程序时从外部存储加载存储的标识符。这样,您就会知道新的注册ID和旧的注册ID属于同一设备。
此外,您还应该在服务器上处理来自Google的规范注册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表中获取注册令牌。要发送到所有设备,我们需要所有令牌。而要发送给单个设备,我们只需要该设备的令牌。首先,在发送通知时,请将用户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"));
}
}
}