0

我试图在用户进入定义的区域以及用户退出该区域时通知用户。这就是我到目前为止所做的。我曾经使用 rangeNotifier 方法 (didBeaconsEnterRange) 来在用户进入某个区域时通知他/她,但随后此方法会每 1 秒调用一次,因此我将通知逻辑移至 monitorNotifier 类 (didEnterRegion) 方法。

我的应用程序类扩展了 BootStrapNotifier,我将 scanPeriod 设置为 2000 秒而不是默认的 1100l 秒,因为我似乎接收退出和进入通知的速度太快了,即使信标在范围内也是如此。早些时候,我什至将超时期限从 10000 毫秒增加到 20000 毫秒,当信标在超时期限内没有发出信号时,它会触发出口。

myapplication 类的代码片段

BeaconManager beaconManager = org.altbeacon.beacon.BeaconManager.getInstanceForApplication(this);
    beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout(LAYOUT_HERE));
    beaconManager.setForegroundScanPeriod(2000l);
    beaconManager.setBackgroundBetweenScanPeriod(1100l);
    //beaconManager.setBackgroundScanPeriod(5000l);
    beaconManager.setDebug(true);

    Log.d(TAG, "setting up background monitoring for beacons and power saving");
    // wake up the app when a beacon is seen
    mRegion = new Region("myRangingUniqueId",
            null, null, null);
    setRegionAgain();

SetRegionAgain 方法

if(SharedPrefs.getString(SharedPrefs.iBEACON_ID, "").trim().length() > 0) {
        if(SharedPrefs.getString(SharedPrefs.iBEACON_ID, "").trim().length() > 0 ) {
            try {
                mRegion = new Region("myRangingUniqueId",
                        Identifier.parse(SharedPrefs.getString(SharedPrefs.iBEACON_ID, "")), 
                        null, null);
            }catch(IllegalArgumentException e) {
                e.printStackTrace();
                mRegion = new Region("myRangingUniqueId",
                        null, null, null);
            }
        }
    }

    regionBootstrap = new RegionBootstrap(this, mRegion);

    // simply constructing this class and holding a reference to it in your custom Application
    // class will automatically cause the BeaconLibrary to save battery whenever the application
    // is not visible.  This reduces bluetooth power usage by about 60%
    backgroundPowerSaver = new BackgroundPowerSaver(this);

我有一个执行通知工作的后台服务,因此它实现了 BeaconConsumer 接口。下面的代码片段:

OnStart 方法:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    flagToCheckExit = false;
    mHandler = new Handler();
    beaconManager.bind(this);
    if (beaconManager.isBound(this)) beaconManager.setBackgroundMode(false);
    return Service.START_STICKY;
}

onDestroy 方法:

@Override
public void onDestroy() {
    super.onDestroy();
    try {
        beaconManager.stopMonitoringBeaconsInRegion(CommonUtilities.getRegion());
// this region is the one that i use to monitor (singleton types)
    } catch (RemoteException e) {
        e.printStackTrace();
    }

    beaconManager.unbind(this);
}

onServiceConnected 方法:

@Override
public void onBeaconServiceConnect() {
    beaconManager.setMonitorNotifier(new MonitorNotifier() {

        @Override
        public void didExitRegion(final Region region) {
            LogManager.d(TAG, "didExitRegion %s", region);

            if(SharedPrefs.getString(SharedPrefs.USER_ID, "").trim().length() > 0) {
                flagToCheckExit = true;
// i use this flag to prevent random entry and exit notifications
                mHandler.postDelayed(mRunnable, 20000);
// waiting for 20seconds before firing an exit notification, since an entry notification might get fired immediately after the exit
            }
        }

        @Override
        public void didEnterRegion(Region region) {
            Log.e(TAG,"region id1 >>> " + ((region.getId1() == null) ? "null" : region.getId1().toUuidString()));

            LogManager.d(TAG, "didEnterRegion %s ",region);

            if(!flagToCheckExit) {
                if(SharedPrefs.getString(SharedPrefs.USER_ID, "").trim().length() > 0) {
                    if(region.getId1() != null && 
                            region.getId1().toUuidString().equalsIgnoreCase(SharedPrefs.getString(SharedPrefs.iBEACON_ID, ""))) {
                        if(!SharedPrefs.getBoolean(SharedPrefs.IS_ENTRY_LOG_CALLED, false)) {
                            String entryRange = getAppContext().getString(R.string.entered_beacon_region);
                    CommonUtilities.sendNotification(MonitoringAltBeaconService.this,entryRange,1);
                        }
                    }
                }
            }else {
                // invalidate the handler
                // stop all operations of the handler
                // we do this to prevent an exit getting called since entry has been called immediately.
                mHandler.removeCallbacks(mRunnable);
            }
        }

        @Override
        public void didDetermineStateForRegion(int state, Region region) {
            LogManager.d(TAG, "didDetermineStateForRegion %s ",region);
        }
    });

    startMonitoring();
}

