AltBeacon不使用前台服务在后台扫描信标。 RegionBootstrap / BootstrapNotifier实现也无法正常工作

时间:2019-04-30 16:20:28

标签: android ibeacon android-bluetooth altbeacon ibeacon-android

我有一项服务,当用户根据位置进入任何建筑物时会寻找信标,它将返回有效信标区域。然后触发BeaconRanger服务,并应开始扫描该区域中的信标。这对于应用程序的背景和前景状态均适用。它还根据应用程序的前台状态和后台状态更新时间间隔。

在后台更新扫描周期可以在updateScanPeriods()中找到代码

    private static Long BACKGROUND_SCAN_PERIOD_MEDIUM = 10 * 1000l; // 10 sec
    private static Long FOREGROUND_SCAN_PERIOD_MEDIUM = 1100l; // 1.1 sec
    private static Long BACKGROUND_BETWEEN_SCAN_PERIOD_MEDIUM = 10 * 60 * 1000l; // 10 min
    private static Long FOREGROUND_BETWEEN_SCAN_PERIOD_MEDIUM = 5 * 1000l; // 5 sec

在前台更新扫描周期可以在updateScanPeriods()中找到代码

    private static Long BACKGROUND_SCAN_PERIOD_LOW = 1100l; // 1.1 sec
    private static Long FOREGROUND_SCAN_PERIOD_LOW = 1100l; // 1.1 sec
    private static Long BACKGROUND_BETWEEN_SCAN_PERIOD_LOW = 4 * 1000l; // 5 sec
    private static Long FOREGROUND_BETWEEN_SCAN_PERIOD_LOW = 3 * 1000l; // 3 sec

设置后台模式可以在public void onEventMainThread(BeaconRangerBackgroundSetting beaconRangerBackgroundSetting)中找到代码

            if (beaconRangerBackgroundSetting.status) {
                if (beaconManager != null && beaconManager.isBound(this))
                    beaconManager.setBackgroundMode(true);
            } else {
                if (beaconManager != null && beaconManager.isBound(this))
                    beaconManager.setBackgroundMode(false);
            }

我能够在后台状态下获取有效区域,并将其传递给BeaconRanger类,但是除非我再次打开该应用程序,否则Altbeacon管理器中的远程信标列表始终为空。我实现了RegionBootstrap / BootstrapNotifier来进行后台启动,但是结果是相同的。

我想知道我的实现是否有问题?

public class BeaconRanger extends Service implements BeaconConsumer, BootstrapNotifier {

