进入区域时,在前景上开始信标测距.

  • 本文关键字:开始 区域 android altbeacon
  • 更新时间 :
  • 英文 :


Goal

当应用程序在后台时,EddyStone EID 信标检测. 一旦用户进入信标区域, 应用程序应该开始测距并对我的服务器进行 http 调用,以便我被告知检测.即使是短期访问。

由于 Android 上的后台扫描限制,我正在考虑使用区域引导程序并在进入信标区域后立即启动前台服务。这比直接使用前台服务更胜一筹,因此我不会一直看到通知。

问题

我的应用程序基于 AltBeacon 参考应用程序。我尝试在用户进入区域后立即启动前台服务。前台服务已启动,但范围通知程序不显示任何信标检测。我尝试的替代方法是启动前台服务并在 didDetermineState 方法回调中限定范围,但这不起作用,因为我必须启用和禁用区域引导才能这样做,这将再次触发 didDetermineState 回调方法。

如何在后台检测信标 (没有延迟( 并在不使用前台服务的情况下开始测距?

代码 + 日志

public class AppController extends MultiDexApplication implements BootstrapNotifier,
RangeNotifier, BeaconConsumer {
private static final String TAG = "BEACON:";
private static AppComponent appComponent;
private static AppController instance;
private RegionBootstrap regionBootstrap;
private BackgroundPowerSaver backgroundPowerSaver;
private boolean isScanningOnForeground = false;
private BeaconManager beaconManager;
@Override
public void onCreate() {
super.onCreate();
beaconManager = BeaconManager.getInstanceForApplication(this);
beaconManager.setDebug(true);
beaconManager.getBeaconParsers().clear();
beaconManager.getBeaconParsers()
.add(new BeaconParser().setBeaconLayout(BeaconParser.EDDYSTONE_UID_LAYOUT));
Region region = new Region("backgroundRegion",
null, null, null);
regionBootstrap = new RegionBootstrap(this, region);
backgroundPowerSaver = new BackgroundPowerSaver(this);
instance = this;
this.getAppComponent().inject(this);
}
public AppComponent getAppComponent() {
if (appComponent == null) {
appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build();
}
return appComponent;
}
public static AppController getInstance() {
return instance;
}
@Override
public void didEnterRegion(Region region) {
Log.d(TAG, "(didEnterRegion) Beacon detected in region!");
startMonitoringOnForeground();
}
public void disableMonitoring() {
if (regionBootstrap != null) {
regionBootstrap.disable();
regionBootstrap = null;
}
}
public void enableMonitoring() {
Region region = new Region("backgroundRegion",
null, null, null);
regionBootstrap = new RegionBootstrap(this, region);
}
private void enableRanging() {
Log.d(TAG, "Enable ranging");
beaconManager.removeAllRangeNotifiers();
beaconManager.addRangeNotifier(this);
try {
beaconManager.startRangingBeaconsInRegion(new Region("rangingRegion",
null, null, null));
Log.d(TAG, "Ranging started..");
} catch (RemoteException e) {
Log.d(TAG, ">>>>>>>>>>> START RANGING EXCEPTION!");
e.printStackTrace();
}
}
private void disableRanging() {
Log.d(TAG, "Disable ranging.");
try {
beaconManager.stopRangingBeaconsInRegion(new Region("rangingRegion",
null, null, null));
} catch (RemoteException e) {
Log.d(TAG, ">>>>>>>>>>> START RANGING EXCEPTION!");
e.printStackTrace();
}
beaconManager.removeAllRangeNotifiers();
}
private void startMonitoringOnForeground() {
if (isScanningOnForeground) {
Log.d(TAG, "Ignore method call, already scanning in foreground");
return;
}
isScanningOnForeground = true;
disableMonitoring();
Notification.Builder builder = new Notification.Builder(this);
builder.setSmallIcon(R.drawable.app_icon);
builder.setContentTitle("Scanning for Beacons");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel("My Notification Channel ID",
"My Notification Name", NotificationManager.IMPORTANCE_DEFAULT);
channel.setDescription("My Notification Channel Description");
NotificationManager notificationManager = (NotificationManager) getSystemService(
Context.NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(channel);
builder.setChannelId(channel.getId());
}
beaconManager.enableForegroundServiceScanning(builder.build(), 456);
// For the above foreground scanning service to be useful, you need to disable
// JobScheduler-based scans (used on Android 8+) and set a fast background scan
// cycle that would otherwise be disallowed by the operating system.
//
beaconManager.setEnableScheduledScanJobs(false);
beaconManager.setBackgroundBetweenScanPeriod(30000);
beaconManager.setBackgroundScanPeriod(1100);
enableRanging();
enableMonitoring();
}
private void stopMonitoringOnForeground() {
if (!isScanningOnForeground) {
Log.d(TAG, "Not stopping since foreground scanning isn't active.");
return;
}
isScanningOnForeground = false;
disableMonitoring();
beaconManager.disableForegroundServiceScanning();
enableMonitoring();
disableRanging();
}
@Override
public void didExitRegion(Region region) {
Log.d(TAG, "(didExitRegion) No beacons anymore");
stopMonitoringOnForeground();
}
@Override
public void didDetermineStateForRegion(int state, Region region) {
Log.d(TAG,
"Determine state for region " + (state == 1 ? "INSIDE" : "OUTSIDE (" + state + ")"));
}
@Override
public void didRangeBeaconsInRegion(Collection<Beacon> collection, Region region) {
Log.d(TAG, "Did range beacons in region");
for (Beacon beacon : collection) {
Log.d(TAG, "Beacon:  " + beacon.getId1().toString());
}
}
@Override
public void onBeaconServiceConnect() {
Log.d(TAG, "OnBeaconServiceConnect");
}
} 
D/BEACON:: Determine state for region OUTSIDE (0)
D/BEACON:: Determine state for region INSIDE
D/BEACON:: (didEnterRegion) Beacon detected in region!
D/BEACON:: Enable ranging
D/BEACON:: Ranging started..
D/BEACON:: Determine state for region OUTSIDE (0)
D/BEACON:: Determine state for region INSIDE
D/BEACON:: (didEnterRegion) Beacon detected in region!
D/BEACON:: Ignore method call, already scanning in foreground
D/BEACON:: (didEnterRegion) Beacon detected in region!
D/BEACON:: Ignore method call, already scanning in foreground

你展示的技术可能接近工作。 主要问题是,在前台服务"绑定"之前,您无法开始范围。

前台服务需要很短的时间才能启动,只有在启动后才能开始范围。 可以尝试的几个选项:

  1. 您可以在禁用 RegionBootstrap 之前开始测距。 然后保持代码的其余部分不变,当服务启动时,它应该仍处于打开状态。 (不肯定这将起作用。

  2. 如果上述方法不起作用,请尝试仅在获得带有 isScanningOnForeground true 的 didDerermineState 回调后才开始范围。 这将确保服务已绑定。

  3. 解决此问题的最佳和最干净的方法是停止使用 RegionBootstrap,因为它在绑定服务时不提供直接回调。 BeaconManager.bind(this( 调用确实提供了一个 onBeaconServiceConnect 回调,可用于启动监控和测距。 但是,此选项需要更改最多的代码。

您可能还希望设置信标管理器.setDebug(true( 并在范围开始后查找消息,这些消息可以为您提供有关它为什么不起作用的线索.