当应用程序关闭或应用程序在后台时获得两次 GCM PUSH 通知

Posted

技术标签:

【中文标题】当应用程序关闭或应用程序在后台时获得两次 GCM PUSH 通知【英文标题】:Getting twice GCM PUSH notification when application is closed or application is in background 【发布时间】:2017-03-02 10:24:58 【问题描述】:

我已经在我的应用程序中实现了 gcm 推送通知。一切正常,我也收到了通知。

问题:

当应用处于后台或终止状态时,我一次收到 2 个通知。 当应用程序在前台时,我希望只收到 1 条通知。

应用程序应该只收到 1 条通知作为要求,但不幸的是面临未定义的情况。

我的代码如下:

GCMPushReceiverService 接收消息的类。

public class GCMPushReceiverService extends GcmListenerService 

//This method will be called on every new message received
@Override
public void onMessageReceived(String from, Bundle data) 
    //Getting the message from the bundle
    String message = data.getString("message");
    //Displaying a notiffication with the message
    Log.e("MeSs",""+message);
    sendNotification(this,message, "Traccar App");
    sendNotification(message);



//This method is generating a notification and displaying the notification  //When in front
private void sendNotification(Context context, String notificationText,
                              String notificationTitle) 

    PowerManager pm = (PowerManager) context
            .getSystemService(Context.POWER_SERVICE);
    PowerManager.WakeLock wakeLock = pm.newWakeLock(
            PowerManager.PARTIAL_WAKE_LOCK, "");
    wakeLock.acquire();

    Intent intent = new Intent(this, Home.class);
    intent.putExtra("ChatFragment", "newChatFound");
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    int requestCode = 0;
    PendingIntent pendingIntent = PendingIntent.getActivity(this, requestCode, intent, PendingIntent.FLAG_ONE_SHOT);
    Uri sound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(
            context)
            .setSmallIcon(R.drawable.bug_log_two)
            .setColor(Color.RED)
            .setContentTitle(notificationTitle)
            .setContentText(notificationText)
            .setDefaults(Notification.DEFAULT_ALL)
            .setAutoCancel(true)
            .setContentIntent(pendingIntent);


    NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);

    notificationManager.notify(0, notificationBuilder.build()); //0 = ID of notification

    wakeLock.release();


private void sendNotification(String message) 
    Intent intent = new Intent(this, Home.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    int requestCode = 0;
    PendingIntent pendingIntent = PendingIntent.getActivity(this, requestCode, intent, PendingIntent.FLAG_ONE_SHOT);
    Uri sound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

    NotificationCompat.Builder noBuilder = new NotificationCompat.Builder(this)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentText(message)
            .setAutoCancel(true)
            .setContentIntent(pendingIntent);

    NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);

    notificationManager.notify(0, noBuilder.build()); //0 = ID of notification



manifest文件代码:

 <!-- GCM -->

    <receiver
        android:name="com.google.android.gms.gcm.GcmReceiver"
        android:exported="true"
        android:permission="com.google.android.c2dm.permission.SEND">
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />

            <category android:name="com.vk.trackeruser" />
        </intent-filter>
    </receiver>

    <!-- GCM Receiver Service -->
    <service
        android:name=".Notification.GCMPushReceiverService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        </intent-filter>
    </service>

    <!-- GCM Registration Intent Service -->
    <service
        android:name=".Notification.GCMRegistrationIntentService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.android.gms.iid.InstanceID" />
        </intent-filter>
    </service>

GCMRegistrationIntentService类:

public class GCMRegistrationIntentService extends IntentService 
//Constants for success and errors
public static final String REGISTRATION_SUCCESS = "RegistrationSuccess";
public static final String REGISTRATION_ERROR = "RegistrationError";
public static final String SenderId = "my id with numeric number ex 9897979";
//Class constructor
public GCMRegistrationIntentService() 
    super("");



@Override
protected void onHandleIntent(Intent intent) 
    //Registering gcm to the device
    registerGCM();


private void registerGCM() 
    //Registration complete intent initially null
    Intent registrationComplete = null;

    //Register token is also null
    //we will get the token on successfull registration
    String token = null;
    try 
        //Creating an instanceid
        InstanceID instanceID = InstanceID.getInstance(getApplicationContext());

        //Getting the token from the instance id
        token = instanceID.getToken(SenderId, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);

        //Displaying the token in the log so that we can copy it to send push notification
        //You can also extend the app by storing the token in to your server
        Log.w("GCMRegIntentService", "token:" + token);
      String  tokan = token;
        //on registration complete creating intent with success
        registrationComplete = new Intent(REGISTRATION_SUCCESS);

        //Putting the token to the intent
        registrationComplete.putExtra("token", token);
     catch (Exception e) 
        //If any error occurred
        Log.w("GCMRegIntentService", "Registration error");
        registrationComplete = new Intent(REGISTRATION_ERROR);
    
    //Sending the broadcast that registration is completed
    LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete);

    

GCMTokenRefreshListenerService类:

public class GCMTokenRefreshListenerService extends InstanceIDListenerService
  //If the token is changed registering the device again
    @Override
    public void onTokenRefresh() 
        Intent intent = new Intent(this, GCMRegistrationIntentService.class);
        startService(intent);
    

