0

I want to create an android service which always runs in background even when we haven't opened the app like gmail service or whatsapp service so we can get notifications when app is closed (but not forced close). I want to get gcm notification even when app is closed like we swapped out app from recent apps.

Right now when I close app by long press on home button and swapped it all components of app close ao I couldn't get gcm notifications.

I know we can't get gcm notifications when app is forced close.

I have stuck on this problem for long time. Can somebody know how to handle this issue

public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        ComponentName comp = new ComponentName(context.getPackageName(),
                GCMNotificationIntentService.class.getName());
        startWakefulService(context, (intent.setComponent(comp)));
        setResultCode(Activity.RESULT_OK);
        }
}

Manifest file

    <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="xxxx"
    android:installLocation="internalOnly">

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />


    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATUS_AND_IDENTITY" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.VIBRATE" />


    <permission
        android:name="xxxx.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />

    <uses-permission android:name="xxxx.permission.C2D_MESSAGE" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />

    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />

        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:windowSoftInputMode="stateHidden" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>


        //it overrides WakefulBroadcastReceiver
        <receiver
            android:name=".gcm.GcmBroadcastReceiver"
            android:permission="com.google.android.c2dm.permission.SEND" >
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />

                <category android:name="xxxx" />
            </intent-filter>
        </receiver>

        //it overrides IntentService
        <service android:name=".gcm.GCMNotificationIntentService" />

    </application>

</manifest> 

   public class GCMNotificationIntentService extends IntentService {
    // Sets an ID for the notification, so it can be updated
    public static final int notifyID = 9001;
    private static final String TAG = GCMNotificationIntentService.class.getSimpleName();

    NotificationCompat.Builder builder;

    public GCMNotificationIntentService() {
        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()) {
            if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR
                    .equals(messageType)) {
                sendNotification("Send error: " + extras.toString());
            } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED
                    .equals(messageType)) {
                sendNotification("Deleted messages on server: "
                        + extras.toString());
            } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE
                    .equals(messageType)) {

                String incomingMessage = extras.get(ApplicationConstants.MSG_KEY)+"";
                String type = identifyHeaders(incomingMessage);
                String processedString = removeHeaders(incomingMessage, type);

                if(type.equals(NOTIFICATION_MESSAGE)) {
                    sendNotification(processedString);
                }else if(type.equals(NOTIFICATION_PHONE_CHANGE)){
                }
            }
        }
        GcmBroadcastReceiver.completeWakefulIntent(intent);
    }

    //this methos is for sending notification to notification bar
    private void sendNotification(String msg) {

    }

}

Updated GCM Service code

public class GCMNotificationIntentService extends Service {
    // Sets an ID for the notification, so it can be updated
    public static final int notifyID = 9001;
    private static final String TAG = GCMNotificationIntentService.class.getSimpleName();

    public GCMNotificationIntentService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        Log.d(TAG, "Service started");
        processIntent(intent);

