XMPP-Android基于openfire+asmack

来源:互联网 发布:java算法书籍推荐 知乎 编辑:程序博客网 时间:2024/06/14 17:47

一、搭建openfire

mysql下载地址:http://pan.baidu.com/s/1qY2a6BU

openfire下载地址:http://download.csdn.net/detail/xsz_1025/9672665

1、安装配置mysql

如果下载的mysql是.exe格式,则无脑安装,以下着重介绍解压版mysql的配置

  • 将压缩包解压到想要安装的位置
  • 配置环境变量,在path后追加 mysql安装目录\bin
  • 修改配置文件,在mysql安装目录下的my-default.ini文件,打开找到如下位置
  • 以管理员身份运行cmd
  • 进入到bin目录(无论是否配置环境变量都需在bin目录下执行)
  • 输入命令 mysqld -install,我的已经导入过所以出现如下提示,如果没有导入过则成功后会提示Service successfully installed

  • 此时mysql已经配置完成,可以在任意目录启动mysql服务,命令 net start mysql
  • 登录mysql,首次登录没有密码,输入mysql -u root -p后出现如下所示

  • 直接回车即可


  • 创建数据库(注意为了让数据库支持中文,在创建时应选择utf8编码,如果此数据库是用于后续openfire,不是utf8的话会导致接收离线消息或其他中文信息时乱码)

2、安装配置openfire

  • 下载openfire安装文件,运行.exe
  • 当出现如下界面时,点击Launch Admin

  • 选择简体中文,点击继续
  • 配置域,点击继续。域为主机IP,注意不要写成127.0.0.1
  • 选择标准数据库连接,点击继续
  • 数据库驱动选择Mysql
  • 数据库URL改为jdbc:mysql://127.0.0.1:3306/dbname?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=UTF8&charset=utf8&characterSetResults=UTF8(注意:127.0.0.1不要修改,dbname是你为openfire创建的数据库,此数据库创建时应选择UTF8编码)
  • 选择初始设置
  • 设置密码
  • 安装完成,可登录到控制台管理openfire

二、开发android客户端

网上大部分客户端都是可以运行的,虽然或多或少会有些问题。但是目前网上大多demo将功能与界面混在一起,且demo比较复杂,不利于理解移植。本文着重介绍asmack的各功能实现,更倾向于API的使用。如:如何建立连接、登录、注册、消息收发等。

下载asmack.jar包:http://download.csdn.net/detail/xsz_1025/9672818

1、建立连接

注意:需要网络权限

