Search code examples
androidgoogle-play-servicesandroid-pendingintentgoogle-nearby

Google Play Services Nearby registration failed with TOO_MANY_PENDING_INTENTS


On my application on login we're registering for Google Play Services nearby and on logout un-registering (code below). Even during registration, we're always first unsubscribing, before subscribing.

But after a few logout/login cycle the app keeps catching ApiException with the message ApiException: 2801: Will exceed MAX_PENDING_INTENTS_PER_APP=5

I know what the error means, but as far as I'm aware the code is unregistering first. So it shouldn't have reach that quota.

Subscribe code, run on-login and when beacons get updated

    val nearby = Nearby.getMessagesClient(app, MessagesOptions.Builder()
            .setPermissions(NearbyPermissions.BLE)
            .build())
    val task = apis
        .checkApiAvailability(nearby)
        .onSuccessTask { nearby.unsubscribe(BeaconReceiver.generatePendingIntent(app)) }
        .onSuccessTask {
            return@onSuccessTask if (beacons.isEmpty()) {
                // if beacons is empty, I don't have to register anything,
                Tasks.forResult(null as Void?)
            } else {
                val messageFilter = MessageFilter.Builder()
                beacons.forEach {
                    messageFilter.includeIBeaconIds(it.proximityUuid, it.major, it.minor)
                }

                val options = SubscribeOptions.Builder()
                    .setStrategy(Strategy.BLE_ONLY)
                    .setFilter(messageFilter.build())
                    .build()

                nearby.subscribe(BeaconReceiver.generatePendingIntent(app), options)
            }
        }
    // inside awaitResult there's Task.await, and catch/log exceptions
    val result = awaitResult("Beacon", 30, task)

Unsubscribe code, run on every logout, almost the same as subscribe

    val nearby = Nearby.getMessagesClient(app, MessagesOptions.Builder()
        .setPermissions(NearbyPermissions.BLE)
        .build())
    val geofence = GeofencingClient(app)
    val task = GoogleApiAvailability.getInstance().checkApiAvailability(nearby, geofence)
        .onSuccessTask { nearby.unsubscribe(BeaconReceiver.generatePendingIntent(app)) }
        .onSuccessTask { geofence.removeGeofences(GeofenceReceiver.generatePendingIntent(app)) }
    val result = awaitResult("SdkDisabled", 30, task)

and the PendingIntent code, it uses our explicit class and a static request code:

val intent = Intent(context, BeaconReceiver::class.java)
return PendingIntent.getBroadcast(context, BEACON_REQUEST_CODE, intent, PendingIntent.FLAG_CANCEL_CURRENT)

So question:

Why it's throwing exception and what can I do to properly unregister/unsubscribe?


Solution

  • Remove the PendingIntent.FLAG_CANCEL_CURRENT on the call to getBroadcast() when you unsubscribe.

    When you unsubscribe, you need to provide a PendingIntent that "matches" the one you used to subscribe. By using FLAG_CANCEL_CURRENT you are canceling the existing PendingIntent and creating a new one and obvioulsy the new one does not "match" the one you used when you subscribed.

    IMHO this is a bug in the Play Services library, because it isn't using the correct "matching" algorithm, because the PendingIntents should "match".