android中实现自定义xmpp消息包收发

devbird devbird     2022-08-01     548

关键词:

       在Android平台实现XMPP即时通讯主要是使用asmack这个包,asmack是XMPP协议的实现。但是asmack只能帮助我们实现一些基本消息包的收发,如果需要实现特定的自定义消息包收发需要我们自己处理。


一、asmack消息的发送和接收

  • 发送Message消息:

       发送一个message结的消息,可以使用sendMessage()发送消息,这个方法有两个重载方法,一种类型的参数是String类型,另一种则是传入Message对象。String类型的方法传入的字符串即为要发送的消息;传入message对象的方需要写一个类继承Message,重写toXML()方法,toXML()方法的返回值即为要发送的消息。例如:


    //1、通过传入String类型的sendMessage()方法发送消息:

    ChatManager chatManager = xmppConnection.getChatManager();
     /**
         * String userJID 对方的JID
         * MessageListener listener 消息监听,当收到消息后会回调processMessage(Chat chat, Message message)方法
         */
    Chat mChat = chatManager.createChat(mToUser, this);
    mChat.sendMessage("your content");
    //2、通过传入Message对象的sendMessage()方法发送消息:

    /**
    *写一个类继承Message重写toXML()方法,方法的返回值即为要发送的消息
    */
    public class MyMessage extends Message {

         @Override
        public String toXML() {

            return "your content";
        }

    }

    ChatManager chatManager = xmppConnection.getChatManager();
     /**
         * String userJID 对方的JID
         * MessageListener listener 消息监听,当收到消息后会回调processMessage(Chat chat, Message message)方法
         */
    Chat mChat = chatManager.createChat(mToUser, this);
    MyMessage myMessage = new MyMessage();
    mChat.sendMessage(myMessage);
  • 接收Message消息:

       接收Message类型的消息主要是在processMessage(Chat chat, Message message)方法中,当收到消息后都会回调这个方法,需要实现MessageListener这个接口,然后实现接口中的processMessage(Chat chat, Message message)方法。


二、发送和接收自定义类型的IQ结消息

       当发送的iq消息中包含自定义的xml结的时候,asmack提供的解析并不能识别这些自定义的xml结,所以就需要我们自己实现消息包的解析和拼装。

1、发送含自定义xml结的iq消息。

例如发送这样一个iq消息:

<iq id=‘123‘ type=‘get‘ from=[email protected]/B‘ to=[email protected]/s2‘><req var=‘read‘><attr var=‘temprature‘/></req></iq>

发送步骤:


    //步骤:
    //1、写一个类继承IQ并重写getChildElementXML()方法,该方法的返回值将作为消息体。
    public class MyIQ extends IQ {
        @Override
        public String getChildElementXML() {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append("&lt;req var=‘read‘&gt;&lt; attr var=‘temprature‘/&gt;&lt;/req&gt;");
            return stringBuilder.toString();
        }
    }
    //2、发送这个含自定义xml结的iq消息包
    MyIQ packet = new MyIQ();
    packet.setType(IQ.Type.GET);//设置IQ结type
    packet.setFrom("[email protected]/B");//设置IQ结from
    packet.setTo("[email protected]/s2");//设置IQ结to
    xmppConnection.sendPacket(packet);//发送消息包

2、解析服务器返回的iq消息包,消息包中含自定义xml结。

例如解析服务器返回的这样一个iq消息:

<iq id=‘12‘ type=‘result‘ from=[email protected]/s2‘ to=[email protected]/B‘><resp xmlns=‘data‘><attr var=‘temprature‘>17</attr></resp></iq>

