Обнаружение iBeacon и сбор данных в Android

Я использую тестовое приложение для Android, предоставленное Radius Network, для обнаружения iBeacon. У меня есть iPad, настроенный как iBeacon, и я добавил около 3 областей маяка в комплект бесконтактных датчиков. Проблема, с которой я сталкиваюсь сейчас, заключается в том, что я не могу получить имя маяка и дополнительный URL-адрес, который у меня был в наборе бесконтактного доступа в Android.

Мне нужно в основном показать URL-адрес, связанный с областью маяка, в этом наборе близости в приложении Android, как это делает приложение iOS.

Во время отладки я проверил, что даже после того, как маяк обнаружен в приложении, didEnterRegion не вызывается. Мне нужно в основном сохранить детали этого конкретного маяка в базе данных после его обнаружения.

Приложение также не вызывает didExitRegion.

Разместив приведенный ниже код, пожалуйста, дайте мне знать, что я делаю неправильно в этом.

public class AndroidProximityReferenceApplication extends Application implements
        BootstrapNotifier {
    private static final String TAG = "AndroidProximityReferenceApplication";
    private RegionBootstrap regionBootstrap;
    private BackgroundPowerSaver backgroundPowerSaver;
    private boolean haveDetectedIBeaconsSinceBoot = false;

    public void onCreate() {
        super.onCreate();
        Log.d(TAG,
                "setting up background monitoring for iBeacons and power saving");

        // wake up the app when an iBeacon is seen
        Region region = new Region(
                "com.radiusnetworks.androidproximityreference.backgroundRegion",
                "2F234454-CF6D-4A0F-ADF2-F4911BA9FFA6", null, null);
        regionBootstrap = new RegionBootstrap(this, region);

        // simply constructing this class and holding a reference to it in your
        // custom Application
        // class will automatically cause the iBeaconLibrary to save battery
        // whenever the application
        // is not visible. This reduces bluetooth power usage by about 60%
        backgroundPowerSaver = new BackgroundPowerSaver(this);
    }

    @Override
    public void didDetermineStateForRegion(int arg0, Region arg1) {
        // This method is not used in this example
    }

    @Override
    public void didEnterRegion(Region arg0) {
        // In this example, this class sends a notification to the user whenever
        // an iBeacon
        // matching a Region (defined above) are first seen.
        Log.d(TAG, "did enter region.");
        if (!haveDetectedIBeaconsSinceBoot) {
            Log.d(TAG, "auto launching MainActivity");

            // The very first time since boot that we detect an iBeacon, we
            // launch the
            // MainActivity
            Intent intent = new Intent(this, MainActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            // Important: make sure to add android:launchMode="singleInstance"
            // in the manifest
            // to keep multiple copies of this activity from getting created if
            // the user has
            // already manually launched the app.
            this.startActivity(intent);
            haveDetectedIBeaconsSinceBoot = true;
        } else {
            // If we have already seen iBeacons and launched the MainActivity
            // before, we simply
            // send a notification to the user on subsequent detections.
            Log.d(TAG, "Sending notification.");
            ParseObject beacon = new ParseObject("Beacon");
            beacon.put("beacon_name", arg0.getClass().getName());
            beacon.put("beacon_id", arg0.getUniqueId());
            beacon.put("device_type", "Android");
            beacon.put("device_UUID", android.os.Build.MODEL);
            beacon.put("beacon_status", "ENTRY");
            beacon.saveInBackground();

            sendNotification();
        }

    }

    @Override
    public void didExitRegion(Region arg0) {
        Log.d(TAG, "exited region");
        ParseObject beacon = new ParseObject("Beacon");
        beacon.put("beacon_name", arg0.getClass().getName());
        beacon.put("beacon_id", arg0.getUniqueId());
        beacon.put("device_type", "Android");
        beacon.put("device_UUID", android.os.Build.MODEL);
        beacon.put("beacon_status", "ENTRY");
        beacon.saveInBackground();

    }

    private void sendNotification() {
        NotificationCompat.Builder builder = new NotificationCompat.Builder(
                this).setContentTitle("Proximity Reference Application")
                .setContentText("An iBeacon is nearby.")
                .setSmallIcon(R.drawable.ic_launcher);

        TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
        stackBuilder.addNextIntent(new Intent(this, MainActivity.class));
        PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,
                PendingIntent.FLAG_UPDATE_CURRENT);
        builder.setContentIntent(resultPendingIntent);
        NotificationManager notificationManager = (NotificationManager) this
                .getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(1, builder.build());

    }
}

Приведенный ниже код относится к классу mainActivity.

