Android iBeacon库使用外部活动

时间:2014-01-21 09:59:28

标签: android android-service ibeacon ibeacon-android android-service-binding

我正在尝试在活动上下文之外使用iBeacon库,以编写其有效的实现,但我遗漏了一些东西,因为我没有获得所需的功能。

很可能看起来服务没有绑定到我新创建的类......我不确定我在这里缺少什么......

这是我的自定义类:

public class BeaconUtils implements IBeaconConsumer, RangeNotifier, IBeaconDataNotifier {

    private Context context;
    protected static final String TAG = "BeaconUtils";

    public BeaconUtils(Context context) {
        this.context = context;
        verifyBluetooth((Activity) context);
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    public static void verifyBluetooth(final Activity activity) {

        try {
            if (!IBeaconManager.getInstanceForApplication(activity).checkAvailability()) {
                final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
                builder.setTitle("Bluetooth not enabled");
                builder.setMessage("Please enable bluetooth in settings and restart this application.");
                builder.setPositiveButton(android.R.string.ok, null);
                builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
                    @Override
                    public void onDismiss(DialogInterface dialog) {
                        activity.finish();
                        //System.exit(0);
                    }
                });
                builder.show();
            }
        } catch (RuntimeException e) {
            final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
            builder.setTitle("Bluetooth LE not available");
            builder.setMessage("Sorry, this device does not support Bluetooth LE.");
            builder.setPositiveButton(android.R.string.ok, null);
            builder.setOnDismissListener(new DialogInterface.OnDismissListener() {

                @Override
                public void onDismiss(DialogInterface dialog) {
                    activity.finish();
                    //System.exit(0);
                }

            });
            builder.show();

        }
    }

    @Override
    public void onIBeaconServiceConnect() {
        Region region = new Region("MainActivityRanging", null, null, null);
        try {
            ZonizApplication.iBeaconManager.startMonitoringBeaconsInRegion(region);
            ZonizApplication.iBeaconManager.setRangeNotifier(this);
            ZonizApplication.iBeaconManager.startRangingBeaconsInRegion(region);
        } catch (RemoteException e) {
            e.printStackTrace();
        }


        ZonizApplication.iBeaconManager.setMonitorNotifier(new MonitorNotifier() {
            @Override
            public void didEnterRegion(Region region) {
                //createNotification();
                //Log.i(TAG, "I am in the range of an IBEACON: "+region.getProximityUuid());
                //SyncServiceHelper.getInst().trySyncOffers(region.getProximityUuid());
            }

            @Override
            public void didExitRegion(Region region) {
                NotificationManager mNotificationManager;
                mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
                mNotificationManager.cancel(0);
            }

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

    @Override
    public Context getApplicationContext() {
        return this.context;
    }

    @Override
    public void unbindService(ServiceConnection serviceConnection) {
        ZonizApplication.iBeaconManager.unBind(this);
    }

    @Override
    public boolean bindService(Intent intent, ServiceConnection serviceConnection, int i) {
        ZonizApplication.iBeaconManager.bind(this);
        return true;
    }

    @Override
    public void iBeaconDataUpdate(IBeacon iBeacon, IBeaconData iBeaconData, DataProviderException e) {
        if (e != null) {
            Log.d(TAG, "data fetch error:" + e);
        }
        if (iBeaconData != null) {
            String displayString = iBeacon.getProximityUuid() + " " + iBeacon.getMajor() + " " + iBeacon.getMinor() + "\n" + "Welcome message:" + iBeaconData.get("welcomeMessage");
            Log.d(TAG, displayString);
        }
    }

    @Override
    public void didRangeBeaconsInRegion(Collection<IBeacon> iBeacons, Region region) {
        for (IBeacon iBeacon : iBeacons) {
            iBeacon.requestData(this);
            String displayString = iBeacon.getProximityUuid() + " " + iBeacon.getMajor() + " " + iBeacon.getMinor() + "\n";

            Log.d(TAG, displayString);
        }
    }

    public void createNotification() {
        // Prepare intent which is triggered if the
        // notification is selected
        Intent intent = new Intent(context, MainActivity.class);
        PendingIntent pIntent = PendingIntent.getActivity(context, 0, intent, 0);

        // Build notification
        // Actions are just fake

        //if (currentUIID != null && !currentUIID.isEmpty()) {
        Notification noti = new Notification.Builder(context)
                .setContentTitle("New beacon in range")
                .setContentText("You are currently in the range of a new beacon.").setSmallIcon(R.drawable.ic_launcher)
                .setContentIntent(pIntent).build();
        NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        // hide the notification after its selected
        noti.flags |= Notification.FLAG_AUTO_CANCEL;
        noti.defaults |= Notification.DEFAULT_SOUND;
        noti.defaults |= Notification.DEFAULT_VIBRATE;

        notificationManager.notify(0, noti);
        //}
    }

}

我在Application类中实例化了信标管理器:

iBeaconManager = IBeaconManager.getInstanceForApplication(this);

我正在使用onCreate()onDestroy()方法在我的活动中绑定此经理。

我缺少什么?

我在活动中实例化我的自定义类:

private BeaconUtils beaconUtilities = new BeaconUtils(MainActivity.this);

绑定部分:

beaconUtilities = new BeaconUtils(MainActivity.this);
ZonizApplication.iBeaconManager.bind(beaconUtilities);

2 个答案:

答案 0 :(得分:3)

我能够通过一些修改获得上面的代码:

  1. 我注释了verifyBluetooth((Activity) context);行,因为它使MainActivityNullPointerException一起崩溃。如果您发现活动正常启动,则可能不需要执行此操作。如果您没有看到它启动,那么BeaconUtils将由Android与您的MainActivity一起处理,并且在看到iBeacons时无法获得任何回调。

  2. 我不得不更改createNotification方法才能让它工作 - 原始代码没有为我显示通知,虽然我不清楚原因。我开始工作的代码是:

    private void createNotification() {
         NotificationCompat.Builder builder =
                 new NotificationCompat.Builder(context)
                         .setContentTitle("New beacon in range")
                         .setContentText("You are currently in the range of a new beacon.")
                         .setSmallIcon(R.drawable.ic_launcher);
    
         TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
         stackBuilder.addNextIntent(new Intent(context, MainActivity.class));
         PendingIntent resultPendingIntent =
                 stackBuilder.getPendingIntent(
                         0,
                         PendingIntent.FLAG_UPDATE_CURRENT
                 );
         builder.setContentIntent(resultPendingIntent);
         NotificationManager notificationManager =
                 (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
         notificationManager.notify(1, builder.build());
     }
    
  3. 完成此更改后,日志在启动后显示以下行:

        01-21 12:52:43.112    I/BeaconUtils﹕ I have just switched from seeing/not seeing iBeacons: null
    

    显示以下通知:

    enter image description here

    通常,解决此类问题的最佳方法是添加日志消息。如果您没有看到很多日志消息,我会在每个生命周期和回调方法的顶部添加它们,包括onCreateonIBeaconServiceConnect()等。一旦您这样做,您应该发送任何消息看,但不要让你知道出了什么问题。

    其他一些提示:

    1. 每次从Eclipse / Android Studio启动应用程序时,请务必进行一些代码更改,否则将不会卸载并重新安装应用程序,并且iBeacon服务将不会重新启动。除非重新启动服务,否则您将无法获得已检测到的iBeacons的新输入区域通知。

    2. 请注意,iBeaconManager上只有一个 monitorNotifier或rangesNotifier。无论最后一个通知器集是什么,它将获得所有回调。

    3. 如果您没有看到正在调用您的on onIBeaconServiceConnect()方法(最好使用日志行进行此操作),请停止所有操作直到您正常工作。

    4. 通常,IBeaconConsumer界面旨在与ActivityServiceApplication实例配合使用。使用像BeaconUtils这样的自定义类来执行此操作没有任何问题,但您必须格外小心,以正确设置上下文,并且无论是什么持有对自定义对象的引用都不会在Android生命周期。 修改另外,在制作自定义bindServiceunbindService方法时,方法必须链接到上下文中的等效方法。我很惊讶这一切都是按原样运作的。请在此处查看我的相关答案:https://stackoverflow.com/a/21298560/1461050

答案 1 :(得分:0)

对于任何感兴趣的人,我都使用了原作者在这里所做的出色工作,并将其作为PhoneGap / Cordova插件实现。请随时在以下网址上发表评论,评论等。

https://github.com/TheMattRay/iBeaconGap