android - 使用 IntentService 的附近消息

标签 android beacon android-intentservice google-nearby android-ble

最初我设置了一个 BroadcastReceiver 来接收来自 Nearby Messages API 的 intents .

class BeaconMessageReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        Nearby.getMessagesClient(context).handleIntent(intent, object : MessageListener() {
            override fun onFound(message: Message) {
                val id = IBeaconId.from(message)
                Timber.i("Found iBeacon=$id")
                sendNotification(context, "Found iBeacon=$id")
            }

            override fun onLost(message: Message) {
                val id = IBeaconId.from(message)
                Timber.i("Lost iBeacon=$id")
                sendNotification(context, "Lost iBeacon=$id")
            }
        })
    }

    private fun sendNotification(context: Context, text: String) {
        Timber.d("Send notification.")
        val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        val notification = NotificationCompat.Builder(context, Notifications.CHANNEL_GENERAL)
                .setContentTitle("Beacons")
                .setContentText(text)
                .setSmallIcon(R.drawable.ic_notification_white)
                .build()

        manager.notify(NotificationIdGenerator.nextID(), notification)
    }

}

然后在授予位置权限后在我的 MainActivity 中注册此接收器。

class MainActivity : AppCompatActivity() {

    // ...

    private fun onLocationPermissionsGranted() {
        val filter = MessageFilter.Builder()
                .includeIBeaconIds(UUID.fromString("B9407F30-F5F8-466E-AFF9-25556B57FEED"), null, null)
                .build()

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

        Nearby.getMessagesClient(context).subscribe(getPendingIntent(), options)
    }

    private fun getPendingIntent(): PendingIntent = PendingIntent.getBroadcast(
            this, 0, Intent(context, BeaconMessageReceiver::class.java), PendingIntent.FLAG_UPDATE_CURRENT)

}

这在应用程序打开时运行良好,但在应用程序关闭时不起作用。所以我找到了this example ,它演示了如何设置 IntentService 以在应用程序处于后台时接收消息。

该示例确实使用了 Nearby.Messages类,已弃用,取而代之的是 MessagesClient .因此,我用 MessagesClient 实现替换了已弃用的代码。

class MainActivity : AppCompatActivity() {

    // ...

    private fun onLocationPermissionsGranted() {
        val filter = MessageFilter.Builder()
                .includeIBeaconIds(UUID.fromString("B9407F30-F5F8-466E-AFF9-25556B57FEED"), null, null)
                .build()

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

        Nearby.getMessagesClient(context).subscribe(getPendingIntent(), options)
            .addOnSuccessListener {
                Timber.i("Subscribed successfully.")
                startService(Intent(this, BeaconMessageIntentService::class.java))
            }.addOnFailureListener {
                Timber.e(exception, "Subscription failed.")
            }
    }

    private fun getPendingIntent(): PendingIntent = PendingIntent.getBroadcast(
            this, 0, Intent(context, BeaconMessageIntentService::class.java), PendingIntent.FLAG_UPDATE_CURRENT)

}

这是 IntentService(与我的 BroadcastReceiver 几乎相同)。

class BeaconMessageIntentService : IntentService("BeaconMessageIntentService") {

    override fun onHandleIntent(intent: Intent?) {
        intent?.let {
            Nearby.getMessagesClient(this)
                    .handleIntent(it, object : MessageListener() {
                        override fun onFound(message: Message) {
                            val id = IBeaconId.from(message)
                            Timber.i("Found iBeacon=$id")
                            sendNotification("Found iBeacon=$id")
                        }

                        override fun onLost(message: Message) {
                            val id = IBeaconId.from(message)
                            Timber.i("Lost iBeacon=$id")
                            sendNotification("Lost iBeacon=$id")
                        }
                    })
        }
    }

    private fun sendNotification(text: String) {
        Timber.d("Send notification.")
        val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        val notification = NotificationCompat.Builder(this, Notifications.CHANNEL_GENERAL)
                .setContentTitle("Beacons")
                .setContentText(text)
                .setSmallIcon(R.drawable.ic_notification_white)
                .build()

        manager.notify(NotificationIdGenerator.nextID(), notification)
    }

}

onHandleIntent被调用,并且Intent不为null;但由于某些原因,onFound()onLost() 从未被调用。为什么会这样?

最佳答案

这不是真正的解决方案,但我发现的是这个(credit to this answer):
我已经尝试了一些配置,包括 BroadcastReceiver 和添加 JobIntentService 以在后台运行代码,但每次我得到这个 onExpired 可以设置为 SubscribeOptions 的回调:

options.setCallback(new SubscribeCallback() {
    @Override
    public void onExpired() {
        super.onExpired();
        Toast.makeText(context.get(), "No longer Subscribing!", Toast.LENGTH_SHORT).show();
    }
}

当订阅发生在后台时,它被延迟了,但它仍然被调用。

注意事项:
1. 当我使用 Strategy.BLE_ONLY 进行测试时,我没有得到 onFound 回调。
2. 来自谷歌的documentation :

Background subscriptions consumes less power than foreground subscriptions, but have higher latency and lower reliability

在测试时,我发现这种“可靠性较低”是一种轻描淡写的说法:onFound 很少被调用,而且我从未得到 onLost

关于android - 使用 IntentService 的附近消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53637194/

相关文章:

android - 使用不包含MediaQuery的上下文调用MediaQuery.of()。错误

ios - 是否可以使用 Objective C 扫描禁用位置服务的信标?

android - android平台上使用altbeacon库后台监控Eddystone beacon

swift - iOS 应用程序与 iBeacon 一起奇怪地工作

android - 无法使用 alarmmanager 定期在后台工作

安卓动态标签

java - SwipeRefreshLayout + AsyncTask : Fail to refresh data

Android IntentService 无法实例化类;没有空的构造函数

android - IntentService 中的数据库操作导致应用程序停止、变得无响应并给出 ANR

java - 扩展 NavigationDrawer Activity