Android 使用Smack+openfire开发基于XMPP协议的聊天

本文:openfire:4.0.1,Smack:4.1.6

OpenFire与Smack下载:http://www.igniterealtime.org/index.jsp

SmackAPI:http://www.igniterealtime.org/projects/index.jsp

Smack开发指南:http://www.igniterealtime.org/builds/smack/docs/latest/documentation/

Smack源码(GitHub地址):https://github.com/igniterealtime/Smack

Smack开发指南写的很简单只描述了一些基本功能,本文记录我在开发过程中遇到的开发指南上没有的问题。

XMPP官网:http://www.xmpp.org/

Android怎么导入Smack的jar包(请参考Android部分):https://github.com/igniterealtime/Smack/wiki/Smack-4.1-Readme-and-Upgrade-Guide

这里有一个老外回答的怎么在Android上使用Smack:http://stackoverflow.com/questions/26965506/how-to-use-smack-4-1-in-android

两个对学习XMPP有帮助的博客:

1、http://blog.csdn.net/lnb333666/article/list/1

2、http://blog.csdn.net/h7870181?viewmode=contents

这两个博主都是基于ASmack开发的,我是基于Smack开发的不过有很多代码通用,很有借鉴意义。


1、登录后立马获取Roster一般是获取不到的,你可以这么做:

mRoster.addRosterLoadedListener(new RosterLoadedListener() {
                                    
                                    @Override
                                    public void onRosterLoaded(Roster arg0) {
                                        getAllRoster();
                                    }
                                });

监听所有Roster加载完成后进行获取。


2、添加好友:

private void addUser(String userId){
        if(userId.indexOf("@你服务器的域名或IP")==-1){
            userId=userId+"@你服务器的域名或IP";
        }
        
        mRoster.addRosterListener(new RosterListener(){

            @Override
            public void entriesAdded(Collection arg0) {
            }

            @Override
            public void entriesDeleted(Collection arg0) {
            }

            @Override
            public void entriesUpdated(Collection arg0) {
            }

            @Override
            public void presenceChanged(Presence arg0) {
            }
            
        });
        try {
            mRoster.createEntry(userId, userId, new String[]{"好友分组名"});
        } catch (NotLoggedInException e) {
            e.printStackTrace();
        } catch (NoResponseException e) {
            e.printStackTrace();
        } catch (XMPPErrorException e) {
            e.printStackTrace();
        } catch (NotConnectedException e) {
            e.printStackTrace();
        }
    }


3、监听别人对你添加好友(也可以监听别人是否响应你的添加请求,在4.1.6PacketListener和PacketTypeFilter提示以过期):
public void addSubscriptionListener() {
    PacketTypeFilter packetFilter = new PacketTypeFilter(Presence.class);      
         PacketListener subscribeListener = new PacketListener(){      

            @Override
            public void processPacket(Stanza stanza) throws NotConnectedException {
                Looper.prepare();
                final Presence presence = (Presence)stanza;     
                if (presence.getType().equals(Presence.Type.subscribe)) {      
                       Toast.makeText(MainActivity.this, stanza.getFrom()+"请求添加你为好友",
                               Toast.LENGTH_SHORT).show();
                } else if (presence.getType().equals(Presence.Type.unsubscribe)) {      
                    Toast.makeText(MainActivity.this, stanza.getFrom()+"删除了你",
                            Toast.LENGTH_SHORT).show();
                }
                Looper.loop();
            }      
                   
         };      
         mXMPPTCPConnection.addPacketListener(subscribeListener, packetFilter);      
    }

4、添加好友分组:

