简体   繁体   中英

Geofencing when app is dead

The new Geofencing API from Google is not triggering any of the events when the app is dead. I tried using PendingIntent.getBroadcast() and PendingIntent.getService() but only being able to get the transition events when the app is opened.

I followed this tutorial from code labs but adapted the code to use the new GeofencingClient

UPDATE

This is how I create the pending intent:

private PendingIntent getGeofencePendingIntent() {
    if (mGeofencePendingIntent != null) {
        Log.d(TAG, "Pending intent is already there");
        return mGeofencePendingIntent;
    }
    Log.d(TAG, "Creating a new pending intent");

    // In case I'm using Service, the second parameter will be GeoIntentService.class
    Intent mIntent = new Intent(mContext, GeoReceiver.class);

    // In case I'm using Service, the method will be getService(...)
    mGeofencePendingIntent = PendingIntent.getBroadcast(mContext, 0, mIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        return mGeofencePendingIntent;
 }

The code inside my GeoReceiver's onReceive method. Somehow the code is similar when using Services inside onHandleIntent method

@Override
public void onReceive(Context context, Intent intent) {
    Log.d(TAG, "onReceive");
    if (intent == null) {
        Log.e(TAG, "Intent is null");
        return;
    }
    final String action = intent.getAction();
    if (ACTION_ADD_GEOFENCE.equals(action)) {
        GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
        if (geofencingEvent.hasError()) {
            String errMsg = GeofenceExceptionMessages.getErrorString(context, geofencingEvent.getErrorCode());
            Log.e(TAG, "onReceive Error: " + errMsg);
            return;
        }
        int geofenceTransition = geofencingEvent.getGeofenceTransition();
        if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
                    geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {

            List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();

            NotificationHelper helper = new NotificationHelper();

            String geofenceTransitionDetails = helper.getGeofenceTransitionDetails(
                    context,
                    geofenceTransition,
                    triggeringGeofences
            );

            helper.sendNotificaiton(context, geofenceTransitionDetails);
            Log.i(TAG, "onReceive: " + geofenceTransitionDetails);
        }
    } else {
        Log.d(TAG, "Diffirent Action: " + action);
    }
}

Geofencing is not working because some devices only allow background services for some whitelist app by default. If your app also has to work like that means you have to enable AutoStart from settings, below code will help you to make user to enable autostart for your app.If AutoStart is enabled, your service will work well in background.

For the better performance of the Phone, some companies will stop all the background services of the app("Some whitelisted App's will only have the permission to do services in background, eg: WhatsApp,Google Apps and well recognized apps.").So If our app also has to work like that means,we have to enable Autostart Services.

AutoStart:

When an Android system boots, it sends out a boot complete event. Android applications can listen and capture this event to take specific actions, such as automatically starting an activity or service.

As of now,there is no way to determine whether AutoStart is enabled or not. So you can redirect them to settings and tell user to enable it.I'am providing codes for redirecting for most common phone's companies which will kill background service.(Show it to user only for once, manage it using SharedPreference, as i told earlier there is no way to determine whether it is enabled or disabled.)

To Achieve this,

Declare the permission in AndroidManifest.xml . Add the android.permission.RECEIVE_BOOT_COMPLETED permission to your application's manifest file just before the application declaration node:

This is the function code which has to be called.

private void enableAutoStart() {
    if (Build.BRAND.equalsIgnoreCase("xiaomi")) {
      new MaterialDialog.Builder(MainActivity.this).title("Enable AutoStart")
        .content(
          "Please allow AppName to always run in the background,else our services can't be accessed.")
        .theme(Theme.LIGHT)
        .positiveText("ALLOW")
        .onPositive(new MaterialDialog.SingleButtonCallback() {
          @Override
          public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {

            Intent intent = new Intent();
            intent.setComponent(new ComponentName("com.miui.securitycenter",
              "com.miui.permcenter.autostart.AutoStartManagementActivity"));
            startActivity(intent);
          }
        })
        .show();
    } else if (Build.BRAND.equalsIgnoreCase("Letv")) {
      new MaterialDialog.Builder(MainActivity.this).title("Enable AutoStart")
        .content(
          "Please allow AppName to always run in the background,else our services can't be accessed.")
        .theme(Theme.LIGHT)
        .positiveText("ALLOW")
        .onPositive(new MaterialDialog.SingleButtonCallback() {
          @Override
          public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {

            Intent intent = new Intent();
            intent.setComponent(new ComponentName("com.letv.android.letvsafe",
              "com.letv.android.letvsafe.AutobootManageActivity"));
            startActivity(intent);
          }
        })
        .show();
    } else if (Build.BRAND.equalsIgnoreCase("Honor")) {
      new MaterialDialog.Builder(MainActivity.this).title("Enable AutoStart")
        .content(
          "Please allow AppName to always run in the background,else our services can't be accessed.")
        .theme(Theme.LIGHT)
        .positiveText("ALLOW")
        .onPositive(new MaterialDialog.SingleButtonCallback() {
          @Override
          public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
            Intent intent = new Intent();
            intent.setComponent(new ComponentName("com.huawei.systemmanager",
              "com.huawei.systemmanager.optimize.process.ProtectActivity"));
            startActivity(intent);
          }
        })
        .show();
    } else if (Build.MANUFACTURER.equalsIgnoreCase("oppo")) {
      new MaterialDialog.Builder(MainActivity.this).title("Enable AutoStart")
        .content(
          "Please allow AppName to always run in the background,else our services can't be accessed.")
        .theme(Theme.LIGHT)
        .positiveText("ALLOW")
        .onPositive(new MaterialDialog.SingleButtonCallback() {
          @Override
          public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
            try {
              Intent intent = new Intent();
              intent.setClassName("com.coloros.safecenter",
                "com.coloros.safecenter.permission.startup.StartupAppListActivity");
              startActivity(intent);
            } catch (Exception e) {
              try {
                Intent intent = new Intent();
                intent.setClassName("com.oppo.safe",
                  "com.oppo.safe.permission.startup.StartupAppListActivity");
                startActivity(intent);
              } catch (Exception ex) {
                try {
                  Intent intent = new Intent();
                  intent.setClassName("com.coloros.safecenter",
                    "com.coloros.safecenter.startupapp.StartupAppListActivity");
                  startActivity(intent);
                } catch (Exception exx) {

                }
              }
            }
          }
        })
        .show();
    } else if (Build.MANUFACTURER.contains("vivo")) {
      new MaterialDialog.Builder(MainActivity.this).title("Enable AutoStart")
        .content(
          "Please allow AppName to always run in the background.Our app runs in background else our services can't be accesed.")
        .theme(Theme.LIGHT)
        .positiveText("ALLOW")
        .onPositive(new MaterialDialog.SingleButtonCallback() {
          @Override
          public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
            try {
              Intent intent = new Intent();
              intent.setComponent(new ComponentName("com.iqoo.secure",
                "com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity"));
              startActivity(intent);
            } catch (Exception e) {
              try {
                Intent intent = new Intent();
                intent.setComponent(new ComponentName("com.vivo.permissionmanager",
                  "com.vivo.permissionmanager.activity.BgStartUpManagerActivity"));
                startActivity(intent);
              } catch (Exception ex) {
                try {
                  Intent intent = new Intent();
                  intent.setClassName("com.iqoo.secure",
                    "com.iqoo.secure.ui.phoneoptimize.BgStartUpManager");
                  startActivity(intent);
                } catch (Exception exx) {
                  ex.printStackTrace();
                }
              }
            }
          }
        })
        .show();
    }
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM