0

I'm using RadiusNetworks Android iBeacon Library and I'd like to have my iBeacon ranging done in a background process, then it will broadcast beacon info to my application. I try to bind the iBeaconManager to the service running on the separate process but it doesn't seem to work as the service never makes it to the onIBeaconServiceConnect() callback.

TestService on separate process:

public class TestService extends Service implements IBeaconConsumer{

public static final String START_SERVICE = "com.example.intent.action.START";
public static final String SEND_PROXID = "com.example.intent.action.PROX";

private String proxID;
private static final String TAG = TestService.class.getSimpleName();
private IBeaconManager iBeaconManager;  
private Region currentRegion;
private boolean checkedRecently = false;

  private Timer timer;
  private TimerTask updateTask = new TimerTask() {
    @Override
    public void run() {
        checkedRecently = false;
         Log.i(TAG, "Resetting checked recently");
    }
  };

  @Override
  public int onStartCommand(Intent intent, int flags, int startId){
     int ret; 
     ret = super.onStartCommand(intent, flags, startId);
     Log.i(TAG, "Got to onStartCommand");
     if(intent.getAction().equals(START_SERVICE)){
         Log.i(TAG, "Service received start intent");
     }
     else if(intent.getAction().equals(SEND_PROXID)){
         Log.i(TAG, "Service received PROXID intent");
         proxID = intent.getStringExtra("prox");
         System.out.println(proxID);
         iBeaconManager = IBeaconManager.getInstanceForApplication(this);
        iBeaconManager.bind(this);
     }
     return ret;
       }

  @Override
  public IBinder onBind(Intent intent) {
      Log.i(TAG, "onBIND called");
    return null;
  }

  @Override
  public void onCreate() {
    super.onCreate();
    Log.i(TAG, "Service creating");

    timer = new Timer("TestTimer");
    timer.schedule(updateTask, 1000L, 20 * 1000L);

  }

  @Override
  public void onDestroy() {
    super.onDestroy();
    Log.i(TAG, "Service destroying");

    timer.cancel();
    timer = null;
    iBeaconManager.unBind(this);
    iBeaconManager = null;
  }

  @Override
    public void onIBeaconServiceConnect() {
      Log.i(TAG, "iBeacon service connect");
        iBeaconManager.setRangeNotifier(new RangeNotifier() {
        @Override 
        public void didRangeBeaconsInRegion(Collection<IBeacon> iBeacons, Region region) {
            if (iBeacons.size() > 0 && !checkedRecently) {
                checkedRecently = true;
                Log.i(TAG, "Service found beacon, sending data");
            Intent i = new Intent();
            i.setAction(ServiceReceiver.DID_ENTER);
            i.putExtra("maj", Integer.toString(iBeacons.iterator().next().getMajor()));
            i.putExtra("min", Integer.toString(iBeacons.iterator().next().getMinor()));
            sendBroadcast(i);
            }
        }
        });

        currentRegion = new Region("myRangingUniqueId", proxID, null, null);
        try {
            iBeaconManager.startMonitoringBeaconsInRegion(currentRegion);
        } catch (RemoteException e) {   }

    }

}

AndroidManifest.xml

<service
        android:name=".TestService"
        android:exported="false"
        android:process=":remote" >
        <intent-filter>
            <action android:name="com.example.intent.action.PROX" />
            <action android:name="com.example.intent.action.START" />
        </intent-filter>
    </service>
<receiver android:name="ServiceReceiver" >
        <intent-filter>
            <action android:name="com.example.intent.action.DIDENTER" >
            </action>
        </intent-filter>
    </receiver>

I fetch the relevant proxID from my server, and send it to the service at which time I figured I ought to be able to bind to it and start ranging for regions that match the prox. But I can't seem to get it to bind to the service successfully. Thanks for help, and let me know if I need to update posted code.

lundhjem
  • 608
  • 6
  • 12

1 Answers1

0

I wonder if your AndroidManifest.xml is getting the proper entries required for the AndroidIBeaconLibrary. The Library relies on a feature called manifest merging to get the library's service entries into your manifest. This must be enabled in your project in Eclipse or Android Studio. Check your build directory for a generated manifest, and make sure it has an entry for the AndroidIBeaconService.

That said, creating your own background service might be a bit of overkill. Understand that the Android iBeacon Library already has a background AndroidIBeaconService class (as mentioned above), so you don't really need to make your own service. All you need to do is to bind the service to something with a longer lifecycle than an Activity (like a custom Android Application class) so the service does not stop when the Activity unbinds from it.

There is a Pro version of the Android iBeacon Library which sets all of this up for you, slows down scanning when your app is in the background to save battery, and automatically launches your app in the background to search for iBeacons, even if the user doesn't manually launch it. Sample code that shows you how to do this with the Pro version is under the "Background Launching Example Code" section here.

Full disclosure: I am Chief Engineer for Radius Networks and the primary author of the Android iBeacon Library.

davidgyoung
  • 63,876
  • 14
  • 121
  • 204
  • Thanks for the prompt response David! I have manifestmerging as true in my project properties, not sure where the generated manifest is; the ranging worked great when I was bound to the activity in the foreground but of course stopped when the activity stopped or paused. I tried having my app singleton that I use for globals extend Application and bind to that but I always get the same errors. Perhaps you can make sense of them, I'll update post. – lundhjem Jun 11 '14 at 21:01
  • I'm afraid I'm confused. You mention you "tried having my app singleton that I use for globals extend Application and bind to that but I always get the same errors" and show a stack trace that appears to be for this attempt. But you don't show your code from that Application class, and the question still shows the use of a Service. I suggest you keep **this** question related to using a Service (you probably should not accept my answer if it didn't solve your problem) and open a **new** question for making your app singleton extend Application. I'll try to help there. – davidgyoung Jun 12 '14 at 02:57
  • For your service-based solution, Eclipse places your merged manifest in bin/AndroidManifest.xml. Check to make sure it has a service entry for com.radiusnetworks.ibeacon.service.IBeaconService. – davidgyoung Jun 12 '14 at 03:06
  • I accepted because your first answer helped solve the problem. The iBeacon service wasn't registered in my Manifest, despite having merging as true; I must not have configured it correctly. And regarding the custom Application, I likely couldn't bind to that for the same reason. Thanks again! – lundhjem Jun 12 '14 at 16:09