использование XMPP для определения местоположения пользователя

Я хочу создать приложение для Android, которое позволит мне получить геолокацию пользователя. Это должно быть сделано как клиент-серверное приложение, а для серверной части я использую OpenFire. Для получения местоположения пользователя мне пришлось бы использовать XEP-0080, верно? И SmackAPI тоже? Я совершенно новичок в XMPP и Smack, поэтому, если кто-нибудь может дать мне несколько указателей или, возможно, примеры или любую документацию по этому поводу, я был бы очень признателен.

Заранее благодарю за любую помощь.


person Robert    schedule 27.04.2010    source источник
comment
Вы также используете сервер OpenFire для обмена мгновенными сообщениями? или вы просто используете его для геолокации?   -  person hannson    schedule 28.04.2010
comment
Я использую его только для геолокации.   -  person Robert    schedule 28.04.2010


Ответы (2)


Проект Android, над которым я сейчас работаю, требовал периодической публикации местоположения пользователя его друзьям из списка XMPP с использованием aSmack и XEP-0080.

Это оказалось сложнее, чем мне хотелось бы, поэтому я задокументировал свое решение здесь: http://www.dbotha.com/2014/11/02/xep-0080-user-location-on-android-using-pep-with-smack/

Для полноты я расскажу здесь о важных частях. В целях краткости я рассмотрю только те дочерние элементы XML из спецификации XEP-0080, которые относятся к широте и долготе.

PEPItem для хранения местоположения пользователя и преобразования его в соответствующий XML:

public class UserLocation extends PEPItem {

    public static final String NODE =
        "http://jabber.org/protocol/geoloc";

    public final double latitude, longitude;

    public UserLocation(double latitude, double longitude) {
        this(StringUtils.randomString(16), latitude, longitude);
    }

    public UserLocation(double latitude, double longitude,
            String id) {
        super(id);
        this.latitude = latitude;
        this.longitude = longitude;
    }

    @Override
    java.lang.String getNode() {
        return NODE;
    }

    // return an XML element approximately inline
    // with the XEP-0080 spec
    @Override
    java.lang.String getItemDetailsXML() {
        return String.format(
            "<geoloc xmlns='%s'><lat>%f</lat>" +
            "<lon>%f</lon></geoloc>",
            NODE, latitude, longitude);
    }
}

В основном шаблонный PEPEvent для хранения PEPItem UserLocation:

public class UserLocationEvent extends PEPEvent {

    private final UserLocation location;

    public UserLocationEvent(UserLocation location) {
        this.location = location;
    }

    public UserLocation getLocation() {
        return location;
    }

    @Override
    public String getNamespace() {
        return "http://jabber.org/protocol/pubsub#event";
    }

    @Override
    public String toXML() {
        return String.format("<event xmlns=" +
            "'http://jabber.org/protocol/pubsub#event' >" +
            "<items node='%s' >%s</items></event>",
            UserLocation.NODE, location.toXML());
    }
}

Пользовательский PacketExtensionProvider для анализа событий UserLocationEvent из входящих пакетов, если они присутствуют.

public class UserLocationProvider
        implements PacketExtensionProvider {

    // This method will get called whenever aSmack discovers a
    // packet extension containing a publish element with the
    // attribute node='http://jabber.org/protocol/geoloc'
    @Override
    public PacketExtension parseExtension(XmlPullParser parser)
            throws Exception {

        boolean stop = false;
        String id = null;
        double latitude = 0;
        double longitude = 0;
        String openTag = null;

        while (!stop) {
            int eventType = parser.next();

            switch (eventType) {
                case XmlPullParser.START_TAG:
                    openTag = parser.getName();
                    if ("item".equals(openTag)) {
                        id = parser.getAttributeValue("", "id");
                    }

                    break;

                case XmlPullParser.TEXT:
                    if ("lat".equals(openTag)) {
                        try {
                            latitude = Double.parseDouble(
                                parser.getText());
                        } catch (NumberFormatException ex) {
                            /* ignore */
                        }
                    } else if ("lon".equals(openTag)) {
                        try {
                            longitude = Double.parseDouble(
                                parser.getText());
                        } catch (NumberFormatException ex) {
                            /* ignore */
                        }
                    }

                    break;

                case XmlPullParser.END_TAG:
                    // Stop parsing when we hit </item>
                    stop = "item".equals(parser.getName());
                    openTag = null;
                    break;
            }
        }

        return new UserLocationEvent(
            new UserLocation(id, latitude, longitude));
    }
}

