Reputation: 7129
I really need to understand how to start a service in order to scan for beacons even if the app goes on background, I took a look at the admin app I found on Github but I can't really understand how it works.. Does anyone has a simple piece of code to show me how it works?
A simple solution (found on the web) that I tried was the following:
public class BeaconRangingService extends Service {
private static final String TAG = BeaconRangingService.class.getSimpleName();
private BeaconManager beaconManager;
@Override
public void onCreate() {
super.onCreate();
beaconManager = BeaconManager.newInstance(getApplicationContext());
beaconManager.setMonitorPeriod(MonitorPeriod.MINIMAL);
beaconManager.setForceScanConfiguration(ForceScanConfiguration.DEFAULT);
beaconManager.registerMonitoringListener(new BeaconManager.MonitoringListener() {
@Override
public void onMonitorStart() {
Log.v(TAG, "start monitoring beacons");
}
@Override
public void onMonitorStop() {
Log.wtf(TAG, "stop monitoring beacons");
}
@Override
public void onBeaconsUpdated(Region region, List<Beacon> list) {
}
@Override
public void onBeaconAppeared(Region region, Beacon beacon) {
Toast.makeText(getApplicationContext(), "Beacon appeared\n BEACON ID: " + beacon.getBeaconUniqueId(), Toast.LENGTH_SHORT).show();
}
@Override
public void onRegionEntered(Region region) {
}
@Override
public void onRegionAbandoned(Region region) {
}
});
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v(TAG, "service started");
if (!beaconManager.isBluetoothEnabled()) {
Log.w(TAG, "bluetooth disabled, stop service");
stopSelf();
} else {
connect();
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
Log.v(TAG, "service destroyed");
beaconManager.stopMonitoring();
beaconManager.disconnect();
beaconManager = null;
super.onDestroy();
}
private void connectBeaconManager() {
try {
beaconManager.connect(new OnServiceBoundListener() {
@Override
public void onServiceBound() {
try {
HashSet<Region> regions = new HashSet<>();
regions.add(Region.EVERYWHERE);
beaconManager.startMonitoring(regions);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
}
}
But I can't get it working
Upvotes: 1
Views: 2441
Reputation: 2452
I assume you've been testing the kontakt-beacon-admin-sample-app - foreground/background showcase. The mechanism is pretty simple but requires some understanding of how broadcasts can be intercepted in Android.
Let's analyze the BackgroundScanService
At first, the BeaconManager is responsible for notifying the BLE remote devices presence via callback methods.
Secondly, the BeaconManager is deliberately configured and controlled in background service because the Service acts as broadcast generator. The primary advantage of the service is the fact it can work even if the user abandons the app. So practically the Service blindly sends the broadcast in hope that there will be someone who will intercept it.
Thirdly, request sending is executed in the following line:
sendOrderedBroadcast(intent, null);
sendOrderedBroadcast() is documented here.
Fourthly, now it's time to intercept the broadcasts. We configure then 2 Broadcast Receivers to do that: the BackgroundScanReceiver and the ForegroundScanReceiver.
The BackgroundScanReceiver displays notifications when the scan broadcast is intercepted.
The ForegroundScanReceiver simply displays toasts but this can be changed according to one's needs.
At this point there is a trick in which we specify in which order the broadcast should be intercepted. We configure the ForegroundScanReceiver to intercept any broadcast in the first order. We do it by setting a priority in Intent filter bound with the Receiver (see SCAN_INTENT_FILTER) that we register dynamically in onResume() (the app becomes visible) and onPause() (the app becomes partially visible). We also configure statically the BackgroundBroadcastReceiver and give it the priority with value 1.
Switching foreground/background
We now have the priorities established and we know that the ForegroundScanReceiver intercepts broadcasts first because it has higher priority.
When the app is in foreground then both Scan receivers (the foreground and the background) are registered but only the foreground one intercepts the broadcasts and prevents each broadcast from being intercepted by the background one. It is done by the following method - abortBroadcast() (note that the Foreground and the Background receiver extend common abstraction):
abortBroadcast();
When the app is hidden in background, however, then the ForegroundScanReceiver is unregistered (see onPause() method) and thus the primal Receiver is then the BackgroundScanReceiver.
You can find the documentation about abortBroadcast() here.
Why is this feature not included in the kontakt.io Proximity SDK?
The approach presented in the kontakt-beacon-admin-sample-app can be solved in different ways and the kontakt.io mobile SDK's goal is to not to provide you with every feature already implemented as this raises some limitations of conforming the SDK to your app. The goal is to give you the basics and provide the flexibility in terms of SDK components usage. The kontakt-beacon-admin-sample-app is the proof of concept that our SDK collaborating with some different Android components can provide you with the functionality that you expect from it and, what is most important, give you the flexibility of what you want to do upon it.
I suggest observing kontakt-beacon-admin-sample-app as this is the first project where different approaches integrating kontakt.io SDK with other open-source libraries and core Android SDK are introduced first.
I also strongly encourage you to raise an issue once you want the SDK to behave in accordance with your expectations.
I hope I provided some clarification to your question.
Upvotes: 6
Reputation: 64941
If you are open to trying the free and open-source Android Beacon Library, there is a ready-to-run reference app you can try that launches the app and sends notifications when beacons are discovered in the background. It's available here:
https://github.com/AltBeacon/android-beacon-library-reference
You can make this work with Kontakt.io beacons by adding a Beacon Parser as described here.
This reference app works by automatically starting a BeaconService
to scan for beacons at phone power-on. This service works in the backround with a RegionBootstrap
class that is used in a custom AndroidApplication
class here (which you can customize). This class' didEnterRegion
method gets called when a beacon is first discovered, allowing you to launch an Activity
(which the example does at first detection) or send a notification (which the example does at subsequent notifications.)
There's more documentation about how this all works with this library here and here.
Upvotes: 4