    private static final String TAG = "ArubaBeacons";
    private static final int MAX_INTERVAL = 60 * 1000; // 1 min
    private static final int MIN_INTERVAL = 25 * 1000; // 25 sec
    private static final int MAX_RETRY_TIME = 2 * 60 * 1000;
    private static final int PERMISSION_REQUEST_STORAGE = 1;
    private static Long BACKGROUND_SCAN_PERIOD_MEDIUM = 10 * 1000l; // 10 sec
    private static Long FOREGROUND_SCAN_PERIOD_MEDIUM = 1100l; // 1.1 sec
    private static Long BACKGROUND_BETWEEN_SCAN_PERIOD_MEDIUM = 10 * 60 * 1000l; // 10 min
    private static Long FOREGROUND_BETWEEN_SCAN_PERIOD_MEDIUM = 5 * 1000l; // 5 sec
    private static Long BACKGROUND_SCAN_PERIOD_LOW = 1100l; // 1.1 sec
    private static Long FOREGROUND_SCAN_PERIOD_LOW = 1100l; // 1.1 sec
    private static Long BACKGROUND_BETWEEN_SCAN_PERIOD_LOW = 4 * 1000l; // 5 sec
    private static Long FOREGROUND_BETWEEN_SCAN_PERIOD_LOW = 3 * 1000l; // 3 sec
    private ArrayList<Model.beacon> beaconList = new ArrayList<Model.beacon>();
    private ArrayList<Region> regions = new ArrayList<>();
    private ArrayList<Region> lastRangedRegions = new ArrayList<>();
    private ArrayList<Region> rangedRegions = new ArrayList<>();
    private BeaconManager beaconManager;
    private  BeaconApplication mApp;
    private long mLastRangeTime = 0;
    private long mLastPostedTime = 0;
    private long mLastRetryTime = 0;
    private int retryCount = 0;
    private EventBus mBus = EventBus.getDefault();
    private ArrayList<String> regionIds = new ArrayList<>();
    private ArrayList<Model.beacon> mLastRangedBeacons = new ArrayList<>();
    private ArrayList<Model.beacon> mLastUpdatedBeacons = new ArrayList<>();
    private RegionBootstrap regionBootstrap;
    private int mLastBeaconSetting = -1;

    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_STICKY;
    }

    @Override
    public void onCreate() {
        super.onCreate();

        try {
            mApp =  BeaconApplication.mInstance;
            mApp.mBeaconRanger = this;
            mBus.registerSticky(this);
            new BackgroundPowerSaver(this);


            beaconManager = BeaconManager.getInstanceForApplication(this);

            beaconManager.getBeaconParsers().add(new BeaconParser()
                    .setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25"));

            // set the duration of the scan
            updateScanPeriods();

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                setForeground();
            }
            beaconManager.bind(this);


            BeaconManager.setDebug(false);
        } catch (Exception e) {
            Timber.e("Exception in onCreate: " + e.getMessage());
        }

    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    private void setForeground() {
        try {
            String NOTIFICATION_CHANNEL_ID = "location_service_notifications";
            String channelName = "Location Service Notifications";
            NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_LOW);
            notificationChannel.setLightColor(Color.BLUE);
            notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
            NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            manager.createNotificationChannel(notificationChannel);


            Notification.Builder builder = new Notification.Builder(this, NOTIFICATION_CHANNEL_ID);
            builder.setSmallIcon(R.drawable.ic_location);
            builder.setContentTitle(getString(R.string.arcangel_location_beacon_notification_title));
            builder.setContentText(getString(R.string.arcangel_location_beacon_notification_text));
            Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
                    .putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName())
                    .putExtra(Settings.EXTRA_CHANNEL_ID, notificationChannel.getId());
            PendingIntent pendingIntent = PendingIntent.getActivity(
                    this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT
            );
            builder.setContentIntent(pendingIntent);
            int v = beaconManager.getForegroundServiceNotificationId();
            startForeground(2, builder.build());
            if (beaconManager.getForegroundServiceNotificationId() < 0) {
                beaconManager.enableForegroundServiceScanning(builder.build(), 2);
                beaconManager.setEnableScheduledScanJobs(false);
                updateScanPeriods();
            }

            Timber.d("started Foreground");
        } catch (Exception e) {
            Timber.e("Exception in setForeground: " + e.getMessage());
        }
    }

    private void updateScanPeriods() {
        int mCurrentBeaconSetting;
        Long backgroundScanPeriod;
        Long foregroundScanPeriod;
        Long backgroundBetweenScanPeriod;
        Long foregroundBetweenScanPeriod;


        if ((mApp.isAppVisible()) { // app in the foreground
            mCurrentBeaconSetting = 0;
            backgroundScanPeriod = BACKGROUND_SCAN_PERIOD_LOW;
            foregroundScanPeriod = FOREGROUND_SCAN_PERIOD_LOW;
            backgroundBetweenScanPeriod = BACKGROUND_BETWEEN_SCAN_PERIOD_LOW;
            foregroundBetweenScanPeriod = FOREGROUND_BETWEEN_SCAN_PERIOD_LOW;

        } else { // app in the background
            mCurrentBeaconSetting = 1;
            backgroundScanPeriod = BACKGROUND_SCAN_PERIOD_MEDIUM;
            foregroundScanPeriod = FOREGROUND_SCAN_PERIOD_MEDIUM;
            backgroundBetweenScanPeriod = BACKGROUND_BETWEEN_SCAN_PERIOD_MEDIUM;
            foregroundBetweenScanPeriod = FOREGROUND_BETWEEN_SCAN_PERIOD_MEDIUM;
        }

        if (mLastBeaconSetting != mCurrentBeaconSetting && beaconManager != null) {
            beaconManager.setBackgroundScanPeriod(backgroundScanPeriod);
            beaconManager.setForegroundScanPeriod(foregroundScanPeriod);
            beaconManager.setBackgroundBetweenScanPeriod(backgroundBetweenScanPeriod); // callback time between scans background
            beaconManager.setForegroundBetweenScanPeriod(foregroundBetweenScanPeriod); // callback time between scans foreground
            mLastBeaconSetting = mCurrentBeaconSetting;
            try {
                beaconManager.updateScanPeriods();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private void checkRangedRegionsValidity() {
        if (regionIds.size() <= 0) {
            beaconList.clear();
            for (Region duplicateRegion : beaconManager.getRangedRegions()) {
                try {
                    beaconManager.stopRangingBeaconsInRegion(duplicateRegion);
                    beaconManager.stopMonitoringBeaconsInRegion(duplicateRegion);
                    regionBootstrap.removeRegion(duplicateRegion);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            mLastRangedBeacons.clear();
        }
    }


   // called by a different service, will give a valid region based on certain parameters like inside an building or location. If no condition is satisfies gives an empty array
    public void setBeaconRegionIds(ArrayList<String> regionIds) {
        this.regionIds = regionIds;
        checkRangedRegionsValidity();
        updateScanPeriods();

        try {
            regions.clear();
            for (String regionId : regionIds) {
                regions.add(new Region(regionId.toLowerCase(), Identifier.parse(regionId.toLowerCase()), null, null));
            }
            if (lastRangedRegions.size() == 0 || !lastRangedRegions.equals(regions)) {
                lastRangedRegions = new ArrayList<>(regions);

                if (beaconManager != null && beaconManager.isBound(this))
                    onBeaconServiceConnect();

            }
        } catch (Exception e) {
            Timber.e(TAG + e);
        }
    }


    private void startRanging() {

        try {
            if (canRun()) {
                rangedRegions = (ArrayList<Region>) beaconManager.getRangedRegions();
                if (rangedRegions.removeAll(regions)) {
                    for (Region duplicateRegion : rangedRegions) {
                        beaconManager.stopRangingBeaconsInRegion(duplicateRegion);
                        beaconManager.stopMonitoringBeaconsInRegion(duplicateRegion);
                    }
                }

                rangedRegions = (ArrayList<Region>) beaconManager.getRangedRegions();
                if (regions.size() > 0 && !rangedRegions.equals(regions)) {
                    regions.removeAll(rangedRegions);
                    regionBootstrap = new RegionBootstrap(this, regions);

                    for (Region newRegion : regions) {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//                            regionBootstrap = new RegionBootstrap(this, newRegion);
                        }

                        beaconManager.startRangingBeaconsInRegion(newRegion);
                        beaconManager.startMonitoringBeaconsInRegion(newRegion);
                    }
                }
            }

        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    private void addRangerNotifier() {
        if (beaconManager == null)
            return;
        beaconManager.addRangeNotifier(new RangeNotifier() {
            @Override
            public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {


                for (Beacon oneBeacon : beacons) {

                    for (int i = 0; i < beaconList.size(); i++) {
                        String arubaDuplicate = beaconList.get(i).id.trim();
                        String aruba = (oneBeacon.getId1().toString().trim() + ":" + oneBeacon.getId2().toInt() + ":" + oneBeacon.getId3().toInt()).trim();
                        if (aruba.equals(arubaDuplicate)) {
                            beaconList.remove(i);
                        }
                    }
                    Timber.d(TAG + "distance: " + oneBeacon.getDistance() + " id:" + oneBeacon.getId1() + "/" + oneBeacon.getId2() + "/" + oneBeacon.getId3());
                    beaconList.add(new Model.beacon(oneBeacon.getId1().toString().trim(), oneBeacon.getId2().toInt(), oneBeacon.getId3().toInt(), oneBeacon.getDistance()));
                    retryCount = 0;
                }
                boolean post = beaconsDifferInOrderByNth(mLastRangedBeacons, beaconList, 4);
                mLastRangedBeacons = new ArrayList<>(beaconList);
                if (mLastPostedTime < (System.currentTimeMillis() - 4500) && mApp.mState != null && mApp.mState.getLastKnownBeacons() == 0 && beaconList.size() > 0 && regionIds.size() > 0) {
                    mLastPostedTime = System.currentTimeMillis();
                    mBus.post(new BeaconRanger.MessageBeaconsRanged());
                }
                checkRangedRegionsValidity();

            }
        });

    }


    public void onEventMainThread(BeaconRangerBackgroundSetting beaconRangerBackgroundSetting) {
        try {

            if (beaconRangerBackgroundSetting.status) {
                if (beaconManager != null && beaconManager.isBound(this))
                    beaconManager.setBackgroundMode(true);
            } else {
                if (beaconManager != null && beaconManager.isBound(this))
                    beaconManager.setBackgroundMode(false);
            }
            updateScanPeriods();
            mBus.removeStickyEvent(beaconRangerBackgroundSetting);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }



    @Override
    public void onBeaconServiceConnect() {
        if (beaconManager != null && (beaconManager.getRangingNotifiers().size() <= 0))
            addRangerNotifier();
        startRanging();

    }


    @Override
    public void didEnterRegion(Region region) {
        Timber.d("didEnterRegion: " + region);
        try {
            rangedRegions = (ArrayList<Region>) beaconManager.getRangedRegions();
            if (!rangedRegions.contains(region) || rangedRegions.indexOf(region) < 0)
                beaconManager.startRangingBeaconsInRegion(region);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void didExitRegion(Region region) {
        Timber.d("didExitRegion: " + region);
    }

    @Override
    public void didDetermineStateForRegion(int i, Region region) {
        Timber.d("didDetermineStateForRegion: " + region);

        if (i == 1) {
            try {
                rangedRegions = (ArrayList<Region>) beaconManager.getRangedRegions();
                if ((rangedRegions.contains(region) || rangedRegions.indexOf(region) >= 0) && mLastRangedBeacons.size() == 0) {
                    beaconManager.stopRangingBeaconsInRegion(region);
                    beaconManager.startRangingBeaconsInRegion(region);
                } else if (!rangedRegions.contains(region) || rangedRegions.indexOf(region) < 0) {
                    beaconManager.startRangingBeaconsInRegion(region);
                }
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }



}

0 个答案:

没有答案