Теперь связываем все вместе:

XMPPTCPConnection connection = new XMPPTCPConnection();

ServiceDiscoveryManager sdm = ServiceDiscoveryManager
    .getInstanceFor(connection);
sdm.addFeature("http://jabber.org/protocol/geoloc");
sdm.addFeature("http://jabber.org/protocol/geoloc+notify");

EntityCapsManager capsManager = EntityCapsManager
    .getInstanceFor(connection);
capsManager.enableEntityCaps();

PEPProvider pepProvider = new PEPProvider();
pepProvider.registerPEPParserExtension(
    "http://jabber.org/protocol/geoloc",
    new UserLocationProvider());
ProviderManager.addExtensionProvider("event",
    "http://jabber.org/protocol/pubsub#event", pepProvider);
PEPManager pepManager = new PEPManager(connection);
pepManager.addPEPListener(PEP_LISTENER);

connection.connect();
connection.login(username, password);

И, наконец, прослушиватель входящих событий LocationEvent:

PEPListener PEP_LISTENER = new PEPListener() {
    @Override
    public void eventReceived(String from, PEPEvent event) {
        if (event instanceof UserLocationEvent) {
            // do something interesting
        }
    }
};
person dbotha    schedule 03.11.2014
comment
Было бы здорово, если бы вы захотели отправить код вверх по течению: github.com/igniterealtime/Smack/wiki/ и igniterealtime.org /issues/browse/SMACK-610 - person Flow; 03.11.2014
comment
Есть небольшая проблема с расширением PEPItem. Его абстрактные методы не имеют модификатора доступа, но вам нужен публичный модификатор, чтобы переопределить их (поскольку без модификатора доступа они видны только для своего пакета — импортированной библиотеки JAR, а когда вы используете свой собственный пакет — расширяйте PEPItem в своем собственном пакете, они будут быть недоступным). Я решил это, перестроив банку библиотеки aSmack с добавлением общедоступных модификаторов в класс PEPItem. - person tomm; 16.03.2015
comment
Я обнаружил следующую проблему при анализе широты и долготы из xml. Я получаю строку, содержащую двойное число, но не с точкой, а с запятой (мой телефон локализован на словацкий язык, а не на английский). Таким образом, при разборе в UserLocationProvider возникали исключения. Решением может быть либо замена всех запятых точками в строке перед синтаксическим анализом в UserLocationProvider, либо установка локали (например, Locale.ENGLISH) в UserLocation.getItemDetailsXML() для метода format() (поэтому не используйте этот метод без параметра локали, что приводит к использованию предопределенной локали устройства). - person tomm; 11.05.2015

Я считаю, что это близко к тому, что вы пытаетесь достичь.

Расположение пользователя XEP-0080 в библиотеке Smack

person Rob Goodwin    schedule 27.04.2010
comment
спасибо за эту ссылку, я ее видел и планирую использовать, но есть ли у вас полный пример использования расширений XMPP в программах Java, потому что, как я уже сказал, я совершенно новичок в этой области. спасибо еще раз за помощь - person Robert; 28.04.2010
comment
Мне просто нужно несколько подсказок, что делать в первую очередь. Как я уже сказал, я полный нуб в этой области. Должен ли я сначала настроить свой сервер Openfire (создать новый плагин) для такого рода вещей, или он поддерживает его по умолчанию, или мне просто нужно разработать приложение для Android, которое делает то, что оно делает. Это для моей диссертации, так что это очень важно. заранее спасибо - person Robert; 28.04.2010
comment
Поддерживает ли Openfire XEP-0800? - person Rob Goodwin; 28.04.2010
comment
Насколько я знаю, нет, но я думаю, что для него можно создать плагин, верно? - person Robert; 29.04.2010
comment
Я не думаю, что сервер XMPP нуждается в поддержке XEP-0800, так как это просто определение формата местоположения пользователя. Меня можно транспортировать через Publish-Subscribe (XEP-0060) или Personal Eventing (XEP-0163). Openfire поддерживает XEP-0060. - person Flow; 10.02.2012