解析步骤:


    //步骤:
    //1、写一个类 implements PacketListener接口并实现其中的processPacket(Packet packet)方法。
    public class MyPacketListener implements PacketListener {
        @Override
        public void processPacket(Packet packet) {
            //当收到消息包就会回调该方法
        }
    }
    //2、添加包监听器
    MyPacketListener mMyPacketListener = new MyPacketListener();
    //该方法有两个参数
    //第一个参数:    PacketListener  包监听器
    //第二个参数:   PacketFilter  包过滤器
    xmppConnection.addPacketListener(mMyPacketListener, null);
    //完成以上两步后,当收到消息包都会回调MyPacketListener中的processPacket(Packet packet)方法。
    //3、写一个类继承IQ并实现getChildElementXML()方法。
    public class GetDataResp extends IQ {
        //例如我们要获取上面iq消息包中的temprature和17两个属性,所以将这两个值声明为成员变量,并生成get和set方法。
        public String var;
        public String value;
        public String getVar() {return var;}
        public void setVar(String var) {this.var = var;}
        public String getValue() {return value;}
        public void setValue(String value) {his.value = value;}
        @Override
        public String getChildElementXML(){
            //拼装消息
            StringBuilder buf = new StringBuilder();
            buf.append("&lt;resp xmlns=‘get:data‘&gt;&lt;attr var=‘");
    ·       buf.append(getVar());
            buf.append("‘>");
            buf.append(getValue());
            buf.append("&lt;/attr&gt;&lt;/resp&gt;");
            return buf.toString();
        }
    }
    //4、写一个类implements IQProvider并实现接口中的parseIQ(XmlPullParser parser)方法。
    public class GetDataRespProvider implements IQProvider {
        @Override
        public IQ parseIQ(XmlPullParser parser) throws Exception {
            GetDataResp getDataResp = new GetDataResp();//这个对象是上面第三步中的那个类对象
            boolean done = false;
            while (!done) {
                int eventType = parser.next();
                if (eventType == XmlPullParser.START_TAG) {
                    if (parser.getName().equals("attr")) {
                        String var = parser.getAttributeValue("", "var");//获取var属性的value即:temprature
                        String value = parser.nextText();//获取attr的文本即:17
                        getDataResp.setVar(var);
                        getDataResp.setValue(value);
                    }
                }else if (eventType == XmlPullParser.END_TAG) {
                    if (parser.getName().equals("resp")) {
                        done = true;
                    }
                }
            }
             return getDataResp;
        }
    }
    //5、在配置ConnectionConfiguration时添加IQProvider
    //第一个参数是:String 元素的名称
    //第二个参数是:String  命名空间
    //第三个参数是:Object  需要传入一个prvider对象
    ProviderManager.getInstance().addIQProvider("resp", "data", new GetDataRespProvider());
    //6、在第一步MyPacketListener中的processPacket(Packet packet)方法中获取相应消息包
    public class MyPacketListener implements PacketListener {
        @Override
        public void processPacket(Packet packet) {
            if (packet instanceof GetDataResp) {
                GetDataResp getDataResp = (GetDataResp) packet;
                String from = getDataResp.getFrom();
                String to = getDataResp.getTo();
                String var = getDataResp.getVar();
                String value = getDataResp.getValue();
            }
        }
    }

三、总结

  • 发送message类型的消息中如果带有自定义xml结,需要写一个类继承Message并重写toXML()方法,该方法的返回值便是消息体。
  • 发送的iq类型的消息中如果带有自定义xml结,需要写一个类继承IQ并重写getChildElementXML()方法,该方法的返回值将作为消息体
  • 服务器返回的iq消息类型中如果带有自定义的xml结:
    • 写一个类继承IQ并重写getChildElementXML()方法,将服务器返回的消息中需要的信息做成成员变量,并拼装出消息体,最后作为返回值返回。
    • 写一个类implements IQProvider并实现接口中的parseIQ(XmlPullParser parser)方法,然后在该方法中做出对应的解析过程,最后通过返回值返回上一个步骤中的IQ对象。
    • 服务器返回的iq消息中的消息体必须带有命名空间。
    • 需要通过这个方法ProviderManager.getInstance().addIQProvider("resp", "data", new GetDataRespProvider());添加相应的IQProvider。
  • 如果需还需要实现一些自定义的解析,可以修改asmack源码中的PacketParserUtils这个类中对应的方法。

下面是源码地址:

点击:下载地址

在 Android 中实现自定义 ListView

】在Android中实现自定义ListView【英文标题】:ImplementacustomListViewinAndroid【发布时间】:2016-10-2802:16:18【问题描述】:我在我的MainActivity中创建了一个listView,并为行布局创建了另一个布局文件,如下所示:问题是,我该如何实现... 查看详情

android中实现自定义的拍照应用

可以参考:http://www.android-doc.com/guide/topics/media/camera.html一、添加相应的权限<uses-permissionandroid:name="android.permission.CAMERA"/><uses-featureandroid:name="android.hardware.camera"/><!- 查看详情

如何在android中实现自定义可折叠工具栏?

】如何在android中实现自定义可折叠工具栏?【英文标题】:HowtoimplementCustomCollapsableToolbarinandroid?【发布时间】:2015-11-2212:08:36【问题描述】:使用thistutorial实现灵活空间模式(带有折叠工具栏的模式)。我正在尝试实现与Lollipop... 查看详情

在spring boot中实现自定义错误

】在springboot中实现自定义错误【英文标题】:Implementthecustomerrorinspringboot【发布时间】:2019-04-0702:58:26【问题描述】:我想页面。在应用程序中,id是主键,所以当没有给出id时,它会将请求传输到页面,但我希望应用程序在索... 查看详情

在 Gradle Android 中实现自定义库时未解析类

】在GradleAndroid中实现自定义库时未解析类【英文标题】:ClassnotresolvedwhenimplementingcustomlibraryinGradleAndroid【发布时间】:2022-01-0201:32:22【问题描述】:我创建了一个android库并在Jitpack中发布。目前,我的构建在Jitpack中取得了成功... 查看详情

在 MembershipProvider 中实现自定义“ValidateUser”