/**连接工具*/public class XmppConnectionManager {private static XmppConnectionManager xmppConnectionManager;static {try {Class.forName("org.jivesoftware.smack.ReconnectionManager");} catch (Exception e) {e.printStackTrace();}}private XmppConnectionManager() {}public static XmppConnectionManager getInstance() {if (xmppConnectionManager == null) {xmppConnectionManager = new XmppConnectionManager();}return xmppConnectionManager;}public XMPPConnection init() {// 设置debug模式,true开启 false关闭Connection.DEBUG_ENABLED = true;// 配置providerconfigureProvider(ProviderManager.getInstance());ConnectionConfiguration connectionConfig = new ConnectionConfiguration("192.168.15.85", 5222);// 不使用SASL验证,设置为falseconnectionConfig.setSASLAuthenticationEnabled(false);connectionConfig.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);// 允许自动连接connectionConfig.setReconnectionAllowed(true);// 允许登陆成功后更新在线状态connectionConfig.setSendPresence(true);// 收到好友邀请后manual表示需要经过同意,accept_all表示不经同意自动为好友Roster.setDefaultSubscriptionMode(Roster.SubscriptionMode.accept_all);XMPPConnection connection = new XMPPConnection(connectionConfig);return connection;}public void configureProvider(ProviderManager pm) {pm.addIQProvider("query", "jabber:iq:private", new PrivateDataManager.PrivateDataIQProvider());// Timetry {pm.addIQProvider("query", "jabber:iq:time", Class.forName("org.jivesoftware.smackx.packet.Time"));} catch (Exception e) {e.printStackTrace();}// Roster Exchangepm.addExtensionProvider("x", "jabber:x:roster", new RosterExchangeProvider());// Message Eventspm.addExtensionProvider("x", "jabber:x:event", new MessageEventProvider());// Chat Statepm.addExtensionProvider("active", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());pm.addExtensionProvider("composing", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());pm.addExtensionProvider("paused", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());pm.addExtensionProvider("inactive", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());pm.addExtensionProvider("gone", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());// XHTMLpm.addExtensionProvider("html", "http://jabber.org/protocol/xhtml-im", new XHTMLExtensionProvider());// Group Chat Invitationspm.addExtensionProvider("x", "jabber:x:conference", new GroupChatInvitation.Provider());// Service Discovery # Items //解析房间列表pm.addIQProvider("query", "http://jabber.org/protocol/disco#items", new DiscoverItemsProvider());// Service Discovery # Info //某一个房间的信息pm.addIQProvider("query", "http://jabber.org/protocol/disco#info", new DiscoverInfoProvider());// Data Formspm.addExtensionProvider("x", "jabber:x:data", new DataFormProvider());// MUC Userpm.addExtensionProvider("x", "http://jabber.org/protocol/muc#user", new MUCUserProvider());// MUC Adminpm.addIQProvider("query", "http://jabber.org/protocol/muc#admin", new MUCAdminProvider());// MUC Ownerpm.addIQProvider("query", "http://jabber.org/protocol/muc#owner", new MUCOwnerProvider());// Delayed Deliverypm.addExtensionProvider("x", "jabber:x:delay", new DelayInformationProvider());// Versiontry {pm.addIQProvider("query", "jabber:iq:version", Class.forName("org.jivesoftware.smackx.packet.Version"));} catch (ClassNotFoundException e) {e.printStackTrace();}// VCardpm.addIQProvider("vCard", "vcard-temp", new VCardProvider());// Offline Message Requestspm.addIQProvider("offline", "http://jabber.org/protocol/offline", new OfflineMessageRequest.Provider());// Offline Message Indicatorpm.addExtensionProvider("offline", "http://jabber.org/protocol/offline", new OfflineMessageInfo.Provider());// Last Activitypm.addIQProvider("query", "jabber:iq:last", new LastActivity.Provider());// User Searchpm.addIQProvider("query", "jabber:iq:search", new UserSearch.Provider());// SharedGroupsInfopm.addIQProvider("sharedgroup", "http://www.jivesoftware.org/protocol/sharedgroup", new SharedGroupsInfo.Provider());// JEP-33: Extended Stanza Addressingpm.addExtensionProvider("addresses", "http://jabber.org/protocol/address", new MultipleAddressesProvider());pm.addIQProvider("si", "http://jabber.org/protocol/si", new StreamInitiationProvider());pm.addIQProvider("query", "http://jabber.org/protocol/bytestreams", new BytestreamsProvider());pm.addIQProvider("query", "jabber:iq:privacy", new PrivacyProvider());pm.addIQProvider("command", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider());pm.addExtensionProvider("malformed-action", "http://jabber.org/protocol/commands",new AdHocCommandDataProvider.MalformedActionError());pm.addExtensionProvider("bad-locale", "http://jabber.org/protocol/commands",new AdHocCommandDataProvider.BadLocaleError());pm.addExtensionProvider("bad-payload", "http://jabber.org/protocol/commands",new AdHocCommandDataProvider.BadPayloadError());pm.addExtensionProvider("bad-sessionid", "http://jabber.org/protocol/commands",new AdHocCommandDataProvider.BadSessionIDError());pm.addExtensionProvider("session-expired", "http://jabber.org/protocol/commands",new AdHocCommandDataProvider.SessionExpiredError());}}

2、连接&登录

// 连接、登录、断开连接public class XMPPApplication extends Application {    public static final String TAG = "XMPPApplication";    public static XMPPConnection mXmppConnection;    @Override    public void onCreate() {        // 程序创建的时候执行        super.onCreate();        // 网络操作放到线程中执行        new Thread(new Runnable() {                        @Override            public void run() {                // 建立连接                mXmppConnection = XmppConnectionManager.getInstance().init();                try {                    // 连接                    mXmppConnection.connect();                    // 登录                    mXmppConnection.login("xsz", "123456");                    // 判断是是否登录成功                    if (mXmppConnection.isAuthenticated()) {                        // 成功                        Log.d(TAG, "登录成功");                    } else {                        // 失败                        Log.d(TAG, "登录失败");                    }                } catch (XMPPException e) {                    Log.d(TAG, "登录异常");                    e.printStackTrace();                }            }        }).start();    }    @Override    public void onTerminate() {        // 程序终止的时候执行        super.onTerminate();        // 断开连接        if (mXmppConnection != null) {            mXmppConnection.disconnect();            mXmppConnection = null;        }    }}

3、发送消息(文本类型)

public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);findViewById(R.id.sendMsg).setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {ChatManager chatmanager = XMPPApplication.mXmppConnection.getChatManager();Chat chat = chatmanager.createChat("test1@192.168.15.85", null);if (chat != null) {try {chat.sendMessage("发送文本消息");Log.e(XMPPApplication.TAG, "发送成功");} catch (XMPPException e) {e.printStackTrace();}}}});}}

