使用IntentService的附近消息

时间:2018-12-05 16:56:35

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

最初,我设置了一个BroadcastReceiver来接收来自Nearby Messages API的意图。

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()。为什么会这样?

2 个答案:

答案 0 :(得分:2)

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

SubscribeOptions

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

注意:
1.用options.setCallback(new SubscribeCallback() { @Override public void onExpired() { super.onExpired(); Toast.makeText(context.get(), "No longer Subscribing!", Toast.LENGTH_SHORT).show(); } } 测试后,没有得到Strategy.BLE_ONLY回调。
2.从Google的documentation

  

后台订阅比前台消耗的电量更少   订阅,但具有较高的延迟和较低的可靠性

在测试时,我发现这种“ 低可靠性”被轻描淡写:onFound很少被调用,而我却从未得到过onFound

答案 1 :(得分:0)

我知道这是一个较晚的答复,但是我遇到了同样的问题,并且通过调试发现这是与以下错误有关的问题:“试图从非活动上下文执行大功率操作”。在调用Nearby.getMessagesClient(this)时,可以通过传入活动上下文而不是传递此上下文来解决此问题。

在我的情况下,我添加了一个扩展应用程序的类,该类有助于返回此上下文(以下内容位于Java中,但应可轻松转换为kotlin)

public class MyApplication extends Application {
    private Activity currentActivity = null;

    public Activity getCurrentActivity(){
        return currentActivity;
    }
    public void setCurrentActivity(Activity mCurrentActivity){
        this.currentActivity = mCurrentActivity;
    }
}

在所有活动都从其扩展的基础活动中,我通过在构造函数中调用((MyApplication) this.getApplicationContext()).setCurrentActivity(this);来设置当前活动。

然后我的服务可以使用如下所示的正确上下文调用getMessagesClient:

final Activity context = ((MyApplication)getApplicationContext()).getCurrentActivity();
Nearby.getMessagesClient(context).[...]

不要忘记在AndroidManifest中注册您的Application类:

<application
android:name="com.example.xxx.MyApplication"`