        return START_STICKY;
    }

    void processIntent(Intent intent){

        Log.d(TAG, "notification received");

        Bundle extras = intent.getExtras();
        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
        String messageType = gcm.getMessageType(intent);
        if (!extras.isEmpty()) {
            if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR
                    .equals(messageType)) {
                sendNotification("Send error: " + extras.toString());
            } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED
                    .equals(messageType)) {
                sendNotification("Deleted messages on server: "
                        + extras.toString());
            } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE
                    .equals(messageType)) {

                String incomingMessage = extras.get(ApplicationConstants.MSG_KEY)+"";
                String type = identifyHeaders(incomingMessage);
                String processedString = removeHeaders(incomingMessage, type);

                if(type.equals(NOTIFICATION_MESSAGE)) {
                    sendNotification(processedString);
                }else if(type.equals(NOTIFICATION_PHONE_CHANGE)){
                    updatePhoneNumber(processedString);
                }
            }
        }

        GcmBroadcastReceiver.completeWakefulIntent(intent);
    }



    private void sendNotification(String msg) {
        Intent resultIntent = new Intent(this, WelcomeScreen.class);
        resultIntent.putExtra("msg", msg);
        resultIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP| Intent.FLAG_ACTIVITY_NEW_TASK| Intent.FLAG_ACTIVITY_SINGLE_TOP);

        PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 0,
                resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        NotificationCompat.Builder mNotifyBuilder;
        NotificationManager mNotificationManager;
        mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        mNotifyBuilder = new NotificationCompat.Builder(this)
                .setContentTitle("GOODSERVICE")
                .setContentText("NEW LEAD FROM GOODSERVICE")
                .setSmallIcon(R.drawable.ic_launcher);

        mNotifyBuilder.setContentIntent(resultPendingIntent);

        // Set Vibrate, Sound and Light
        int defaults = 0;
        defaults = defaults | Notification.DEFAULT_LIGHTS;
        defaults = defaults | Notification.DEFAULT_VIBRATE;

        mNotifyBuilder.setDefaults(defaults);
        // Set the content for Notification
        mNotifyBuilder.setContentText("NEW LEAD FROM GOODSERVICE");
        // Set autocancel
        mNotifyBuilder.setAutoCancel(true);
        Uri soundTest =  Settings.System.DEFAULT_RINGTONE_URI;
        mNotifyBuilder.setSound(soundTest);
        // Post a notification
        mNotificationManager.notify(notifyID, mNotifyBuilder.build());
        Intent intentone = new Intent(this, HomeActivity.class);
        intentone.putExtra("msg", msg);
        intentone.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP| Intent.FLAG_ACTIVITY_NEW_TASK| Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
        this.startActivity(intentone);
    }

}

This is how I am calling this service

    ComponentName comp = new ComponentName(context.getPackageName(),
            GCMNotificationIntentService.class.getName());
    startWakefulService(context, (intent.setComponent(comp)));
    startWakefulService(context, (intent.setComponent(comp)));
    setResultCode(Activity.RESULT_OK);