public static boolean addGroup(Roster roster, String groupName) {
        try {
            roster.createGroup(groupName);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


5、获取账户所有属性信息:

    /**
     * 获取账户所有属性信息
     * @return
     */
    public Set getAccountAttributes() {
        if(isConnected()) {
            try {
            return AccountManager.getInstance(connection).getAccountAttributes();
        } catch (Exception e) {
        throw new RuntimeException(e);
        }
        }
        throw new NullPointerException("服务器连接失败,请先连接服务器");
    }


6、删除好友:

/* 删除好友
    *  
    * @param roster
    * @param userName
    * @return
    */  
   public static boolean removeUser(Roster roster, String userName) {  
       try {  
           if (userName.contains("@")) {  
               userName = userName.split("@")[0];  
           }  
 
           RosterEntry entry = roster.getEntry(userName);  
           System.out.println("删除好友:" + userName);  
           System.out.println("User." + roster.getEntry(userName) == null);  
           roster.removeEntry(entry);  
 
           return true;  
       } catch (Exception e) {  
           e.printStackTrace();  
           return false;  
       }  

   }


7、获取所有会议服务器与服务器中的群聊(获取所有群聊):

private void getChatGroups() {  
        try {  
            Collection hostrooms = multiUserChatManager.getHostedRooms("124.128.194.106");
            for (HostedRoom entry : hostrooms) {  
                List listDiscoverItems = new ArrayList();  
                // 获得与XMPPConnection相关的ServiceDiscoveryManager  
                ServiceDiscoveryManager discoManager = ServiceDiscoveryManager  
                        .getInstanceFor(MainActivity.mXMPPTCPConnection);  
          
                // 获得指定XMPP实体的项目  
                // 这个例子获得与在线目录服务相关的项目  
                try {  
                    DiscoverItems discoItems = discoManager.discoverItems(entry.getJid());  
                    // 获得被查询的XMPP实体的要查看的项目  
                    List listItems = discoItems.getItems();  
                    // 显示远端XMPP实体的项目  
                    for(DiscoverItems.Item item:listItems){
                        GroupInfo groupInfo=new GroupInfo();
                        groupInfo.setName(item.getName());
                        groupInfo.setService(entry.getJid());
                        groupInfo.setEntityId(item.getEntityID());
                        groupInfo.setAction(item.getAction());
                        groupInfo.setNode(item.getNode());
                        mList.add(groupInfo);
                    }
                    setListAdapter();
                } catch (XMPPException e) {  
                    e.printStackTrace();  
                }
            }  
        } catch (XMPPException e) {  
            e.printStackTrace();  
        } catch (NoResponseException e1) {
            e1.printStackTrace();
        } catch (NotConnectedException e1) {
            e1.printStackTrace();
        }  
    }


8、加入群聊:

try {
                MultiUserChat multiUserChat=multiUserChatManager
                        .getMultiUserChat(editText.getText().toString());
                multiUserChat.join("nickname");
            } catch (NoResponseException e) {
                e.printStackTrace();
            } catch (XMPPErrorException e) {
                e.printStackTrace();
            } catch (NotConnectedException e) {
                e.printStackTrace();
            }


9、获取离线消息:

获取好友的离线消息:

private void getOfflineMessage(){
        new Thread(){

            @Override
            public void run() {
                offlineMsgList.clear();

                //使用OfflineMessageManager需要先“离线状态登录”然后获取离线消息

                 XMPPTCPConnectionConfiguration configuration=XMPPTCPConnectionConfiguration.builder()
                .setServiceName("124.128.194.106")
                .setHost("124.128.194.106")
                .setPort(5222)
                .setUsernameAndPassword("15606416093", "1111111a")
                .setSendPresence(isPresence)
                .setSecurityMode(SecurityMode.disabled)
                .setConnectTimeout(15*1000)
                .setCompressionEnabled(false)
                .build();
                mXMPPTCPConnection=new XMPPTCPConnection(configuration);
                mXMPPTCPConnection.addConnectionListener(new ConnectionListener() {
                    
                    @Override
                    public void reconnectionSuccessful() {

                    }
                    
                    @Override
                    public void reconnectionFailed(Exception arg0) {

                    }
                    
                    @Override
                    public void reconnectingIn(int arg0) {

                    }
                    
                    @Override
                    public void connectionClosedOnError(Exception arg0) {

                    }
                    
                    @Override
                    public void connectionClosed() {

                    }
                    
                    @Override
                    public void connected(XMPPConnection arg0) {
                        
                        try {
//                            mXMPPTCPConnection.setPacketReplyTimeout(30*1000);
                            mXMPPTCPConnection.login();
                            OfflineMessageManager offlineManager = new OfflineMessageManager(
                                    MainActivity.mXMPPTCPConnection);
//                            offlineManager.supportsFlexibleRetrieval();
                            Log.i("离线消息数量: ", "" + offlineManager.getMessageCount());
                            List messageList = offlineManager.getMessages();
                            
                            for(org.jivesoftware.smack.packet.Message message:messageList){
                                Log.i("收到离线消息", "Received from 【" + message.getFrom()
                                + "】 message: " + message.getBody());
                                if (message != null && message.getBody() != null
                                        && !message.getBody().equals("null")) {
                                    offlineMsgList.add(message.getFrom().split("/")[0]+"###"
                                        +message.getBody());
                                }
                            }

                            offlineManager.deleteMessages();// 通知服务器删除离线消息
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                    }
                    
                    @Override
                    public void authenticated(XMPPConnection arg0, boolean arg1) {
                        Log.d("jinru", "jinru authenticated offline message");
                    }
                });
                try {
                    mXMPPTCPConnection.connect();
                } catch (SmackException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (XMPPException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

群离线消息,貌似Smack不提供获取群离线消息需要插件。

10、监听收到的消息(无论是群还是个人,不知道为什么我使用ChatManagerListener或者ChatMessageListener都不能收到消息),我干脆监听Packet了:

PacketTypeFilter packetTypeFilter=new PacketTypeFilter(Message.class);
mXMPPTCPConnection.addPacketListener(new PacketListener() {
            
            @Override
            public void processPacket(Stanza stanza) throws NotConnectedException {
                Message message=(Message)stanza;
            }
        }, packetTypeFilter);

11、发送群消息:

MultiUserChat multiUserChat=multiUserChatManager.getMultiUserChat(user)

Message message=multiUserChat.createMessage();
message.setBody(editText.getText().toString());
multiUserChat.sendMessage(message);

12、发送文件:

初始化:
        ServiceDiscoveryManager sdManager= ServiceDiscoveryManager
                .getInstanceFor(mXMPPTCPConnection);
        sdManager.addFeature("http://jabber.org/protocol/disco#info");
        sdManager.addFeature("jabber:iq:privacy");
        fileTransferManager = FileTransferManager.getInstanceFor(MainActivity.mXMPPTCPConnection);

        //监听好友发文件给你

        fileTransferManager.addFileTransferListener(new FileTransferListener() {
            
            @Override
            public void fileTransferRequest(FileTransferRequest request) {
                File file=new File(file_save_path);
                IncomingFileTransfer incomingFileTransfer=request.accept();
                try {
                    incomingFileTransfer.recieveFile(file);
                } catch (SmackException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });


发送文件:

new SendFileTask().execute("/sdcard/123456.jpg",userId);//图片路径,和文件发送给谁的user


public class SendFileTask extends AsyncTask{
        private final static String TAG="SendFileTask";
        @Override
        protected Integer doInBackground(String... params) {
               if  (params.length < 2) {
                   Log.d(TAG,"parameter invalide");
                   return Integer.valueOf(-1);
              }
               String img_path=params[0];
               String toId=params[1]+"/Spark";  //resource必须要加,不加报不是一个完整的userId错误。
               Log.d(TAG,"img_path:"+img_path+","+toId);
            
               if(fileTransferManager==null)
               {
                   Log.d(TAG, "get FileTransferManager failed");
                   return -1 ;
               }
               File filetosend= new File(img_path);
               if(filetosend.exists()==false)
               {
                   Log.d(TAG,"file:"+img_path+" is  not exist");
                   return -1;
               }
               Log.d(TAG,"to user:"+toId);
               OutgoingFileTransfer oft=fileTransferManager.createOutgoingFileTransfer(toId);//创建一个输出文件传输对象
               try {
                   oft.sendFile(filetosend, "recv img");
                  while(!oft.isDone())
                   {
                       if (oft.getStatus().equals(FileTransfer.Status.error))
                       {
                           Log.e(TAG, "send failed");
                       }
                       else
                       {
                           Log.i(TAG, "status:" + oft.getStatus() + "|progress:" +  oft.getProgress());//打印进度
                       }
                       try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                   }
            } catch (SmackException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
    
              return 0;
              
        }
    }


13、创建群聊:

private void createGroupChat(){
        try {
            MultiUserChat multiUserChat=multiUserChatManager
                    .getMultiUserChat("自定义的群ID");
            multiUserChat.create("群聊的名字");
            
            // 获得聊天室的配置表单  
            Form form = multiUserChat.getConfigurationForm();  
            // 根据原始表单创建一个要提交的新表单。  
            Form submitForm = form.createAnswerForm();  
            // 向要提交的表单添加默认答复  
//            for (List fields = form.getFields(); fields.hasNext();) {  
//                FormField field = (FormField) fields.next();  
//                if (!FormField.TYPE_HIDDEN.equals(field.getType())  
//                        && field.getVariable() != null) {  
//                    // 设置默认值作为答复  
//                    submitForm.setDefaultAnswer(field.getVariable());  
//                }  
//            }  
            for(FormField formField:form.getFields()){
                if(!formField.getType().equals(Type.hidden)&&formField.getVariable()!=null){
                    submitForm.setDefaultAnswer(formField.getVariable());
                }
            }
            // 设置聊天室的新拥有者  
//             List owners = new ArrayList(); 
//             owners.add("liaonaibo2\\40slook.cc");  
//             owners.add("liaonaibo1\\40slook.cc");  
//             submitForm.setAnswer("muc#roomconfig_roomowners", owners);  
            // 设置聊天室是持久聊天室,即将要被保存下来  
            submitForm.setAnswer("muc#roomconfig_persistentroom", true);  
            // 房间仅对成员开放  
            submitForm.setAnswer("muc#roomconfig_membersonly", false);  
            // 允许占有者邀请其他人  
            submitForm.setAnswer("muc#roomconfig_allowinvites", true);  
            // 能够发现占有者真实 JID 的角色  
            // submitForm.setAnswer("muc#roomconfig_whois", "anyone");  
            // 登录房间对话  
            submitForm.setAnswer("muc#roomconfig_enablelogging", true);  
            // 仅允许注册的昵称登录  
            submitForm.setAnswer("x-muc#roomconfig_reservednick", true);  
            // 允许使用者修改昵称  
            submitForm.setAnswer("x-muc#roomconfig_canchangenick", false);  
            // 允许用户注册房间  
            submitForm.setAnswer("x-muc#roomconfig_registration", false);  
            // 发送已完成的表单(有默认值)到服务器来配置聊天室  
            multiUserChat.sendConfigurationForm(submitForm);
            multiUserChat.join("用户加入群聊的昵称");
            multiUserChat.grantOwnership("用户的ID(完整登录名)");
            
            //邀请用户进入群聊
            multiUserChat.invite("用户ID", "邀请语");
        } catch (NoResponseException e) {
            e.printStackTrace();
        } catch (XMPPErrorException e) {
            e.printStackTrace();
        } catch (SmackException e) {
            e.printStackTrace();
        }
    }


14、监听加入群聊的邀请:

multiUserChatManager.addInvitationListener(new InvitationListener() {
            
            @Override
            public void invitationReceived(XMPPConnection conn, MultiUserChat multiUserChat,
                    String room, String inviter, String reason,,Message message) {
            }
        });

你可能感兴趣的:(Android学习)