简体   繁体   English

Android BLE邻近通知

[英]Android BLE proximity notifications

I've been working on developing an application that interacts with BLE devices. 我一直在开发一个与BLE设备交互的应用程序。 Everything works great, I can scan, connect, and consume services. 一切都很好,我可以扫描,连接和使用服务。

I've been reading through all the docs and I do not see anything that gives the developer the option of listening for BLE devices. 我一直在阅读所有文档,我没有看到任何让开发人员选择监听BLE设备的东西。 Basically I would like to trigger a broadcast receiver when the devices enters the range of a BLE device. 基本上我想在设备进入BLE设备范围时触发广播接收器。

I know I could continually scan for this, but battery use is way too high and I would like this to be invoked even when my application is not being used. 我知道我可以继续扫描这个,但电池使用率太高了,我希望即使我的应用程序没有被使用也可以调用它。

Is this feature not supported or am I missing a section of the docs that discuss this? 是不支持此功能还是我错过了讨论此内容的部分文档?

I have done a project recently, and from what I read in your question it has some similarity to what I did. 我最近做了一个项目,从我在你的问题中看到的,它与我所做的有些相似。

I know I could continually scan for this but battery use is way too high and I would like this to be invoked even when my application is not being used. 我知道我可以继续扫描这个,但电池使用率太高了,我希望即使我的应用程序没有被使用也可以调用它。

Regarding battery problem, having Bluetooth on all the time is power consuming, but at the same time you can not detect BLE with out having Bluetooth on. 关于电池问题,一直使用蓝牙是耗电的,但同时你无法在没有蓝牙的情况下检测到BLE。

What I did is two experiments and both are useful but are different and I can not say which one is best, but you need to test it so it fits your requirement. 我做的是两个实验,两个都很有用,但不同,我不能说哪一个最好,但你需要测试它,以满足你的要求。

  1. Having Thread running that turns Bluetooth on and listen to iBeacon and off (with sleeping time) for while programmatically. 让线程运行打开蓝牙并以编程方式监听iBeacon并关闭(使用休眠时间)。 It can be done many ways. 它可以通过多种方式完成。

  2. Using a package called Altbeacon, has a lot of useful features, one of those features is Auto Battery Saving with example code : 使用名为Altbeacon的软件包,有许多有用的功能,其中一个功能是使用示例代码自动节省电池:

     public class MyApplication extends Application implements BootstrapNotifier { private BackgroundPowerSaver backgroundPowerSaver; public void onCreate() { super.onCreate(); // Simply constructing this class and holding a reference to it // in your custom Application class // enables auto battery saving of about 60% backgroundPowerSaver = new BackgroundPowerSaver(this); } } 

We need a broadcast event, that wakes up our app once a BLE-device with a certain Service-UUID is in reach. 我们需要一个广播事件,一旦具有特定Service-UUID的BLE设备到达,就会唤醒我们的应用程序。 Maybe now there is a better BLE API available than 2 years ago. 也许现在有比2年前更好的BLE API。 The most energy saving and most precise method gets rewarded. 最节能,最精确的方法得到回报。

Your other part, it is called triggering actions at a specific distance. 你的另一部分,它被称为特定距离的触发动作。 I still use the Altbeacon to check beacon range and triggering action. 我仍然使用Altbeacon来检查信标范围和触发动作。 A sample code is something like 示例代码就像

@Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
    for (Beacon beacon : beacons) {
        if (beacon.getDistance() < 5.0) {
            Log.d(TAG, "I see a beacon that is less than 5 meters away.");
            // Perform distance-specific action here
        }
    }
}

So when that said, you can also get distance of specific UUID I build a method based on Altbeacon, looks like this (Look inside the for loop and if statement): 所以当说,你也可以获得特定UUID的距离我构建一个基于Altbeacon的方法,看起来像这样(查看for循环和if语句):

private void startRangeNotifier() {
    Log.i(TAG, "Starting range notifier...");
    beaconManager.setRangeNotifier(new BeaconRangeListener() {
        @Override
        public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {

            if (beacons.size() > 0) {
                for (Beacon beacon : beacons) {
                    Log.d(TAG, "uuid's: " + beacon);
                    Log.d(TAG, "uuid id1: " + beacon.getId1());
                    if (beacon.getId1().toString()
                            .equals("b9407f30-f5f8-466e-aff9-25556b57fe6d")) {
                        Log.d(TAG, "uuid id1 distance: " + beacon.getDistance());
                    }
                }

            }
        }
    });

    try {
        beaconManager.startRangingBeaconsInRegion(
                new Region(BEACON_MONITORING_ID, null, null, null));
    } catch (RemoteException e) {
        e.printStackTrace();
    }
}

My log output: 我的日志输出:

D/Main activity:: uuid's: id1: b9407f30-f5f8-466e-aff9-25556b57fe6d id2: 31807 id3: 59251
D/Main activity:: uuid id1: b9407f30-f5f8-466e-aff9-25556b57fe6d
D/Main activity:: uuid id1 distance: 0.2108658568686884

In my answer I wanted to present the concept I used, Beacons project need patience in general. 在我的回答中,我想提出我使用的概念,Beacons项目总体上需要耐心。 As the other answer mentioned it is also possible to combine the solution here with Geofences and ActivityRecognition. 正如另一个答案所提到的,也可以将此处的解决方案与Geofences和ActivityRecognition结合起来。

Note: Since the nature of bluetooth beacon, the distance is proximity and not absolute, and some time even the bluetooth beacon is 1 meter a way it might show 2 meter or 0.5 meter, so have that in mind 注意:由于蓝牙信标的性质,距离是接近而不是绝对的,有时甚至蓝牙信标是1米的方式,它可能显示2米或0.5米,所以请记住

Link reference: 链接参考:

BLE scanning on Android is pretty battery intensive, and it's definitely not something you want to do in the background all the time. Android上的BLE扫描非常耗电,而且它绝对不是您想要在后台执行的操作。 If you are working on a background application with stationary bluetooth devices (à la ibeacons) that you know the location of, you can use Geofences to turn scanning on and off when you think you are in the approximate proximity of a device. 如果您正在处理具有固定蓝牙设备(àlabebeons)的后台应用程序,您知道其位置,则可以使用Geofences在您认为距离设备大致接近时打开和关闭扫描。 If you are not careful geofencing can also drain battery. 如果你不小心地理围栏也可以耗尽电池。

If you don't know the location of your bluetooth devices I guess you can also play tricks with ActivityRecognition , ie only scan periodically when the user is walking and stopping it if the user is stationary/running/biking/in vehicle. 如果您不知道蓝牙设备的位置,我猜您也可以使用ActivityRecognition玩弄技巧,即只在用户步行时定期扫描并在用户静止/跑步/骑车/车辆时停止。 Again, the activity recognition stuff also takes battery so you are going to have to be judicious. 同样,活动识别的东西也需要电池,所以你必须要明智。

We need a broadcast event, that wakes up our app once a BLE-device with a certain Service-UUID is in reach. 我们需要一个广播事件,一旦具有特定Service-UUID的BLE设备到达,就会唤醒我们的应用程序。

You probably know how to filter scan results by Service UUID so I won't go into that. 您可能知道如何按服务UUID过滤扫描结果,所以我不会进入。 About the waking up: if your app is scanning, it is awake by definition. 关于醒来:如果你的应用正在扫描,它的清晰度就是清醒。 It may or may not be on the foreground, but it is awake. 它可能是也可能不是前景,但它是清醒的。

Maybe now there is a better BLE API available than 2 years ago. 也许现在有比2年前更好的BLE API。

Since SDK version 21, there is a new API that you can use for BLE scanning. 自SDK版本21以来,您可以使用新的API进行BLE扫描。 To my knowledge, the only difference is the way you access the API and the underlying functionality (regarding power consumption etc.) has not changed. 据我所知,唯一的区别是您访问API的方式和底层功能(关于功耗等)没有改变。


About the scanning: 关于扫描:
It's true that scanning is battery-intensive. 扫描是电池密集型的。 Even the docs say so. 甚至文档也这么说。

The intensity is relative though. 虽然强度是相对的。 It is intensive compared to not scanning at all, but it is not intensive enough that it will hopelessly drain your battery. 与完全不扫描相比,这是非常密集的,但它不够密集,以至于它将无可救药地耗尽电池。 It's called low energy after all. 毕竟它被称为低能量

An other answer suggest monitoring Geofences and only scan when you know you are in range of BLE devices. 另一个答案建议监控Geofences,只有当您知道自己处于BLE设备范围内时才会进行扫描。 While this will lower the battery consumption of the ble scan , it will need that battery power for the GPS, otherwise it can't monitor the Geofences (well, it can, with cellular/wifi data, but then it won't be nearly as accurate). 虽然这会降低ble扫描的电池消耗,但它需要为GPS提供电池电量,否则无法监控Geofences(好吧,它可以,使用蜂窝/ wifi数据,但它不会接近如准确)。


