【问题标题】:using XMPP for user location使用 XMPP 获取用户位置
【发布时间】:2010-04-27 22:05:33
【问题描述】:

我想为 Android 创建一个应用程序,使我能够获取用户的地理位置。这必须作为客户端-服务器应用程序制作,而对于服务器端,我使用的是 OpenFire。 为了获取用户的位置,我必须使用 XEP-0080,对吧?还有 SmackAPI 吗? 我对 XMPP 和 Smack 完全陌生,所以如果有人能给我一些建议或示例或任何类型的文档,我将不胜感激。

提前感谢您的帮助。

【问题讨论】:

  • 您是否也在使用 OpenFire 服务器进行 IM?还是您只是将其用于地理定位?
  • 我只是将它用于地理定位。

标签: android xmpp smack


【解决方案1】:

我目前正在处理的一个 Android 项目需要使用 aSmack 和 XEP-0080 定期将用户的位置发布给他们的 XMPP 花名册朋友。

结果比我想象的要复杂,所以我在这里记录了我的解决方案:http://www.dbotha.com/2014/11/02/xep-0080-user-location-on-android-using-pep-with-smack/

为了完整起见,我将在这里介绍重要部分。为了简洁起见,我将介绍的 XEP-0080 规范中的唯一 XML 子元素是那些与纬度和经度相关的元素。

用于保存用户位置并将其转换为适当的 XML 的 PEPItem:

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);
    }
}

用于保存 UserLocation PEPItem 的大部分样板 PEPEvent:

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
        }
    }
};

【讨论】:

  • 如果您愿意将代码发送到上游,那就太好了:github.com/igniterealtime/Smack/wiki/…igniterealtime.org/issues/browse/SMACK-610
  • 扩展 PEPItem 有一点问题。它的抽象方法没有访问修饰符,但是您需要公共修饰符来覆盖它们(因为没有访问修饰符,它们仅对其包可见 - 导入的库 JAR,并且当您使用自己的包时 - 在自己的包中扩展 PEPItem,它们将不可访问)。我通过在 PEPItem 类中添加公共修饰符重建 aSmack 库 jar 来解决它。
  • 我在从 xml 解析纬度和经度时发现了下一个问题。我得到包含双精度的字符串,但不是带点而是带逗号(我的手机已本地化为斯洛伐克语而不是英语)。所以在 UserLocationProvider 中解析时出现异常。解决方案可能是在解析 UserLocationProvider 之前将字符串中的所有逗号替换为点,或者在 UserLocation.getItemDetailsXML() 中为 format() 方法设置语言环境(例如 Locale.ENGLISH)(所以不要在没有语言环境参数的情况下使用此方法,这会导致使用设备预定义的语言环境)。
【解决方案2】:

我相信这与您想要完成的目标很接近。

XEP-0080 User Location in Smack Library

【讨论】:

  • thnx 这个链接,我已经看过并打算使用它,但是你有没有在 Java 程序中使用 XMPP 扩展的完整示例,因为就像我说的,我是全新的到这个区域。再次寻求帮助
  • 我只需要一些关于首先做什么的线索。就像我说的,我在这个领域完全是菜鸟。我是否必须首先为这种东西配置我的 Openfire 服务器(创建新插件),或者它是否默认支持它,或者我只需要开发 Android 应用程序来完成它的工作。这是我的论文,所以它有点重要。提前致谢
  • Openfire 是否支持 XEP-0800
  • 据我所知我没有,但我认为可以为它创建一个插件,对吧?
  • 我不认为 XMPP 服务器需要对 XEP-0800 的支持,因为它只是用户位置格式的定义。我可以通过 Publish-Subscribe (XEP-0060) 或 Personal Eventing (XEP-0163) 传输。 Openfire 确实支持 XEP-0060。
猜你喜欢
  • 1970-01-01
  • 2020-10-21
  • 2013-12-29
  • 2012-08-19
  • 2017-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多