Search code examples
androidandroid-servicealarmmanagerandroid-workmanager

Isn't there any way to show notification when app is closed in all devices?


I want to send a notification to user if there is any changes in firebase database. I have tried using Broadcast-Receiver, Service, Work-Manager, Alarm-Manager. But none of them works perfectly. It only works when app is running or in background and also working in some devices[tested in android 7] when app is closed. But In android 10[tested in Samsung and Xiaomi], it's not working when app is closed. When I turn off battery saver in my app in Xiaomi, it works sometime after closing app, then stops working. Some people said, You have turn-off battery saver and turn-on auto-start mode in Xiaomi and do something in other manufacturers phone. But there are many app that shows notification even though I haven't open the app for more that 10/15 days and I have checked in app-info of those app that battery-saver in on and auto-start is off[checked in Xiaomi-android10]. What am I doing wrong? Service:

public class ServiceManager extends Service {


public ServiceManager() {}

@Override
public IBinder onBind(Intent intent) {
    // TODO Auto-generated method stub
    return null;
}

@Override
public void onCreate() {
    getLastModifiedTime2(new HomePage.MyCallback() {
        @Override
        public void onCallback(String roll) {
            SharedPreferences spExtra = getSharedPreferences("spExtra",MODE_PRIVATE);
            if(!Objects.equals(spExtra.getString("1", "No changes"), roll)){
                SharedPreferences.Editor editor = spExtra.edit();
                editor.putString("1",roll);
                editor.apply();
                showNotification(getApplicationContext());
                //
            }
        }
    });
}

@Override
public void onDestroy() {
}
@Override
public int onStartCommand(Intent intent, int flags, int startid) {
    System.out.println("called start command");
    //
    getLastModifiedTime2(new HomePage.MyCallback() {
        @Override
        public void onCallback(String roll) {
            SharedPreferences spExtra = getSharedPreferences("spExtra",MODE_PRIVATE);
            if(!Objects.equals(spExtra.getString("1", "No changes"), roll)){
                SharedPreferences.Editor editor = spExtra.edit();
                editor.putString("1",roll);
                editor.apply();
                showNotification(getApplicationContext());
            }
        }
    });
    //
    return START_STICKY;
}

private void stopService() {
}
 //not showing the method getlastmodifiedtime2 and shownotification;
}

and starting service that below:

startService(new Intent(this, ServiceManager.class));

Work-manager:

public class UploadWorker extends Worker {

public UploadWorker(
        @NonNull Context context,
        @NonNull WorkerParameters workerParams){
    super(context, workerParams);
}

@NonNull
@Override
public Result doWork() {
    System.out.println("UploadWorker called");
    getLastModifiedTime2(new HomePage.MyCallback() {
        @Override
        public void onCallback(String roll) {
            SharedPreferences spExtra = getApplicationContext().getSharedPreferences("spExtra",MODE_PRIVATE);
            if(!Objects.equals(spExtra.getString("1", "No changes"), roll)){
                SharedPreferences.Editor editor = spExtra.edit();
                editor.putString("1",roll);
                editor.apply();
                showNotification(getApplicationContext());
                //
            }
            //startNewRequest();
        }
    });
    return Result.success();
    //return Result.Retry.retry();
}
//not showing function getlastmodifiedtime2 and shownotification
}

calling worker like below:

PeriodicWorkRequest workRequest = new PeriodicWorkRequest
                .Builder(UploadWorker.class,15,TimeUnit.MINUTES).build();
        WorkManager.getInstance(this).enqueueUniquePeriodicWork("firebaseTest",
                ExistingPeriodicWorkPolicy.KEEP,workRequest);

and alarm-manager code:

Calendar cal = Calendar.getInstance();
    Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(System.currentTimeMillis());
    calendar.set(Calendar.HOUR_OF_DAY, 12);
    calendar.set(Calendar.MINUTE, 25);
    calendar.set(Calendar.SECOND, 30);

    Intent intent = new Intent(HomePage.this, ServiceManager.class);
    PendingIntent pintent = PendingIntent.getService(HomePage.this, 0, intent, 0);
    AlarmManager alarm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
    System.out.println("called alarm-intent");
    System.out.println("called"+cal.getTimeInMillis());
    alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 60*1000, pintent);

All of them are not working when app is closed. Some people says to use foreground services, but won't it show a notification all the time. What process should I use to do my work[notifying user when data is changed in firebase].


Solution

  • All of them given above aren't working when app is killed or closed. Then I tried Firebase cloud messaging and it worked[tested in android 7,10] even if app is closed or killed.

    RequestQueue requestQueue;
    requestQueue = Volley.newRequestQueue(this);
    

    --

    public void sendNotificationToUser() {
            JSONObject mainObj = new JSONObject();
            try {
                mainObj.put("to", "/topics/" + topic_name);//
                JSONObject notificationObj = new JSONObject();
                notificationObj.put("title", "About title");
                notificationObj.put("body", "Enter you message here");
                mainObj.put("notification", notificationObj);
    
                JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, value,
                        mainObj, new Response.Listener<JSONObject>() {//value="https://fcm.googleapis.com/fcm/send"
                    @Override
                    public void onResponse(JSONObject response) {
                    }
                }, new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
    
                    }
                }) {
                    @Override
                    public Map<String, String> getHeaders() throws AuthFailureError {
    
                        Map<String, String> header = new HashMap<>();
                        header.put("content-type", "application/json");
                        header.put("authorization", "key=" + server-key);
                        return header;
                    }
                };
                Toast.makeText(this, "Successfully added", Toast.LENGTH_SHORT).show();
                requestQueue.add(jsonObjectRequest);
                //
        }
    }
    

    Make sure to import

    implementation 'com.mcxiaoke.volley:library:1.0.19'
    

    Don't put your server-key inside your app. You can use Firebase cloud function for this[not free]. Above code will send notification to all of the user who are subcribed to topic_name.