Android Geofence only works with opened app

前端 未结 2 914
闹比i
闹比i 2020-12-13 16:44

I\'m doing a serious research on this topic for many days... I saw many topics here too... But unfortunately I couldn\'t find a solution....

I\'m writing an app that

相关标签:
2条回答
  • 2020-12-13 17:03

    I had a similar issue and after trying various ways I could finally fix the issue. Unfortunately, the android documentation fails to mention these issues.
    The android geofences get removed every time you reboot your device or every time you toggle the location mode. So Add a broadcast receiver to listen to device reboots and location mode changes, and add the geofences again in the receiver.

    I have posted a detailed explanation here

    0 讨论(0)
  • 2020-12-13 17:26

    I had the same exact problem. Here is what I answered over there: So after playing around with this a bit, it looks like the ReceiveTransitionsIntentService (as defined in the sample code) will stop getting the notifications when the app is not around. I think this is a big problem with the example code... Seems like that will trip folks like me up.

    So I used a broadcast receiver instead, and so far it seems to be working from my tests.

    Add this to the manifest:

    <receiver android:name="com.aol.android.geofence.GeofenceReceiver"
            android:exported="false">
            <intent-filter >
                <action android:name="com.aol.android.geofence.ACTION_RECEIVE_GEOFENCE"/>
            </intent-filter>
        </receiver>
    

    Then in the GeofenceRequester class you need to change the createRequestPendingIntent method so that it goes to your BroadcastReceiver instead of the ReceiveTransitionsIntentService. MAKE SURE AND NOTE the change to .getBroadcast instead of getService. That got me hung up for a while.

    private PendingIntent createRequestPendingIntent() {
    
            // If the PendingIntent already exists
            if (null != mGeofencePendingIntent) {
    
                // Return the existing intent
                return mGeofencePendingIntent;
    
            // If no PendingIntent exists
            } else {
    
                // Create an Intent pointing to the IntentService
                Intent intent = new Intent("com.aol.android.geofence.ACTION_RECEIVE_GEOFENCE");
    
                //MAKE SURE YOU CHANGE THIS TO getBroadcast if you are coming from the sample code.
                return PendingIntent.getBroadcast(
                        context,
                        0,
                        intent,
                        PendingIntent.FLAG_UPDATE_CURRENT);
            }
        }
    

    Then I added the GeofenceReceiver class that looks something like this:

    public class GeofenceReceiver extends BroadcastReceiver {
        Context context;
    
        Intent broadcastIntent = new Intent();
    
        @Override
        public void onReceive(Context context, Intent intent) {
            this.context = context;
    
            broadcastIntent.addCategory(GeofenceUtils.CATEGORY_LOCATION_SERVICES);
    
            if (LocationClient.hasError(intent)) {
                handleError(intent);
            } else {
                handleEnterExit(intent);
            }
        }
    
        private void handleError(Intent intent){
            // Get the error code
            int errorCode = LocationClient.getErrorCode(intent);
    
            // Get the error message
            String errorMessage = LocationServiceErrorMessages.getErrorString(
                    context, errorCode);
    
            // Log the error
            Log.e(GeofenceUtils.APPTAG,
                    context.getString(R.string.geofence_transition_error_detail,
                            errorMessage));
    
            // Set the action and error message for the broadcast intent
            broadcastIntent
                    .setAction(GeofenceUtils.ACTION_GEOFENCE_ERROR)
                    .putExtra(GeofenceUtils.EXTRA_GEOFENCE_STATUS, errorMessage);
    
            // Broadcast the error *locally* to other components in this app
            LocalBroadcastManager.getInstance(context).sendBroadcast(
                    broadcastIntent);
        }
    
    
        private void handleEnterExit(Intent intent) {
            // Get the type of transition (entry or exit)
            int transition = LocationClient.getGeofenceTransition(intent);
    
            // Test that a valid transition was reported
            if ((transition == Geofence.GEOFENCE_TRANSITION_ENTER)
                    || (transition == Geofence.GEOFENCE_TRANSITION_EXIT)) {
    
                // Post a notification
                List<Geofence> geofences = LocationClient
                        .getTriggeringGeofences(intent);
                String[] geofenceIds = new String[geofences.size()];
                String ids = TextUtils.join(GeofenceUtils.GEOFENCE_ID_DELIMITER,
                        geofenceIds);
                String transitionType = GeofenceUtils
                        .getTransitionString(transition);
    
                for (int index = 0; index < geofences.size(); index++) {
                    Geofence geofence = geofences.get(index);
                    ...do something with the geofence entry or exit. I'm saving them to a local sqlite db
    
                }
                // Create an Intent to broadcast to the app
                broadcastIntent
                        .setAction(GeofenceUtils.ACTION_GEOFENCE_TRANSITION)
                        .addCategory(GeofenceUtils.CATEGORY_LOCATION_SERVICES)
                        .putExtra(GeofenceUtils.EXTRA_GEOFENCE_ID, geofenceIds)
                        .putExtra(GeofenceUtils.EXTRA_GEOFENCE_TRANSITION_TYPE,
                                transitionType);
    
                LocalBroadcastManager.getInstance(MyApplication.getContext())
                        .sendBroadcast(broadcastIntent);
    
                // Log the transition type and a message
                Log.d(GeofenceUtils.APPTAG, transitionType + ": " + ids);
                Log.d(GeofenceUtils.APPTAG,
                        context.getString(R.string.geofence_transition_notification_text));
    
                // In debug mode, log the result
                Log.d(GeofenceUtils.APPTAG, "transition");
    
                // An invalid transition was reported
            } else {
                // Always log as an error
                Log.e(GeofenceUtils.APPTAG,
                        context.getString(R.string.geofence_transition_invalid_type,
                                transition));
            }
        }
    
        /**
         * Posts a notification in the notification bar when a transition is
         * detected. If the user clicks the notification, control goes to the main
         * Activity.
         * 
         * @param transitionType
         *            The type of transition that occurred.
         * 
         */
        private void sendNotification(String transitionType, String locationName) {
    
            // Create an explicit content Intent that starts the main Activity
            Intent notificationIntent = new Intent(context, MainActivity.class);
    
            // Construct a task stack
            TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
    
            // Adds the main Activity to the task stack as the parent
            stackBuilder.addParentStack(MainActivity.class);
    
            // Push the content Intent onto the stack
            stackBuilder.addNextIntent(notificationIntent);
    
            // Get a PendingIntent containing the entire back stack
            PendingIntent notificationPendingIntent = stackBuilder
                    .getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
    
            // Get a notification builder that's compatible with platform versions
            // >= 4
            NotificationCompat.Builder builder = new NotificationCompat.Builder(
                    context);
    
            // Set the notification contents
            builder.setSmallIcon(R.drawable.ic_notification)
                    .setContentTitle(transitionType + ": " + locationName)
                    .setContentText(
                            context.getString(R.string.geofence_transition_notification_text))
                    .setContentIntent(notificationPendingIntent);
    
            // Get an instance of the Notification manager
            NotificationManager mNotificationManager = (NotificationManager) context
                    .getSystemService(Context.NOTIFICATION_SERVICE);
    
            // Issue the notification
            mNotificationManager.notify(0, builder.build());
        }
    }
    

    Hopefully that helps someone else.

    0 讨论(0)
提交回复
热议问题