public class MainActivity extends Activity implements IBeaconConsumer,
        RangeNotifier, IBeaconDataNotifier {
    public static final String TAG = "MainActivity";

    IBeaconManager iBeaconManager;
    Map<String, TableRow> rowMap = new HashMap<String, TableRow>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Parse.initialize(this, "test123",
                "test345");
        IBeaconManager.LOG_DEBUG = true;
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        iBeaconManager = IBeaconManager.getInstanceForApplication(this
                .getApplicationContext());
        iBeaconManager.bind(this);
    }

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

    @Override
    public void onDestroy() {
        super.onDestroy();
        iBeaconManager.unBind(this);
    }

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

        }
    }

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

    private void displayTableRow(final IBeacon iBeacon,
            final String displayString, final boolean updateIfExists) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                TableLayout table = (TableLayout) findViewById(R.id.beacon_table);
                String key = iBeacon.getProximity() + "-" + iBeacon.getMajor()
                        + "-" + iBeacon.getMinor();
                TableRow tr = (TableRow) rowMap.get(key);
                if (tr == null) {
                    tr = new TableRow(MainActivity.this);
                    tr.setLayoutParams(new TableRow.LayoutParams(
                            TableRow.LayoutParams.WRAP_CONTENT,
                            TableRow.LayoutParams.WRAP_CONTENT));
                    rowMap.put(key, tr);
                    table.addView(tr);
                } else {
                    if (updateIfExists == false) {
                        return;
                    }
                }
                tr.removeAllViews();
                TextView textView = new TextView(MainActivity.this);
                textView.setText(displayString);
                tr.addView(textView);

            }
        });

    }

}

Будем признательны за любую помощь. Спасибо :)


person Sumodh Nair    schedule 04.06.2014    source источник
comment
Я не понимаю этого: даже после того, как маяк обнаружен в приложении, didEnterRegion не вызывается. Как узнать, что маяк обнаружен, если метод не вызывается?   -  person davidgyoung    schedule 04.06.2014
comment
@davidgyoung: - предположение делается, когда приложение перечисляет ближайший маяк со связанным с ним uuid близости, а также его основными и второстепенными значениями.   -  person Sumodh Nair    schedule 04.06.2014
comment
Хорошо, должен быть какой-то другой код, который отображает идентификаторы, которые не показаны выше. Я подозреваю, что этот код может мешать функционированию показанного кода. Не могли бы вы опубликовать код, который отображает идентификаторы маяков?   -  person davidgyoung    schedule 04.06.2014
comment
@davidgyoung: извините за поздний ответ. Я обновил код с помощью основного класса Activity. Пожалуйста, дайте мне знать, что я делаю неправильно? Спасибо.   -  person Sumodh Nair    schedule 05.06.2014
comment
@davidgyoung: после обновления AndroidProximityLibrary я теперь могу получать данные, связанные с ближайшим маяком, и методы области выхода и входа вызываются только для маяков, чей UUID близости указан в приложении. Что делать, если мне нужно получить подробности о других маяках, а также с разными UUID в моем наборе, я обнаружил, что методы выхода и входа никогда не вызываются для них. Также уведомление, которое появляется, когда приложение находится в фоновом режиме, вообще не отображается. Не могли бы вы сказать мне, что я делаю неправильно? Спасибо   -  person Sumodh Nair    schedule 05.06.2014


Ответы (1)


При использовании Proximity Kit для Android доступны два отдельных набора API. В одном наборе используется ProximityKitManager, и он предназначен для более простых случаев использования, когда вы можете предварительно настроить все свои идентификаторы iBeacon и связанные с ними данные на стороне сервера и позволить ProximityKitManager управлять настройкой ранжирования и мониторинга в глобальном классе приложения.

Второй набор API использует IBeaconManager и обеспечивает более детальное управление. Но поскольку ProximityKitManager использует IBeaconManager под капотом, вам не следует использовать оба одновременно, потому что вы можете легко нарушить автоматическую настройку, выполненную ProximityKitManager. Я подозреваю, что именно это вызывает вашу проблему, потому что код использует ProximityKitManager в классе Application и IBeaconManager в классе Activity. Подробнее см. здесь.

Если вам нужно отслеживать маяки независимо от идентификаторов, установленных в ProximityKit, но при этом вы хотите получить доступ к данным, настроенным для определенных iBeacons в ProximityKit, вам не следует использовать ProximityKitManager, а вместо этого просто используйте IBeaconManager. здесь доступно эталонное приложение, которое показывает, как получить доступ к данным ProximityKit с помощью этого API.

person davidgyoung    schedule 05.06.2014
comment
Спасибо за ваш ответ. Сейчас мне удалось получить все подробности. Сейчас я столкнулся с проблемой, когда, если приложение работает в фоновом режиме, я могу запускать приложение каждый раз, когда обнаруживается iBeacon, но оно не запускается, если Я завершаю работу приложения. Есть ли какой-либо способ заставить приложение работать, даже если пользователь закрыл приложение? Кажется, iPhone решил эту проблему в iOS 7.1, интересно, смогу ли я сделать это в Android? Я новичок в Android, поэтому мало что знаю об этом. Спасибо. - person Sumodh Nair; 06.06.2014
comment
Библиотека временно прекратит сканирование после закрытия вашего приложения с помощью переключателя задач, но автоматически перезапустится. Это гарантированно произойдет при следующей загрузке, поэтому простой способ проверить — перезагрузить телефон после закрытия приложения. - person davidgyoung; 06.06.2014