启动监控方法:

private void startMonitoring() {
    try {
        if(SharedPrefs.getString(SharedPrefs.iBEACON_ID, "").trim().length() > 0 ) {
            try {
                beaconManager.startMonitoringBeaconsInRegion(CommonUtilities.getRegion());
            }catch(IllegalArgumentException e) {
                e.printStackTrace();

                beaconManager.startMonitoringBeaconsInRegion(CommonUtilities.getRegion());
            }
        }
    } catch (RemoteException e) {   }
}

可运行线程:

Runnable mRunnable = new Runnable() {
    @Override
    public void run() {
        SharedPrefs.putBoolean(SharedPrefs.IS_ENTRY_LOG_CALLED, false);
        SharedPrefs.putBoolean(SharedPrefs.IS_EXIT_LOG_CALLED, true);

        String exitedRange = getAppContext().getString(R.string.exited_beacon_region);
        CommonUtilities.sendNotification(MonitoringAltBeaconService.this,exitedRange,2);
        LogManager.d(TAG, "exit called");
        flagToCheckExit = false;
    }
};

这有一个奇怪的行为,即使信标设备在范围内,我也会得到多个进入和退出日志,我得到了退出。我尝试绕过退出通知,但上面的逻辑(补丁)似乎失败了。

日志:

03-19 18:00:25.866: D/MonitoringAltBeaconService(22795): didDetermineStateForRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 
03-19 18:00:25.867: D/MonitoringAltBeaconService(22795): didExitRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null
03-19 18:00:26.470: D/MonitoringAltBeaconService(22795): didDetermineStateForRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 

03-19 18:00:26.477: D/MonitoringAltBeaconService(22795): didEnterRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 

03-19 18:00:48.076: D/MonitoringAltBeaconService(22795): didDetermineStateForRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 
03-19 18:00:48.076: D/MonitoringAltBeaconService(22795): didExitRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null

03-19 18:00:51.275: D/MonitoringAltBeaconService(22795): didDetermineStateForRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 
03-19 18:00:51.282: D/MonitoringAltBeaconService(22795): didEnterRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 
03-19 18:01:10.269: D/MonitoringAltBeaconService(22795): didDetermineStateForRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null
03-19 18:01:10.269: D/MonitoringAltBeaconService(22795): didExitRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null
03-19 18:01:15.876: D/MonitoringAltBeaconService(22795): didDetermineStateForRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 
03-19 18:01:15.883: D/MonitoringAltBeaconService(22795): didEnterRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 

我正在使用 AprilBeacon。我正在开发的应用程序被搁置,因为信标无法正确生成通知。请协助。

编辑:

