title: Android Push notifications not working when app is closed
body: <p>I'm using <a href="https://github.com/heremaps/oksse" rel="noreferrer">OkSse</a> to subscribe to my Server Sent Events.</p>
  
  <p>Whenever a new message is sent by the server, a notification should appear whether the app is in <strong>foreground,minimized or fully closed</strong>.</p>
  
  <p>The notifications work as expected when <em>minimized or in foreground</em> but when <strong>fully closed</strong>, this only works on some <strong>device brands</strong>.</p>
  
  <p>Researching a <a href="https://medium.freecodecamp.org/why-your-push-notifications-never-see-the-light-of-day-3fa297520793" rel="noreferrer">bit</a>, I found that:</p>
  
  <blockquote>
    <p>this issue is noticed only on phones by manufacturers like Xiaomi,
    Oppo, One Plus, Vivo, Lenovo, Huawei, Samsung, and a few others.</p>
  </blockquote>
  
  <p>How does <code>WhatsApp, Facebook, Slack, Gmail, etc..</code> display notifications even if app is closed?</p>
  
  <p>I don't use <code>FCM</code>, just subscribe to <code>Sse</code>.</p>
  
  <p>I also have in manifest:</p>
  
  <pre><code>&lt;uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /&gt;
  
  &lt;receiver android:name="com.goparty.communication.NotificationsAlarmReceiver"&gt;
      &lt;intent-filter&gt;
          &lt;action android:name="android.media.action.DISPLAY_NOTIFICATION" /&gt;
          &lt;action android:name="android.intent.action.BOOT_COMPLETED"/&gt;
      &lt;/intent-filter&gt;
  &lt;/receiver&gt;
  </code></pre>
  
  <p>How can I achieve this?</p>
  
  <h2>Update</h2>
  
  <p>I managed to make it work by using an <code>IntentService</code> and <code>BroadcastReceiver</code> but this crashes for <code>Oreo</code> versions.</p>
  
  <p>After more <a href="https://developer.android.com/reference/android/support/v4/app/JobIntentService" rel="noreferrer">reading</a> I found that <code>JobIntentService</code> is the replacement of <code>IntentService</code> when targeting <code>Android O</code> and above.</p>
  
  <p>The transition to <code>JobIntentService</code> was pretty straight forward but again, my solution is not working when I close the app.</p>
  
  <p>The whole purpose of notifications are to work even when the app is closed.</p>
  
  <p>Using <code>IntentService</code> worked in the background by sending a <code>broadcast</code> with a new intent of my service.</p>
  
  <p>I'm doing the same with <code>JobIntentService</code> with no luck.</p>
  
  <p>Here's my code:</p>
  
  <pre><code>public class NotificationService extends JobIntentService {
  
      private static final int JOB_ID = 1;
      private NotificationManager notificationManager;
  
      public static void enqueueWork(Context context, Intent intent) {
          enqueueWork(context, NotificationService.class, JOB_ID, intent);
      }
  
      @Override
      public void onCreate() {
          super.onCreate();
          Logger.logGoParty(getClass().getSimpleName() + "#onCreate");
          notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
      }
  
      @Override
      public void onDestroy() {
          super.onDestroy();
          Logger.logGoParty("Running in background.");
          sendBroadcast(new Intent(getApplicationContext(), NotificationService.class));
      }
  
      @Override
      protected void onHandleWork(@NonNull Intent intent) {
          Logger.logGoParty(getClass().getSimpleName() + "#onHandleWork");
          Logger.logGoParty("Sse initialized");
  
          Request request = new Request.Builder().url("the sse url").build();
          OkSse okSse = new OkSse();
  
          ServerSentEvent sse = okSse.newServerSentEvent(request, new ServerSentEvent.Listener() {
              @Override
              public void onOpen(ServerSentEvent sse, Response response) {
                  Logger.logGoParty(response.toString());
              }
  
              @Override
              public void onMessage(ServerSentEvent sse, String id, String event, String message) {
                  Logger.logGoParty("Sse#onMessage: " + message);
                  try {
                      JSONObject promoJson = new JSONObject(message);
  
                      sendNotification(...);
  
                  } catch (JSONException e) {
                      Logger.logGoParty("JSONException: " + e.toString());
                  }
              }
                  // ...
          });
      }
  
      private void sendNotification(String promoImageUrl, String notificationContent, String title) {
  
          try {
              URL url = new URL(promoImageUrl);
              Bitmap bitmap = BitmapFactory.decodeStream(url.openConnection().getInputStream());
  
  
              NotificationCompat.BigPictureStyle style = new NotificationCompat.BigPictureStyle();
              style.bigPicture(bitmap);
  
              Uri defaultSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
  
              Intent intent = new Intent(this, MapsActivity.class);
              intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
              intent.putExtra("page-to-open", "promotions");
              PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
  
  
              NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, GoParty.PROMO_CHANNEL_ID)
                      .setSmallIcon(R.mipmap.ic_launcher_round)
                      .setContentTitle(title)
                      .setAutoCancel(true)
                      .setSound(defaultSound)
                      .setContentText(notificationContent)
                      .setContentIntent(pendingIntent)
                      .setStyle(style)
                      .setLargeIcon(bitmap)
                      .setWhen(System.currentTimeMillis())
                      .setPriority(NotificationCompat.PRIORITY_HIGH)
                      .setCategory(NotificationCompat.CATEGORY_MESSAGE);
  
              notificationManager.notify(0, notificationBuilder.build());
  
              Log.i("GoParty", "Notification sent ----- ");
  
          } catch (MalformedURLException e) {
              Logger.logGoParty(e.toString());
          } catch (IOException e) {
              Logger.logGoParty(e.toString());
          }
      }
  }
  </code></pre>
  
  <p>Notification Receiver:</p>
  
  <pre><code>public class NotificationReceiver extends BroadcastReceiver {
  
      @Override
      public void onReceive(Context context, Intent intent) {
  
          Intent notificationIntent = new Intent(context, NotificationService.class);
          NotificationService.enqueueWork(context, notificationIntent);
      }
  }
  </code></pre>
  
  <p>Manifest:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.goparty"&gt;
  
      &lt;uses-permission android:name="android.permission.INTERNET" /&gt;
      &lt;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /&gt;
      &lt;uses-permission android:name="android.permission.WAKE_LOCK" /&gt;
      &lt;uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /&gt;
  
  
      &lt;application
          android:name=".scopes.application.GoParty"
          android:allowBackup="true"
          android:icon="@mipmap/ic_launcher"
          android:label="@string/app_name"
          android:roundIcon="@mipmap/ic_launcher_round"
          android:supportsRtl="true"
          android:theme="@style/AppTheme"&gt;
  
          &lt;activity
              android:name=".MapsActivity"
              android:label="@string/title_activity_maps"
              android:screenOrientation="portrait"&gt;
              &lt;meta-data
                  android:name="android.support.PARENT_ACTIVITY"
                  android:value="com.goparty.LoginActivity" /&gt;
          &lt;/activity&gt;
  
          &lt;service
              android:name=".jobs.NotificationService"
              android:permission="android.permission.BIND_JOB_SERVICE" /&gt;
  
          &lt;receiver android:name=".receivers.NotificationReceiver"&gt;
              &lt;intent-filter&gt;
                  &lt;action android:name="android.intent.action.BOOT_COMPLETED" /&gt;
              &lt;/intent-filter&gt;
          &lt;/receiver&gt;
  
      &lt;/application&gt;
  
  &lt;/manifest&gt;
  </code></pre>