user3265443
  • 535
  • 1
  • 8
  • 25
  • Your service is destroyed because you destroy the process (long press close) in which your service is spawned. I hope that your service is not bound to your Activity, but since your process is killed so is your service. Ideally Android should restart all such destroyed service, but they will start from scratch. – Karan Mar 26 '15 at 18:12
  • Use START_STICKY http://developer.android.com/reference/android/app/Service.html#START_STICKY or use startForeground(int,Notification) but that will keep showing a notification to the user and I don't think is ideal for gcm – Karan Mar 26 '15 at 18:17
  • I have added a picture in which app's services are always running in foreground. Have you tried doing anything like this? I already tried these options but the service is stopping when I do long press close – user3265443 Mar 26 '15 at 18:19
  • Do you know any approach for gcm? – user3265443 Mar 26 '15 at 18:20
  • Process dead ---> All components dead (Activity, Service etc) . Return Service.START_STICKY in your onStartCommand(), and Android will restart your service when process is killed! – Karan Mar 26 '15 at 18:21
  • Ideally it can be done with IntentService ( since its already on a worker thread and we dont need to start a new thread in our service). See link shared by Ryan. – Karan Mar 26 '15 at 18:24
  • I already implemented a IntentService but I am not getting any notifications after long press close. I hope I am not doing any wrong in manifest. Let me paste it here – user3265443 Mar 26 '15 at 18:27
  • @Kay Sorry to ask you again but Does it makes sense what I am talking? – user3265443 Mar 26 '15 at 18:49
  • please see: http://stackoverflow.com/questions/11614521/how-can-i-receive-notifications-from-gcm-when-application-is-stopped – Karan Mar 26 '15 at 19:10
  • when app stops, process stops, gcm intent will also stop. So this is something user can do and gcm will restart on manual launch of the app. I am not sure though why if can set gcm intent as sticky, or maybe we can but force closing the process will stop your intent in any case – Karan Mar 26 '15 at 19:11
  • if you are fine we can continue the discussion in chat? for 5 minutes – user3265443 Mar 26 '15 at 19:15
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/73873/discussion-between-user3265443-and-kay). – user3265443 Mar 26 '15 at 19:16
  • are you extending WakefulBroadcastReceiver ? have you declared in manifest? – Karan Mar 26 '15 at 19:21
  • Yes, it is already there. See my manifest file – user3265443 Mar 26 '15 at 19:22
  • ok, if you have followed gcm guide from Android dev site(used WakefulBroadcastReceiver and GcnIntentService), your notifications should be coming even when activity is not in backstack, provided it was launched once... – Karan Mar 26 '15 at 19:24
  • Yes, it should be coming but I am not receiving it. Please help me if you can. I can paste my code if you want. It would be really helpful – user3265443 Mar 26 '15 at 19:28
  • yes update with intentService and receiver – Karan Mar 26 '15 at 19:31
  • I removed the unnecessary code from the two classes and pasted it. – user3265443 Mar 26 '15 at 19:41
  • There are so many possibilities like is there a gcm package in your project? are you registering for gcm? do you get a notification when app is in background? – Karan Mar 26 '15 at 19:51
  • Did you find anything unusual in my implementation or let me know in case you haven't understood any part of code – user3265443 Mar 26 '15 at 19:51
  • Ok so assuming you are receiving notification when app is in background or foreground, it means your intentService is attached to activity. Only solution then to keep getting gcm messages is use a service which is not bound to activity. see :https://github.com/life0fun/GCM-app/blob/master/src/com/colorcloud/gcm/GcmService.java – Karan Mar 26 '15 at 19:59
  • However, if you are not receiving messages when Activity is in foreground too then something is wrong with gcm setup – Karan Mar 26 '15 at 20:00
  • I am receiving notifications when app is in foreground and background but not receiving when it is removed from backstack. Let me check if this works. Stuck on this problem for long long. Hopeful it should resolve – user3265443 Mar 26 '15 at 20:03
  • Should I replace GCMNotificationIntentService.java with this? – user3265443 Mar 26 '15 at 20:04
  • So intentService IS attached to activity, which is its natural behavior. Create a service as in the link. bests! – Karan Mar 26 '15 at 20:04
  • Sorry mate...but again I am facing the same issue. Service wokes up when a notification arrives as I am starting the service in GCM broadcast receiver. the service keeps on running until I pop my application from backstack with this error. Scheduling restart of crashed service com.net.gs.goodservice/.gcm.GCMNotificationIntentService in 1000ms Force stopping service ServiceRecord{4419ab30 u0 com.net.gs.goodservice/.gcm.GCMNotificationIntentService} – user3265443 Mar 26 '15 at 21:10
  • @Kay I have added updated Service code in question. Please see it – user3265443 Mar 26 '15 at 21:15
  • return START_STICKY; this should restart the service when process is destroyed – Karan Mar 27 '15 at 06:09

2 Answers2

1

IntentService won't run in background continuously. They will run just one time and when they are finished, they will be destroyed. You should check Service. They are not destroyed even if app is closed. Override its function onStartCommand. Check this answer for more detailed difference.

Community
  • 1
  • 1
Bugs Happen
  • 2,169
  • 4
  • 33
  • 59
  • *They are not destroyed even if app is closed* oh they are. But the difference is they can restart themselves – Tim Mar 08 '16 at 13:22
0

You're looking for WakefulBroadcastReceiver and IntentService

Here this will help you https://developer.android.com/google/gcm/client.html

priyank
  • 2,651
  • 4
  • 24
  • 36
  • I already implemented it but the problem is when I do long press close I stopped getting notifications as all components of my app is closed. I am thinking of a way where a component of app is opened so I can get GCM notifications – user3265443 Mar 26 '15 at 18:24
  • That won't work as when you you force close the app it's background services will also get closed. Try to force close gmail and whatsapp you won't get their notifications either. – priyank Mar 26 '15 at 18:32
  • but this is not forced close. I swapped out whatsapp from recent apps than too I get notifications. Forced close is when I go to settings->Apps->Forced close – user3265443 Mar 26 '15 at 18:36
  • I pasted a picture when I have no apps showing in Recent Apps and we can see that 1 process and 1 service is running for Whatsapp and Facebook and I believe that's why we can get notifications when app is closed – user3265443 Mar 26 '15 at 18:38
  • Okay look force closing is when you long press back button. And swiping out from recent apps is different. This does not close the background service. If you've implemented the `IntentService` and `WakefulBroadcastReceiver` correctly then swiping out from recents shouldn't affect the working of GCM. – priyank Mar 26 '15 at 19:16