我在 Motorolla g2 中使用的设备,这种情况发生在 kitkat 和棒棒糖版本中。并且 Wifi 开启,我更喜欢它开启,因为当确定入口退出时,涉及到 web 服务调用。实时,不鼓励用户关闭 wifi :(..

我使用的库是 android-beacon-library 我恐怕不知道 4 月信标发出信号的频率。

编辑2:

日志 1 可以在这里找到

日志 2 可以在这里找到

编辑 3

关闭wifi时记录 我注意到即使信标在范围内我也确实退出了并且我打开了定位应用程序,它显示没有信标存在(见屏幕截图)。我取出电池并将它们放回去它得到了信标,我的应用程序也是如此。(但在现实生活中,我相信电池不会被篡改)

未检测到时 取出电池后

4

3 回答 3

2

问题是一个不常见的广告信标和一个太短的自定义背景扫描间隔的组合。

信标似乎每 2 秒只做一次广告,因为这是我在日志中看到的最接近的两个后续检测时间戳。这是低传输频率是有问题的,并且因自定义设置而加剧。

为使磁带库正常运行,后台扫描周期必须至少是信标传输周期的 5 倍。这是因为并非所有蓝牙数据包都因无线电噪声而被接收。间隔是传输周期的 5 倍意味着在每个后台扫描周期有 5 次机会接收数据包,因此库不太可能错过一个。

默认库设置将后台扫描周期设置为 10 秒,这应该足以提供非常高的概率检测到即使是每 2 秒仅传输一次的信标,并且使不正确的区域退出非常非常罕见。

建议:

  1. 将后台扫描周期更改为至少默认值 10 秒。 为了节省电池,两次扫描之间的时间也应该更长——默认的 5 分钟是一个合理的选择,除非你有充分的理由缩短它。如果您仍然收到退出事件,请使后台扫描周期更长。

  2. 使用更频繁地做广告的不同信标。 尽管您应该能够使库与这些信标一起工作,但您不会经常获得更新,并且诸如 Locate 之类的应用程序会定期显示检测结果丢失。如果您在应用程序中进行距离估计,则需要以 10Hz 或更高频率传输的信标。如果您的应用程序中没有进行距离估计,您仍然应该使用以 1Hz 或更高频率传输的信标,否则您将更有可能遇到此类问题。

我怎么知道这是问题所在?

从下面的日志摘录中可以看到,错误的区域退出发生在 15:50:52,因为距离上一次检测已经 10 秒。任何没有检测到的 10 秒时间段都将在下次扫描周期停止时导致区域退出事件。因此,您必须非常确定扫描周期足够长以捕获信标传输。使用自定义设置,错过三个后续扫描周期的检测将导致区域退出。

03-26 15:49:49.533: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:49:55.567: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:01.624: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:08.898: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:11.315: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:17.380: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:21.010: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:26.440: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:30.066: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:33.108: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:36.120: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:39.745: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:41.573: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7

03-26 15:50:52.415: D/MonitorState(28596): We are newly outside the region because the lastSeenTime of 1427365241573 was 10841 seconds ago, and that is over the expiration duration of 10000
03-26 15:50:52.415: D/BeaconService(28596): found a monitor that expired: id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null
03-26 15:50:52.415: D/Callback(28596): attempting callback via intent: ComponentInfo{com.credencys.mycarline/org.altbeacon.beacon.BeaconIntentProcessor}

03-26 15:50:54.879: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:56.705: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:51:00.940: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:51:03.348: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:51:03.349: D/BeaconService(28596): looking for ranging region matches for this beacon
03-26 15:51:03.842: D/CycledLeScanner(28596): Waiting to stop scan cycle for another 1000 milliseconds
03-26 15:51:04.730: D/MonitoringAltBeaconService(28596): didExitRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null
于 2015-03-21T15:18:53.460 回答
2

您的配置似乎有效,但有一点缺陷。您应该设置了两个前台扫描配置:

beaconManager.setForegroundScanPeriod(2000l);
beaconManager.setForegroundBetweenScanPeriod(1100l);
//Update default time with the new one
beaconManager.updateScanPeriods();

或/和后台扫描配置:

beaconManager.setBackgroundScanPeriod(2000l);
beaconManager.setBackgroundBetweenScanPeriod(1100l);
//Update default time with the new one
beaconManager.updateScanPeriods();

另外,你知道信标的广告频率吗?您说您已将扫描周期增加到 20 秒,并且没有任何变化,仍然频率将有助于我们为您提供帮助。

顺便说一句,您还可以分享 AltBeacon 的 logcat 输出吗?另外,您的设备和型号是什么?它运行的是哪个 Android 版本?您使用的是哪个 AltBeacon 库版本?

如果您的设备正在运行 Lollipop,请尝试以下行并与我们分享结果:

BeaconManager.setAndroidLScanningDisabled(true);

此外,如果 WiFi 已打开,请尝试打开它,因为在某些设备中它会干扰蓝牙扫描。

顺便说一句,对不起,这更像是评论而不是答案,但它也渴望发表评论:)。

于 2015-03-20T08:50:54.820 回答
0

编辑:查看日志后,我提交了一个更好地回答问题的不同答案。请看那个答案。

我从两个发布的日志中注意到,该库报告该应用程序在后台并使用 Android L API。这导致他们使用“低延迟”检测:

03-26 15:47:21.647: D/CycledLeScannerForLollipop(28596): This is Android L. Doing a filtered scan for the background.

低延迟检测可以节省电力,但它们会延迟 5 秒或更长时间。这适用于后台操作,但不适用于前台操作,应与默认扫描间隔一起使用。 使用这些 Andorid L API 时,您永远不应该在扫描间隔之间设置非零值,否则您可能会遇到您描述的退出。

如果日志误报您的应用程序在后台,则可能是BackgroundPowerSaver.

您也可以尝试禁用 Android L API,并使用较旧的 4.x 扫描 API 来查看这是否更适合您的用例。如果您这样做,我还将删除任何特殊的扫描间隔设置,以免使您的配置过于复杂:

beaconManager.setAndroidLScanningDisabled(true)

onCreate在进行任何其他信标处理之前,您需要将该行放在您的应用程序类中。

于 2015-03-20T16:25:07.260 回答