3、接收消息

实现接收消息监听

public class MyMessageListener implements MessageListener {@Overridepublic void processMessage(Chat chat, Message msg) {String message = msg.getBody();String from = msg.getFrom();String name = msg.getType().name();Log.d(XMPPApplication.TAG, "message:" + message + "\nfrom:" + from + "\nname:" + name);}}

登陆成功后注册接收消息监听

if (mXmppConnection.isAuthenticated()) {// 成功Log.d(TAG, "登录成功");ChatManager chatmanager = mXmppConnection.getChatManager();chatmanager.addChatListener(new ChatManagerListener() {@Overridepublic void chatCreated(Chat arg0, boolean arg1) {// 添加新消息接收监听arg0.addMessageListener(new MyMessageListener());}});} else {// 失败Log.d(TAG, "登录失败");}

消息发送和接收这块只写了文本内容的,还有图片、音频或者群聊等。群聊的消息type.name为groupchat。图片、音频等内容的发送可以通过Message来实现。

Message message = new Message();message.setProperty("image", "图片的base64");message.setBody("图片name.后缀类型");chat.sendMessage(message);

4、断开重连

XMPP断开重连,自定义类实现ConnectionListener

public class MyConnectionListener implements ConnectionListener {@Overridepublic void connectionClosed() {Log.d(XMPPApplication.TAG, "MyConnectionListener-->连接关闭");}@Overridepublic void connectionClosedOnError(Exception e) {if (e.getMessage().equals("stream:error (conflict)")) {Log.d(XMPPApplication.TAG, "MyConnectionListener-->您的账号在异地登录");} else {Log.d(XMPPApplication.TAG, "MyConnectionListener-->" + e.getMessage());}}@Overridepublic void reconnectingIn(int arg0) {Log.d(XMPPApplication.TAG, "MyConnectionListener-->正在重连");}@Overridepublic void reconnectionFailed(Exception e) {Log.d(XMPPApplication.TAG, "MyConnectionListener-->重连失败-->" + e.getMessage());}@Overridepublic void reconnectionSuccessful() {Log.d(XMPPApplication.TAG, "MyConnectionListener-->重连成功");}}

登录成功后添加自定义的连接监听

// 添加连接监听MyConnectionListener connectionListener = new MyConnectionListener();XMPPApplication.mXmppConnection.addConnectionListener(connectionListener);

当客户端异常段开时,会自动重连。

5、注册

<pre name="code" class="java"><pre name="code" class="java">new Thread(new Runnable() {@Overridepublic void run() {// 参数2:用户名 参数3:密码int result = register(XMPPApplication.mXmppConnection, "test3", "123456");Log.d(XMPPApplication.TAG, "注册返回结果:" + result);}}).start();

6、搜索好友

    /** * 搜索好友 *  * @param userName 好友昵称(模糊匹配) * @return * @throws XMPPException */private void searchUsers(XMPPConnection mXMPPConnection, String userName) {try {UserSearchManager search = new UserSearchManager(mXMPPConnection);Form searchForm = search.getSearchForm("search." + mXMPPConnection.getServiceName());Form answerForm = searchForm.createAnswerForm();answerForm.setAnswer("Username", true);answerForm.setAnswer("search", userName);ReportedData data = search.getSearchResults(answerForm, "search." + mXMPPConnection.getServiceName());Iterator<Row> it = data.getRows();Row row = null;while (it.hasNext()) {row = it.next();String username = row.getValues("Username").next().toString();Log.d(XMPPApplication.TAG, "好友:" + username);}} catch (Exception e) {e.printStackTrace();}}

7、添加好友

当好友状态改变时收到PacketListener监听,实现此监听可以获取到好友相关信息,好友申请,状态改变及上下线信息等。

public class PresencePacketListener implements PacketListener {@Overridepublic void processPacket(Packet packet) {if (packet instanceof Presence) {Presence presence = (Presence) packet;final String from = presence.getFrom();// 发送方String to = presence.getTo();// 接收方Log.d(XMPPApplication.TAG, "PresencePacketListener--->from:" + from);Log.d(XMPPApplication.TAG, "PresencePacketListener--->to:" + to);if (presence.getType().equals(Presence.Type.subscribe)) {// 好友申请Log.d(XMPPApplication.TAG, "PresencePacketListener--->好友申请");} else if (presence.getType().equals(Presence.Type.subscribed)) {// 同意添加好友Log.d(XMPPApplication.TAG, "PresencePacketListener--->同意添加好友");} else if (presence.getType().equals(Presence.Type.unsubscribe)) {// 拒绝添加好友 和 删除好友Log.d(XMPPApplication.TAG, "PresencePacketListener--->拒绝添加好友");} else if (presence.getType().equals(Presence.Type.unsubscribed)) {// 同意拒绝好友Log.d(XMPPApplication.TAG, "PresencePacketListener--->同意拒绝好友");} else if (presence.getType().equals(Presence.Type.unavailable)) {// 好友下线 要更新好友列表,可以在这收到包后,发广播到指定页面 更新列表Log.d(XMPPApplication.TAG, "PresencePacketListener--->好友下线");Log.d(XMPPApplication.TAG, "PresencePacketListener--->好友状态:" + presence.getMode().name());} else if (presence.getType().equals(Presence.Type.available)) {// 好友上线Log.d(XMPPApplication.TAG, "PresencePacketListener--->好友上线");Log.d(XMPPApplication.TAG, "PresencePacketListener--->好友状态:" + presence.getMode().name());} else {Log.e(XMPPApplication.TAG, "PresencePacketListener--->error");}}};}

登陆成功后添加此监听

// 添加好友状态、好友申请监听packetListener = new PresencePacketListener();PacketFilter filter = new AndFilter(new PacketTypeFilter(Presence.class));XMPPApplication.mXmppConnection.addPacketListener(packetListener, filter);

当两个装好互相添加好友时,添加好友操作即可完成

例如xsz添加test2为好友,执行如下代码

<pre name="code" class="java">Roster roster = XMPPApplication.mXmppConnection.getRoster();// 创建分组try {roster.createGroup("分组1");} catch (Exception e) {Log.d(XMPPApplication.TAG, "分组1已存在");}try {// 添加好友roster.createEntry("test2@192.168.15.85", "test2", new String[] { "分组1" });} catch (XMPPException e) {e.printStackTrace();}

此时test2会执行到PresencePacketListener的Log.d(XMPPApplication.TAG, "PresencePacketListener--->好友申请");,可根据实际场景进行开发,比如弹出好友请求的对话框,或者在消息列表增加一条好友请求的消息。

当test2执行如下代码时,好友添加即可完成

Roster roster = XMPPApplication.mXmppConnection.getRoster();// 创建分组try {roster.createGroup("我的分组");} catch (Exception e) {Log.d(XMPPApplication.TAG, "我的分组已存在");}try {// 添加好友roster.createEntry("xsz@192.168.15.85", "xsz", new String[] { "我的分组" });} catch (XMPPException e) {e.printStackTrace();}
此时xsz会执行到PresencePacketListener的Log.d(XMPPApplication.TAG, "PresencePacketListener--->同意添加好友");

8、删除好友

// 参数为要删除的好友RosterEntry entry = XMPPApplication.mXmppConnection.getRoster().getEntry("test2@192.168.15.85");try {XMPPApplication.mXmppConnection.getRoster().removeEntry(entry);} catch (XMPPException e) {e.printStackTrace();}

9、获取好友列表

try {Roster roster = XMPPApplication.mXmppConnection.getRoster();Collection<RosterGroup> groups = roster.getGroups();for (RosterGroup group : groups) {Log.d(XMPPApplication.TAG, "组:" + group.getName());Collection<RosterEntry> entries = group.getEntries();for (RosterEntry entry : entries) {if (entry.getType().name().equals("both")) {Presence presence = roster.getPresence(entry.getUser());Log.d(XMPPApplication.TAG, "好友:" + entry.getUser());Log.d(XMPPApplication.TAG, "在线:" + presence.isAvailable());if (presence.getMode() != null) {Log.d(XMPPApplication.TAG, "状态:" + presence.getMode().name());} else {Log.d(XMPPApplication.TAG, "状态:未设置");}}}}} catch (Exception e) {e.printStackTrace();}

10、获取个人信息//好友信息

new Thread(new Runnable() {@Overridepublic void run() {VCard card = new VCard();try {// 获取个人信息card.load(XMPPApplication.mXmppConnection);// 可通过Field获取任意协商好的属性String nickname = card.getNickName();String emailHome = card.getEmailHome();String emailWork = card.getEmailWork();String sign = card.getField("sign");String sex = card.getField("sex");String mobile = card.getField("mobile");String adr1 = card.getAddressFieldHome("test1");String adr2 = card.getAddressFieldHome("test2");String adr3 = card.getAddressFieldWork("test1");Log.d(XMPPApplication.TAG, "nickname:" + nickname);Log.d(XMPPApplication.TAG, "emailHome:" + emailHome);Log.d(XMPPApplication.TAG, "emailWork:" + emailWork);Log.d(XMPPApplication.TAG, "sign:" + sign);Log.d(XMPPApplication.TAG, "sex:" + sex);Log.d(XMPPApplication.TAG, "mobile:" + mobile);Log.d(XMPPApplication.TAG, "adr1:" + adr1);Log.d(XMPPApplication.TAG, "adr2:" + adr2);Log.d(XMPPApplication.TAG, "adr3:" + adr3);} catch (XMPPException e) {Log.d(XMPPApplication.TAG, "获取个人信息失败");e.printStackTrace();}VCard cardFriend = new VCard();try {// 获取执行好友信息        cardFriend.load(XMPPApplication.mXmppConnection, "test1@192.168.15.85");// 可获取任意协商好的属性String nickname = cardFriend.getNickName();String emailHome = cardFriend.getEmailHome();String emailWork = cardFriend.getEmailWork();String sign = cardFriend.getField("sign");String sex = cardFriend.getField("sex");String mobile = cardFriend.getField("mobile");String adr1 = cardFriend.getAddressFieldHome("test1");String adr2 = cardFriend.getAddressFieldHome("test2");String adr3 = cardFriend.getAddressFieldWork("test1");Log.d(XMPPApplication.TAG, "nickname:" + nickname);        Log.d(XMPPApplication.TAG, "emailHome:" + emailHome);        Log.d(XMPPApplication.TAG, "emailWork:" + emailWork);Log.d(XMPPApplication.TAG, "sign:" + sign);Log.d(XMPPApplication.TAG, "sex:" + sex);Log.d(XMPPApplication.TAG, "mobile:" + mobile);Log.d(XMPPApplication.TAG, "adr1:" + adr1);Log.d(XMPPApplication.TAG, "adr2:" + adr2);Log.d(XMPPApplication.TAG, "adr3:" + adr3);} catch (XMPPException e) {Log.d(XMPPApplication.TAG, "获取好友信息失败");e.printStackTrace();}}}).start();

11、修改个人信息

new Thread(new Runnable() {@Overridepublic void run() {        VCard card = new VCard();// 设置昵称card.setNickName("测试下中文的");// 设置头像card.setAvatar("AB".getBytes());// 设置地址card.setAddressFieldHome("test1", "zzzzz");card.setAddressFieldHome("test2", "yyyyy");card.setAddressFieldWork("test1", "zzzzzz");// 设置邮箱card.setEmailHome("home@163.com");card.setEmailWork("work@163.com");// 设置自定义字段card.setField("sign", "使用自定义字段设置一个签名");card.setField("sex", "男");card.setField("mobile", "13200000001");try {card.save(XMPPApplication.mXmppConnection);} catch (XMPPException e) {e.printStackTrace();}}}).start();

12、修改在线状态

        /** * 修改用户状态 */private void setPresence(XMPPConnection con, int code) {if (con == null)return;Presence presence = null;switch (code) {case 0:// 在线presence = new Presence(Presence.Type.available);break;case 1:// Q我吧presence = new Presence(Presence.Type.available);presence.setMode(Presence.Mode.chat);break;case 2:// 隐身Roster roster = con.getRoster();Collection<RosterEntry> entries = roster.getEntries();for (RosterEntry entry : entries) {presence = new Presence(Presence.Type.unavailable);presence.setPacketID(Packet.ID_NOT_AVAILABLE);presence.setFrom(con.getUser());presence.setTo(entry.getUser());}// 向同一用户的其他客户端发送隐身状态presence = new Presence(Presence.Type.unavailable);presence.setPacketID(Packet.ID_NOT_AVAILABLE);presence.setFrom(con.getUser());presence.setTo(StringUtils.parseBareAddress(con.getUser()));break;case 3:// 忙碌presence = new Presence(Presence.Type.available);presence.setMode(Presence.Mode.dnd);break;case 4:// 离开presence = new Presence(Presence.Type.available);presence.setMode(Presence.Mode.away);break;case 5:// 离线presence = new Presence(Presence.Type.unavailable);break;default:break;}if (presence != null) {con.sendPacket(presence);}}

13、退出

if (XMPPApplication.mXmppConnection != null && packetListener != null) {XMPPApplication.mXmppConnection.removePacketListener(packetListener);}if (XMPPApplication.mXmppConnection != null && connectionListener != null) {XMPPApplication.mXmppConnection.removeConnectionListener(connectionListener);}if (XMPPApplication.mXmppConnection != null) {XMPPApplication.mXmppConnection.disconnect();XMPPApplication.mXmppConnection = null;}

14、创建群聊

        /** * 创建房间 *  * @param roomName 房间名称 * @param password 密码(可以为空) */private MultiUserChat createRoom(String roomName, String password) {if (XMPPApplication.mXmppConnection == null)return null;MultiUserChat muc;try {muc = new MultiUserChat(XMPPApplication.mXmppConnection, roomName + "@conference." + XmppConnectionManager.IP);// 为每个房间创建监听muc.addMessageListener(new MyPacketListener());// 创建聊天室muc.create(roomName);// 获得聊天室的配置表单Form form = muc.getConfigurationForm();// 根据原始表单创建一个要提交的新表单。Form submitForm = form.createAnswerForm();// 向要提交的表单添加默认答复for (Iterator<FormField> fields = form.getFields(); fields.hasNext();) {FormField field = (FormField) fields.next();if (!FormField.TYPE_HIDDEN.equals(field.getType()) && field.getVariable() != null) {// 设置默认值作为答复submitForm.setDefaultAnswer(field.getVariable());}}// 设置聊天室的新拥有者List<String> owners = new ArrayList<String>();owners.add(XMPPApplication.mXmppConnection.getUser());// 用户JIDsubmitForm.setAnswer("muc#roomconfig_roomowners", owners);// 设置聊天室是持久聊天室,即将要被保存下来submitForm.setAnswer("muc#roomconfig_persistentroom", true);// 房间仅对成员开放submitForm.setAnswer("muc#roomconfig_membersonly", false);// 允许占有者邀请其他人submitForm.setAnswer("muc#roomconfig_allowinvites", true);if (!password.equals("")) {// 进入是否需要密码submitForm.setAnswer("muc#roomconfig_passwordprotectedroom", true);// 设置进入密码submitForm.setAnswer("muc#roomconfig_roomsecret", password);}// 能够发现占有者真实 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);// 发送已完成的表单(有默认值)到服务器来配置聊天室muc.sendConfigurationForm(submitForm);// 创建会议室成功后应该在本地或服务器(自己的服务器,非openfire)存储房间信息,因为asmack无法获取聊天室列表Editor editor = XMPPApplication.preferences.edit();String roomstr = XMPPApplication.preferences.getString(XMPPApplication.roomName, "");if (roomstr.equals("")) {roomstr = roomName;} else {roomstr = roomstr + "," + roomName;}editor.putString(XMPPApplication.roomName, roomstr);editor.commit();XMPPApplication.mRoomList.put(XMPPApplication.ROOM_NAME, muc);return muc;} catch (XMPPException e) {e.printStackTrace();return null;}}

15、邀请好友

// demo中在创建房间或者加入房间时,将MultiUserChat对象将如到了XMPPApplication.mRoomList中,此处只需要取出该对象调用invite方法即可XMPPApplication.mRoomList.get("房间名称").invite("好友jid","房间名称");

16、加入群聊

        /** * 加入会议室 *  * @param user 昵称 * @param roomsName 会议室名 * @param password 会议室密码 */public static MultiUserChat joinMultiUserChat(String user, String roomName, String password) {if (XMPPApplication.mXmppConnection == null)return null;MultiUserChat muc;try {muc = new MultiUserChat(XMPPApplication.mXmppConnection, roomName + "@conference." + XmppConnectionManager.IP);// 为每个房间创建监听muc.addMessageListener(new MyPacketListener());// 使用XMPPConnection创建一个MultiUserChat窗口// 聊天室服务将会决定要接受的历史记录数量DiscussionHistory history = new DiscussionHistory();history.setMaxChars(0);// history.setSince(new Date());// 用户加入聊天室muc.join(user, password, history, SmackConfiguration.getPacketReplyTimeout());Log.i(XMPPApplication.TAG, user + "-->加入会议室成功【" + roomName + "】");// 加入会议室成功后应该在本地或服务器(自己的服务器,非openfire)存储房间信息,因为asmack无法获取聊天室列表Editor editor = XMPPApplication.preferences.edit();String roomstr = XMPPApplication.preferences.getString(XMPPApplication.roomName, "");if (roomstr.equals("")) {roomstr = roomName;} else {roomstr = roomstr + "," + roomName;}editor.putString(XMPPApplication.roomName, roomstr);editor.commit();XMPPApplication.mRoomList.put(XMPPApplication.ROOM_NAME, muc);return muc;} catch (XMPPException e) {e.printStackTrace();Log.e(XMPPApplication.TAG, user + "-->加入会议室失败【" + roomName + "】");return null;}}

注意:XMPP在断开连接后相关房间信息丢失,所以在登录成功后需要重新加入房间,从本地(或服务器)取出房间列表并加入

// XMPP在断开后需要重新加入房间,获取当前用户所有已加入过的房间,重新加入if (null != XMPPApplication.mRoomList) {XMPPApplication.mRoomList.clear();} else {XMPPApplication.mRoomList = new HashMap<String, MultiUserChat>();}String roomstr = XMPPApplication.preferences.getString(XMPPApplication.roomName, "");if (!roomstr.equals("")) {String[] rooms = roomstr.split(",");for (String room : rooms) {if (!room.equals(""))MainActivity.joinMultiUserChat(XMPPApplication.ACCOUNT, room, "");}}

17、发送群聊

XMPPApplication.mRoomList.get(XMPPApplication.ROOM_NAME).sendMessage("测试一下中文的消息");

18、退出群聊

XMPPApplication.mRoomList.get(XMPPApplication.ROOM_NAME).leave();

19、获取群聊列表

asmack不支持获取房间列表,它提供的MultiUserChat.getJoinedRooms(arg0, arg1)方法存在bug,一直返回null,据说smack可以获取(未实验)

如果采用asmack可以采用将用户的房间信息存储到本地或服务器(建议存储到服务器,否则当客户端清除数据后,房间信息无法获取)

20、获取群聊好友列表

同获取聊天列表

三、异常处理

1、报java.security.KeyStoreException: java.security.NoSuchAlgorithmException: KeyStore jks implementation not found异常

此异常出现原因为SASL验证错误,找到XMPP连接的地方,将验证SASL设置为false即可。

2、离线消息中文乱码

搭建openfire时有几点注意事项:

  • 创建数据库时选择UTF8,在cmd中输入如下内容 create database name character set utf8;(name为你要创建的数据库的名字) 
  • 连接mysql数据库时,在url后加上useUnicode=true&characterEncoding=UTF8&charset=utf8&characterSetResults=UTF8

离线消息中文乱码多是由于数据库编码格式或者openfire连接数据库所使用的编码导致,如果按照上述搭建openfire的方式进行搭建,一般不会出现这种问题,如果出现检查是否按照上述步骤进行配置,如果步骤错误或者未发现原因,建议重新搭建

如何重新搭建?

  • 关闭mysql:命令 net stop mysql


  • 退出openfire
  • 在openfire的安装目录\conf找到openfire.xml
  • 打开文件,删除  <setup>true</setup>
  • 重启mysql:命令 net start mysql

  • 启动openfire,点击Launch Admin重新配置

源码下载:http://download.csdn.net/detail/xsz_1025/9682132



0 0