xmpp资源:http://blog.csdn.net/jerry0827/article/category/1406016
http://nodex.iteye.com/blog/2008036
tigase相关:
1、下载tigase server代码:git clone https://repository.tigase.org/git/tigase-server.git
2、 编译tigase server代码:mvn -Pdist -f modules/master/pom.xml clean install
3、日志跟踪:tail -f logs/tigase-console.log
1、创建数据库:scripts/db-create-mysql.sh tigase_user tigase_passwd tigasedb root 111111 localhost
拷贝脚本:由于版本的关系,脚本文件路径发生了变化,需要手工拷贝:cp src/main/groovy/tigase/admin/* scripts/admin/
设置初始化文件:文件路径etc/init.properties,内容如下:
#config-type=--gen-config-def
#--admins=admin@$HOST_NAME
#--virt-hosts = $HOST_NAME
#--debug=server
config-type=--gen-config-def
--admins=admin@localhost
--virt-hosts = localhost
--debug=server
--monitoring=jmx:9050,http:9080,snmp:9060
--user-db=mysql
--user-db-uri=jdbc:mysql://127.0.0.1:3306/tigasedb?user=root&password=111111&useUnicode=true&characterEncoding=UTF-8
#开启MUC群组
--comp-name-1 = muc
--comp-class-1 = tigase.muc.MUCComponent
#不添加该代码,以默认配置创建的房间会被锁住,其他人无法加入
muc/muc-lock-new-room[B]=false
#配置一个使用MUC组建的二级域名
--external= muc.localhost:muc-pass
#--comp-name-2 = pubsub
#--comp-class-2 = tigase.pubsub.PubSubComponent
etc/tigase.conf
#osgiEnabled=(true|false)
#osgiEnabled=false
OSGI=${osgiEnabled}
ENC="-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8"
DRV="-Djdbc.drivers=com.mysql.jdbc.Driver:org.postgresql.Driver:org.apache.derby.jdbc.EmbeddedDriver"
#GC="-XX:+UseBiasedLocking -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:ParallelCMSThreads=2 -XX:-ReduceInitialCardMarks"
#EX="-XX:+OptimizeStringConcat -XX:+DoEscapeAnalysis -XX:+UseNUMA"
#JAVA_HOME="${JDKPath}"
CLASSPATH=""
JAVA_OPTIONS="${GC} ${EX} ${ENC} ${DRV} -server -Xms100M -Xmx200M -XX:PermSize=32m -XX:MaxPermSize=256m -XX:MaxDirectMemorySize=128m "
TIGASE_CONFIG="etc/tigase.xml"
TIGASE_OPTIONS=" --property-file etc/init.properties "
2、启动tigase服务:./scripts/tigase.sh start etc/tigase.conf
终止tigase服务:./scripts/tigase.sh stop etc/tigase.conf
3、安装tclmt: git clone https://repository.tigase.org/git/tclmt.git,编译mvn clean install
tclmt's distribution file: https://projects.tigase.org/projects/tclmt/files
tigase相关资料:https://chutianxing.wordpress.com/tag/tigase/page/2/
数据表介绍:
http://www.tigase.org/content/tigase-db-schema-explained
使用tclmt管理tigase server,
1、登录bin/tclmt.sh -i,输入用户名和密码:admin@localhost 123456
2、https://stackoverflow.com/questions/8670234/scaling-tigase-xmpp-server-on-amazon-ec2/8672592#8672592
xabber代码分析:
1、添加Account:AccountAdd.java 的onclick里响应
2、连接线程ConnectionThread,客户端处理数据包的逻辑为该类的processPacket方法,
@Override
public void processPacket(final Packet packet) {
Application.getInstance().runOnUiThread(new Runnable() {
@Override
public void run() {
ConnectionManager.getInstance().processPacket(
ConnectionThread.this, packet);
}
});
}
最终会调用ConnectionManager中的包处理方法
3、如果需要监听某个特殊类型的数据包,比如在线状态、好友信息、MUC信息等,需要定义一个实现了OnPacketListener接口的manager,并在application中注册该manager,Application.java
public void addManager(Object manager) {
registeredManagers.add(manager);
}
4、多个Manager的初始化,包括(AccountManager、ReconnectionManager、ScreenManager、ConnectionManager等等),初始化的流程如下:
TypedArray managerClasses = getResources().obtainTypedArray(
R.array.managers);
for (int index = 0; index < managerClasses.length(); index++)
if (isContactsSupported()
|| !contactManager
.contains(managerClasses.getString(index)))
try {
Class.forName(managerClasses.getString(index));
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
managerClasses.recycle();
用了反射生成对象,每个manager类都有一块static bolck进行初始化,包括将自己加入Application的manager。这些Manager的初始化时机是在XabberService启动完毕后调用Applicaiton中的onServiceStarted方法,
5、添加账户:AccountAdd.java,添加账户的逻辑:
String account;
try {
account = AccountManager.getInstance().addAccount(
userView.getText().toString(),
passwordView.getText().toString(), accountType,
syncableView.isChecked(),
storePasswordView.isChecked());
} catch (NetworkException e) {
Application.getInstance().onError(e);
return;
}
账户类型定义在AccountProtocol.java中,有xmpp、gtalk等
6、ContactList从ManagedListActivity派生出来,在ManagedListActivity的onCreate函数中会对ActivityManager进行初始化,如下:
protected void onCreate(Bundle savedInstanceState) {
ActivityManager.getInstance().onCreate(this);
super.onCreate(savedInstanceState);
}
在ActivityManager中会启动LoadActivity
if (application.isClosing() && !(activity instanceof LoadActivity)) {
activity.startActivity(LoadActivity.createIntent(activity));
activity.finish();
}
在LoadActivity中会启动xabberService,但是这个条件在app启动时是进不来的,
public void onResume(final Activity activity) {
if (LOG)
LogManager.i(activity, "onResume");
if (!application.isInitialized() && !(activity instanceof LoadActivity)) {
if (LOG)
LogManager.i(this, "Wait for loading");
activity.startActivity(LoadActivity.createIntent(activity));
}
if (onErrorListener != null)
application
.removeUIListener(OnErrorListener.class, onErrorListener);
onErrorListener = new OnErrorListener() {
@Override
public void onError(final int resourceId) {
Toast.makeText(activity, activity.getString(resourceId),
Toast.LENGTH_LONG).show();
}
};
application.addUIListener(OnErrorListener.class, onErrorListener);
}
app启动时会调用上面的onResume方法启动LoadActivity,这个方法在ActivityManager类中。
客户端流程:
1、主activity启动时需要启动XabberService,xabberservice只是显示一个通知栏
2、xabberservice启动后会回调Application.java中的onServiceStarted方法,
Application.getInstance().onServiceStarted();
在此回调中会调用Application的onInitialized方法,此处会调用所有的manager的onInitialized方法。服务器主机地址解析完毕后会调用
ConnectionThread的onReady方法进行连接xmpp server,连接成功后会调用connect方法。
3、为保证连接的有效,Application中有一个定时器会定时触发ReconnectionManager的onTimer接口。
4、xabber android使用了大量的监听器,以account add为例,在AccountManager类中有这样的方法:
private void addAccount(AccountItem accountItem) {
accountItems.put(accountItem.getAccount(), accountItem);
if (accountItem.isEnabled())
enabledAccounts.add(accountItem.getAccount());
for (OnAccountAddedListener listener : application
.getManagers(OnAccountAddedListener.class))
listener.onAccountAdded(accountItem);
if (accountItem.isEnabled()) {
onAccountEnabled(accountItem);
if (accountItem.getRawStatusMode().isOnline())
onAccountOnline(accountItem);
}
onAccountChanged(accountItem.getAccount());
}
所有的account add都会调用这个方法,此时会调用application中的所有实现了onAccountAddedListener接口的manager,这些manager都实现了onAccountAdded方法。在account add的过程中最终会调用如下方法:
private AccountItem addAccount(AccountProtocol protocol, boolean custom,
String host, int port, String serverName, String userName,
boolean storePassword, String password, String resource, int color,
int priority, StatusMode statusMode, String statusText,
boolean enabled, boolean saslEnabled, TLSMode tlsMode,
boolean compression, boolean syncable, KeyPair keyPair,
Date lastSync, ArchiveMode archiveMode) {
AccountItem accountItem = new AccountItem(protocol, custom, host, port,
serverName, userName, resource, storePassword, password, color,
priority, statusMode, statusText, enabled, saslEnabled,
tlsMode, compression, syncable, keyPair, lastSync, archiveMode);
requestToWriteAccount(accountItem);
addAccount(accountItem);
accountItem.updateConnection(true);
return accountItem;
}
该方法的最后会调用updateConnection方法连接xmpp service
5、MUC的创建过程:
1) 需要返回主界面选择联系人,选人的intent创建函数为:
public static Intent createRoomInviteIntent(Context context,
String account, String room) {
Intent intent = new EntityIntentBuilder(context, ContactList.class)
.setAccount(account).setUser(room).build();
intent.setAction(ACTION_ROOM_INVITE);
return intent;
}
其中account的值为:jiangsai@localhost/androiddtQMYayh(登录账户)
room的值为:嗯哪@muc.localhost 嗯哪为这个聊天室的名称
2) 拉人进入聊天室的逻辑:在MUCManager中:
public void invite(String account, String room, String user)
throws NetworkException {
RoomChat roomChat = getRoomChat(account, room);
if (roomChat == null || roomChat.getState() != RoomState.available) {
Application.getInstance().onError(R.string.NOT_CONNECTED);
return;
}
Message message = new Message(room);
MUCUser mucUser = new MUCUser();
MUCUser.Invite invite = new MUCUser.Invite();
invite.setTo(user);
invite.setReason("");
mucUser.setInvite(invite);
message.addExtension(mucUser);
ConnectionManager.getInstance().sendPacket(account, message);
roomChat.putInvite(message.getPacketID(), user);
roomChat.newAction(roomChat.getNickname(), user, ChatAction.invite_sent);
}
其中参数
account为jiangsai@localhost/androiddtQMYayh(邀请人)
room为:嗯哪@muc.localhost(聊天室名称)
user为:xiaoming@localhost(被邀请人)
6、登录后自动加入部门聊天室,部门聊天室通过admin创建:
加入聊天室的逻辑:
1)调用一下函数加入聊天室:
MUCManager.getInstance()
.createRoom(account, room, nick, password, join);
各个参数为:
account的值jiangsai@localhost/androiddtQMYayh(当前登录账号)
room的值为:微信@muc.localhost(聊天室名称)
nick的值为:jiangsai
password的值为: ""
join的值为:true1
TODO:
1、ReConnectService.java中的reconnect方法,调用connection.connect();进行重连的地方要改成异步线程,参考xabber里的ConnectionThread
2、解析vcard的逻辑,需要解析返回的xml格式内容,在VCardProvider类的parseInner方法中