Search code examples
androidnotificationsbroadcastreceivergoogle-cloud-messaging

When multiple apps which listen to same GCM channel are installed, How to make sure the notification is shown only once?


I'm going to publish a series of apps and I want to be able to display notifications to users who have installed any of these apps via GCM. but when there are multiple apps installed on each device, multiple notifications are displayed to users. I want to make sure that only one notification is displayed to users, regardless of count of apps they have installed.

I have tried to put a unique Id in each GCM message that I send and in the application when the Broadcast message is received save it in a file in a specific folder in internal storage, so I can keep track of the message and avoid displaying the same message from multiple apps. but I think this is unreliable and better methods should exist.

All the apps receive the messages from the same GCM channel.


Solution

  • I ended up using a file on external storage as a way to check wether the current GCM message is handled or not, I tested it throughly and in works.

    public class GcmIntentService extends IntentService {
    public static final int NOTIFICATION_ID = -3;
    private NotificationManager mNotificationManager;
    public static final String TAG = "CGMIntentService";
    
    public GcmIntentService() {
        super("GcmIntentService");
    }
    
    @Override
    protected void onHandleIntent(Intent intent) {
        Bundle extras = intent.getExtras();
        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
        // The getMessageType() intent parameter must be the intent you received
        // in your BroadcastReceiver.
        String messageType = gcm.getMessageType(intent);
    
        if (!extras.isEmpty()) {  // has effect of unparcelling Bundle
        if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
                // Post notification of received message.
                sendNotification("Received: " + extras.toString(), extras);
                Log.i(TAG, "Received: " + extras.toString());
            }
        }
        // Release the wake lock provided by the WakefulBroadcastReceiver.
        GcmBroadcastReceiver.completeWakefulIntent(intent);
    }
    
    private void sendNotification(String msg, final Bundle bundle) {
        ATImg atImg = new ATImg();
        //use a file lock as way to check whether another app is displaying this gcm message
        String fileName = DirectoryHelper.getMCDirectory() + "/" + DirectoryHelper.handledIdsFileName;
        if (DirectoryHelper.isFileLocked(fileName))
            return;//file is locked, it means another app has caught this gcm message prior to this app
        try {
            atImg.randomAccessFile = new RandomAccessFile(fileName, "rw");
            atImg.lock= atImg.randomAccessFile.getChannel().lock();// lock the file so no other app access it
        } catch (FileNotFoundException e) {//again this means file is locked
            e.printStackTrace();
            return;
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
        atImg.bundle = bundle;
        atImg.doInBackground("");
    }
    
    public class ATImg extends AsyncTask<String, String, String> {
        Bundle bundle;
        RandomAccessFile randomAccessFile;
        FileLock lock;
        @Override
        protected void onPostExecute(String reult){
    //release the lock on file
            try {
                lock.release();
                randomAccessFile.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        @Override
        protected String doInBackground(String... strings) {
            String id = bundle.getString("id");
     //CHECK IF THE MESSAGE IS HANDLED
    
            Gson gson = new Gson();
            List<String> ids = null;
            try {
                Type concerete = new TypeToken<List<String>>() {
                }.getType();
                randomAccessFile.seek(0);
                ids = gson.fromJson(randomAccessFile.readUTF(), concerete);
                if (ids != null && ids.contains(id)) {
                    return "";//the message has already been shown
                }
            }
            catch (Exception ex){
                ex.printStackTrace();
                return "";
            }
    
            //write the new id to the end of the file
            if (ids == null)
                ids = new ArrayList<>();
            ids.add(id);
            try {
                randomAccessFile.seek(0);
                randomAccessFile.writeUTF(gson.toJson(ids));
            } catch (IOException e) {
                e.printStackTrace();
            }
     //END MASSAGE HANDLING CODE
     //write code to show the message
        }
    }
    }