Depending on how time critical your scanning is (eg if there is a device nearby, must you know it right away ? or is it okay if it's delayed a couple seconds?) you can implement a pause inbetween scans. 根据您的扫描时间如何关键的是(例如,如果附近有设备, 必须要知道它的时候了 ?或者是好的,如果它的延迟几秒钟?)可以实现暂停其间扫描。

Say you scan for 5 seconds, pause for 5 seconds, scan for 5 seconds again. 假设您扫描5秒钟,暂停5秒钟,再次扫描5秒钟。 That way you will be scanning almost all the time, yet only consume roughly half of the battery power. 这样你几乎可以一直扫描,但只消耗大约一半的电池电量。 These intervals can be tweaked to match your situation. 可以调整这些间隔以符合您的情况。 Maybe you're okay with scanning 3 seconds and pausing for 10. (note that the maximum time between a device's broadcasts is 10.24 seconds ). 也许你可以通过扫描3秒钟并暂停10秒钟。(请注意, 设备广播之间的最长时间为10.24秒 )。

I have an app with about 50 users that scans with pauses like this (scan for 3 seconds, pause for 3, repeat) 24/7 in the background, and have not received any complaints about excessive battery usage. 我有一个大约50个用户的应用程序,在后台扫描这样的暂停(扫描3秒,暂停3,重复)24/7,并没有收到任何关于过度使用电池的投诉。

If you have a specific BLE peripheral you want to detect, then figure out its advertisement period. 如果您想要检测特定的BLE外围设备,请找出其广告时段。 If you have different devices, find the longest advertisement period. 如果您有不同的设备,请找到最长的广告时段。 Scan longer than the advertisement period of the device, so you get at least one advertisement message. 扫描时间长于设备的广告时段,因此您至少会收到一条广告消息。 Repeat this scanning periodically with the frequency that is suitable for your use case. 定期以适合您用例的频率重复扫描。 Eg Your peripheral is advertising every second once. 例如,您的外围设备每秒都会广告一次。 You would like to detect the device in 5s when it comes to proximity. 在接近时,您希望在5秒内检测到设备。 Then Scan for 1s (or a bit more). 然后扫描1秒(或更多)。 Switch off scanning for 4s. 关闭扫描4秒。 This way you can save battery. 这样可以节省电量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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