】在MembershipProvider中实现自定义“ValidateUser”【英文标题】:Implementcustom"ValidateUser"inMembershipProvider【发布时间】:2011-03-2510:32:38【问题描述】:我正在实现一个自定义MembershipProvider,我正在尝试使用ValidateUser方法来验证... 查看详情

如何在 keras 中实现自定义指标?

】如何在keras中实现自定义指标?【英文标题】:howtoimplementcustommetricinkeras?【发布时间】:2016-10-0601:13:54【问题描述】:我得到这个错误:sum()得到了一个意外的关键字参数\'out\'当我运行这段代码时:importpandasaspd,numpyasnpimportkera... 查看详情

如何在 iPhone 中实现自定义相机功能? [关闭]

】如何在iPhone中实现自定义相机功能?[关闭]【英文标题】:HowtoimplementcustomcamerafunctionalityiniPhone?[closed]【发布时间】:2011-08-1605:07:13【问题描述】:我想开发一种功能,以便在iPhone应用程序中实现自定义相机功能,所以请给我... 查看详情

在具有条件的 keras 中实现自定义损失函数

】在具有条件的keras中实现自定义损失函数【英文标题】:Implementingcustomlossfunctioninkeraswithcondition【发布时间】:2018-12-0813:49:59【问题描述】:我需要一些有关keras损失函数的帮助。我一直在使用Tensorflow后端在keras上实现自定义损... 查看详情

在 Freemarker 中实现自定义 Escaper

】在Freemarker中实现自定义Escaper【英文标题】:ImplementaCustomEscaperinFreemarker【发布时间】:2010-11-0920:21:59【问题描述】:Freemarker可以使用以下方式进行文本转义:<#escapexasx?html>Foo:$someValBar:$someOtherVal</#escape>xml、xhtml和html... 查看详情

为啥不推荐使用 JScript 在 WiX 中实现自定义操作?

】为啥不推荐使用JScript在WiX中实现自定义操作?【英文标题】:WhyisusingJScriptforimplementingcustomactionsinWiXnotrecommended?为什么不推荐使用JScript在WiX中实现自定义操作?【发布时间】:2013-07-1008:19:33【问题描述】:在浏览有关WiX的文... 查看详情

如何在canvas中实现自定义路径动画(代码片段)

在最近的项目中笔者需要做一个新需求:在canvas中实现自定义的路径动画。这里所谓的自定义路径不单单包括一条直线,也许是多条直线的运动组合,甚至还包含了贝塞尔曲线,因此,这个动画也许是下面这个样子的:那么如何... 查看详情

具有自定义元素或属性的 Tigase-XMPP 消息包

】具有自定义元素或属性的Tigase-XMPP消息包【英文标题】:Tigase-XMPPMessagePacketwithCustomElementsorAttributes【发布时间】:2014-03-1114:40:04【问题描述】:<messagexmlns="jabber:client"to="5410037:testingmine@muc.app.smsall.pk"type="groupchat"from="54100 查看详情

在 kvm 中实现自定义超级调用

】在kvm中实现自定义超级调用【英文标题】:Implementingacustomhypercallinkvm【发布时间】:2016-02-0900:28:27【问题描述】:我对虚拟化非常陌生,最近我一直在尝试熟悉VMM的操作方式以及如何进行超级调用。谈到我打算在安装在我的Ubu... 查看详情

如何在黄瓜中实现自定义监听器?

】如何在黄瓜中实现自定义监听器?【英文标题】:Howtoimplementcustomlistenersincucumber?【发布时间】:2021-12-2214:55:47【问题描述】:如何在cucumber中实现客户监听?哪个可以记录到控制台/报告失败方法的发生?使用黄瓜4.0注意:钩... 查看详情

在 SDK 中实现自定义取消按钮

】在SDK中实现自定义取消按钮【英文标题】:ImplementcustomCancelButtoninaSDK【发布时间】:2015-11-0917:24:08【问题描述】:我想用paysbuySDK实现支付功能....问题是它没有任何cancel选项,以便用户可以在支付成功后取消关闭操作。默认情... 查看详情

如何在 UIImagePicker 中实现自定义“使用”和“重拍”按钮?

】如何在UIImagePicker中实现自定义“使用”和“重拍”按钮?【英文标题】:Howtoimplementcustom\'Use\'and\'Retake\'buttoninUIImagePicker?【发布时间】:2011-03-2507:06:04【问题描述】:我的意思是,我已经关闭了相机控制器pickerCam.showsCameraContro... 查看详情

如何在自定义 Spring 存储库中实现自定义方法? [复制]

】如何在自定义Spring存储库中实现自定义方法?[复制]【英文标题】:Howtoimplementcustommethodincustomspringrepository?[duplicate]【发布时间】:2016-03-2719:36:21【问题描述】:假设我想要一个方法,获取超级主客户,有id=0。我有客户类:@Ent... 查看详情