获取我的GCM 令牌的类:

   in oncreate 
    //Initializing our broadcast receiver
    mRegistrationBroadcastReceiver = new BroadcastReceiver() 

        //When the broadcast received
        //We are sending the broadcast from GCMRegistrationIntentService

        @Override
        public void onReceive(Context context, Intent intent) 
            //If the broadcast has received with success
            //that means device is registered successfully
            if(intent.getAction().equals(GCMRegistrationIntentService.REGISTRATION_SUCCESS))
                //Getting the registration token from the intent
                String token = intent.getStringExtra("token");
                StaticContents.Gcm_token=token;
                Log.e("Token",""+token);
                //Displaying the token as toast
                Toast.makeText(getApplicationContext(), "Registration token:" + token, Toast.LENGTH_LONG).show();

                //if the intent is not with success then displaying error messages
             else if(intent.getAction().equals(GCMRegistrationIntentService.REGISTRATION_ERROR))
                //        Toast.makeText(getApplicationContext(), "GCM registration error!", Toast.LENGTH_LONG).show();
             else 
                //          Toast.makeText(getApplicationContext(), "Error occurred", Toast.LENGTH_LONG).show();
            
        
    ;

    //Checking play service is available or not
    int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());

    //if play service is not available
    if(ConnectionResult.SUCCESS != resultCode) 
        //If play service is supported but not installed
        if(GooglePlayServicesUtil.isUserRecoverableError(resultCode)) 
            //Displaying message that play service is not installed
            //        Toast.makeText(getApplicationContext(), "Google Play Service is not install/enabled in this device!", Toast.LENGTH_LONG).show();
            GooglePlayServicesUtil.showErrorNotification(resultCode, getApplicationContext());

            //If play service is not supported
            //Displaying an error message
         else 
            //          Toast.makeText(getApplicationContext(), "This device does not support for Google Play Service!", Toast.LENGTH_LONG).show();
        

        //If play service is available
     else 
        //Starting intent to register device
        Intent itent = new Intent(this, GCMRegistrationIntentService.class);
        startService(itent);
    

 //Registering receiver on activity resume
@Override
protected void onResume() 
    super.onResume();
    Log.w("MainActivity", "onResume");
    LocalBroadcastManager.getInstance(this).registerReceiver(mRegistrationBroadcastReceiver,
            new IntentFilter(GCMRegistrationIntentService.REGISTRATION_SUCCESS));
    LocalBroadcastManager.getInstance(this).registerReceiver(mRegistrationBroadcastReceiver,
            new IntentFilter(GCMRegistrationIntentService.REGISTRATION_ERROR));


    //Unregistering receiver on activity paused
@Override
protected void onPause() 
    super.onPause();

LocalBroadcastManager.getInstance(this).unregisterReceiver(mRegistrationBroadcastReceiver);


输出 1:当应用程序处于可见(前台)时,仅收到一个通知。

输出 2:当应用程序关闭或应用程序处于后台时收到 2 条通知。

【问题讨论】:

你能显示你的日志有什么错误吗?如果可能,请使用 FCM 而不是 GCM。 @JaydipUmaretiya 实际上它的工作正常问题是当前面的应用程序我收到一次通知但当应用程序在后台或未打开时我收到两次相同的通知先生 嗨。你能展示一个样本有效载荷吗?目前,我认为原因是您在onMessageReceived() 中调用了两个sendNotification()。我不确定为什么它只发生在后台。 @AL。先生,我没有太多的存储库来发布示例图像,实际上我在 onMessageReceived() 中评论了 sendnotification() 的一个函数,但结果是相同的。我已经测试了 sendNotification(this,message,"Traccar App"); == > 这在应用程序打开时有效。发送通知(消息); == > 当应用程序关闭或在后台时,这个可以工作。 您可以编辑您的帖子并将示例有效负载作为文本包含在内。然后将其格式化为代码。 :) 我懂了。这是发生在多台设备上还是仅发生在特定设备上? 【参考方案1】:

1. GCMPushReceiverService 类中的 onMessageReceived 函数在您收到来自 GCM 的消息后被调用。

使用这个

String message = data.getString("message");

您正在解析消息并将其存储在名为 message 的变量中。

问题是您将消息传递给两个函数

sendNotification(this,message, "Traccar App");
sendNotification(message);

这两个函数都在构建一个通知,并将您传递给这两个函数的消息显示为 2 个单独的通知。

只需注释掉这两个函数中的任何一个并检查。

2. 为了避免重复通知,我们有一种方法可以处理它。 尝试改变这个 -

PendingIntent pendingIntent = PendingIntent.getActivity(this, requestCode, intent, PendingIntent.FLAG_ONE_SHOT);

PendingIntent pendingIntent = PendingIntent.getActivity(this, requestCode, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);

如果问题仍然存在,请发布您获得的有效负载。我建议使用 FCM 而不是 GCM

【讨论】:

我一一评论了 sendNotification(this,message, "Traccar App");发送通知(消息);但结果是一样的。 还是同一个兄弟 这是一个罕见的问题,第一次看到它,也是一个有趣的问题。我想重现它并找到原因。还是您尝试使用 FCM ?从今天开始,您应该使用 FCM 而不是 GCM。【参考方案2】:

您可以使用 FCM 下游而不是上游

【讨论】:

以上是关于当应用程序关闭或应用程序在后台时获得两次 GCM PUSH 通知的主要内容,如果未能解决你的问题,请参考以下文章

GCM BroadcastReceiver 仅在应用程序正在运行或在后台运行时触发

重复通知GCM android应用程序

关闭应用程序时如何避免处理来自 GCM 的推送通知

当应用程序在后台或被杀死时,GCM 支持 ios 应用程序

当应用程序关闭时,GCM 广播接收器未检测到 gcm 通知

如何接收应用程序停止或设备关闭时发送的 GCM 推送通知?