如何使用 Altbeacon 在后台对信标进行测距:Android 信标库?

How to range beacons in background using Altbeacon: Android Beacon Library?

我正在开发一个提供后台 Beacon 监控的应用程序。当用户从定义的区域进入信标时,我想开始测距。当应用程序处于后台并且它一直在监视并且用户进入我定义的区域时,我想开始测距并获取 InstanceID 或 Major,Minor 值以确定那是什么信标,连接到服务器并向用户发送通知。最好的情况是我可以在后台与服务器进行范围和通信。我用这个例子来实现后台监控:https://altbeacon.github.io/android-beacon-library/samples.html. I also downloaded sample project from here: https://github.com/AltBeacon/android-beacon-library-reference 以此为基础

不幸的是,在这个例子中,当用户进入区域 Activity 时启动...我不希望这种情况发生。所以我的问题是:是否可以在后台对信标进行测距?

在我的案例中也发生了奇怪的事情,因为当我将我的应用程序置于后台时,方法 "didRangeBeaconsInRegion(Collection beacons, Region region)" 仍然从 MainActivity 调用,但没有找到信标。此外,由于 beaconManager 处于后台模式,方法调用频率较低。当我启动没有发生的示例项目时。可能是因为我没有监控Activity。 My MainActivity 在启动时立即进行测距。当然,我尝试将所有内容设置为与 BeaconReferenceApplication 示例中的完全相同。

顺便说一句,我正在使用 Android 6.0.1

在 Nexus 5 上测试我的应用程序

提前感谢您提供任何解决方案!

我终于知道怎么做了!其实我很简单,我从一开始就做对了,但我一直在使用旧版本的 Altbeacon 库,这导致了我所有的问题......嗯

没关系。这是我的代码。也许有人可以使用它 ;) 我是通过创建集中式应用程序 class 实现的,该应用程序在进入定义的区域时为后台通知实现 BootstrapNotifier。我的 class 还实现了 BeaconConsumer 和 RangeNotifier 接口,它们是进行信标测距所必需的。

package com.smartmachi.smartmachi_android;
import android.app.Application;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.content.Context;
import android.content.Intent;
import android.os.RemoteException;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

import org.altbeacon.beacon.Beacon;
import org.altbeacon.beacon.BeaconConsumer;
import org.altbeacon.beacon.BeaconManager;
import org.altbeacon.beacon.BeaconParser;
import org.altbeacon.beacon.Identifier;
import org.altbeacon.beacon.RangeNotifier;
import org.altbeacon.beacon.Region;
import org.altbeacon.beacon.powersave.BackgroundPowerSaver;
import org.altbeacon.beacon.startup.BootstrapNotifier;
import org.altbeacon.beacon.startup.RegionBootstrap;

import java.util.Collection;

public class BeaconReferenceApplication extends Application implements BootstrapNotifier, BeaconConsumer, RangeNotifier {
    private static final String TAG = "BeaconReferenceApp";
    private RegionBootstrap regionBootstrap;
    private BackgroundPowerSaver backgroundPowerSaver;
    private MainActivity rangingActivity = null;
    BeaconManager beaconManager;


    public void onCreate() {
        super.onCreate();
        beaconManager = BeaconManager.getInstanceForApplication(this);
        beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("s:0-1=feaa,m:2-2=00,p:3-3:-41,i:4-13,i:14-19"));

        Region region = new Region("backgroundRegion", Identifier.parse("0xf7826da6bc5b71e0893e"), null, null);
        regionBootstrap = new RegionBootstrap(this, region);

        backgroundPowerSaver = new BackgroundPowerSaver(this);

        beaconManager.setBackgroundBetweenScanPeriod(30000l);
        beaconManager.setForegroundBetweenScanPeriod(2000l);
        beaconManager.bind(this);
    }

    @Override
    public void didEnterRegion(Region region) {
        Log.d(TAG, "did enter region.");
        try {
            beaconManager.startRangingBeaconsInRegion(region);
        }
        catch (RemoteException e) {
            if (BuildConfig.DEBUG) Log.d(TAG, "Can't start ranging");
        }
    }

    @Override
    public void didExitRegion(Region region) {
        try {
            beaconManager.stopRangingBeaconsInRegion(region);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void didDetermineStateForRegion(int state, Region region) {
        Log.d(TAG,"I have just switched from seeing/not seeing beacons: " + state);
    }

    private void sendNotification(String text) {
        NotificationCompat.Builder builder =
                new NotificationCompat.Builder(this)
                        .setContentTitle("Beacon Reference Application")
                        .setContentText(text)
                        .setSmallIcon(R.drawable.ic_launcher);

        TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
        stackBuilder.addNextIntent(new Intent(this, MainActivity.class));
        PendingIntent resultPendingIntent =
                stackBuilder.getPendingIntent(
                        0,
                        PendingIntent.FLAG_UPDATE_CURRENT
                );
        builder.setContentIntent(resultPendingIntent);
        NotificationManager notificationManager =
                (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(1, builder.build());
    }

    @Override
    public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
        if (beacons.size() > 0) {
            for (Beacon b : beacons) {
                if(b.getId2().toString().equals("0x6d767674636e")) {
                    Log.e(TAG, "Beacon with my Instance ID found!");
                    sendNotification("Beacon with my Instance ID found!");
                }
            }
        }
    }

    @Override
    public void onBeaconServiceConnect() {
        beaconManager.setRangeNotifier(this);
    }
}