一.首先服务端,需要去(https://www.process-one.net/en/ejabberd/downloads/)官网下载ejabberd,然后就是简单的安装啦。安装过程中设置domain域名跟管理员账号密码。
二.安装跟启动完成之后,启动ejabberd服务,会进入一个后台管理页面,然后你就可以进行创建用户啦。
三.android端,我这边采用的是一个xxmp的第三方框架smack
首先你需要引入依赖
def smackVersion = '4.1.9'
implementation "org.igniterealtime.smack:smack-android-extensions:$smackVersion"
implementation "org.igniterealtime.smack:smack-experimental:$smackVersion"
implementation "org.igniterealtime.smack:smack-tcp:$smackVersion"
接着来了,开始链接
XMPPTCPConnectionConfiguration configuration = null;
try {
configuration = XMPPTCPConnectionConfiguration.builder()
.setHost("你的域名")
// .setPort(port)
// .setResource("phone")//代表链接设备的一个标识
.setServiceName("你开始设置的服务器名也就是domain")
.setDebuggerEnabled(DEBUG)//是否开启debug
.setConnectTimeout(5000)
.setSendPresence(true)//不发在线状态 等UI处理完以后再发
.setSecurityMode(ConnectionConfiguration.SecurityMode.disable)//跳过安全认证
.setCompressionEnabled(false)//是否压缩发送
.build();
connection = new XMPPTCPConnection(configuration);
connection.connect();//开始链接
上面就是链接的代码,你以为这里就可以链接上去了吗?太天真了,如果是openfire应该就是没问题了,但是ejabberd是不行的,ejabberd默认是开启starttls,如果你用以上连接,那么会报下面这样一个错误
org.jivesoftware.smack.SmackException$SecurityRequiredByServerException: SSL/TLS required by server but disabled in client
在这里有两个解决办法,
(1)直接去服务端ejabberd那里找到conf文件夹下面的ejabberd.yml文件把starttls_required = true改为false
(2)使用下面代码,信任所有证书
在设置Configuration的时候加上这两个配置就可以搞定啦
XMPPTCPConnectionConfiguration.builder()
.setSecurityMode(ConnectionConfiguration.SecurityMode.require)
.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
})
.setCustomSSLContext(sslContext())
public SSLContext sslContext() {
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}};
SSLContext sc = null;
try {
sc = SSLContext.getInstance("TLS");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
// trustAllCerts信任所有的证书
try {
sc.init(null, trustAllCerts, new SecureRandom());
} catch (KeyManagementException e) {
e.printStackTrace();
}
return sc;
}
四:链接完成之后,就可以开始操作啦,首先是登陆
登陆的话可以直接调用拿到的XMPPTCPConnection
实例,或者直接在配置上面设置setUsernameAndPassword("username","password")
如果你上面有设置setUsernameAndPassword
那么你就直接调用XMPPTCPConnection.login()
没有的话则可以调用XMPPTCPConnection.login(“username”,"password","resource")
登陆完成之后,就是获取联系人啊,发送消息这些,这些我看网上有很多类似的博客跟文章了,我就不再赘述了
五:这里有两个注意的点,
(1)如果你发现你不能注册的话,你需要在ejabberd.yml上的trusted_network: allow: loopback
改为trusted_network: allow: all
(2)接着就是ejabberd的搜索好友问题,如果你不能搜索好友的话,你需要在ejabberd.yml的mod_vcard:{}
这里改为mod_vcard:{search:true}
,其次还有代码跟openfire不一样,ejabberd使用的代码是
UserSearchManager userSearchManager = new UserSearchManager(connection);
try {
Form searchForm = userSearchManager.getSearchForm("vjud." + connection.getServiceName());//还有这里,openfire是serach,ejabberd是vjud
Form answer = searchForm.createAnswerForm();
answer.setAnswer("user", “user”)//主要是这里不一样
ReportedData reportedData = userSearchManager.getSearchResults(answer, "vjud." + connection.getServiceName());
ArrayList<String> columnnames = new ArrayList<>();
for (ReportedData.Column column : reportedData.getColumns()) {
columnnames.add(column.getLabel());
}
for (ReportedData.Row row : reportedData.getRows()) {
if (!row.getValues(columnnames.get(0)).isEmpty()) {
String s = row.getValues(columnnames.get(0)).get(0).toString();
list.add(new ContactVo(s));
}
}
六:发送图片和发送语音消息
网上查资料说的都是按照下面代码去实现,调用XMPPTCPConnection的发送文件去发送的
FileTransferManager fileTransferManager = FileTransferManager.getInstanceFor(connection);
OutgoingFileTransfer fileTransfer = fileTransferManager
.createOutgoingFileTransfer("jid");//这里的jid需要在后面加一个/resource否则会报错
fileTransfer.sendFile("file", "这是一个标识"); //这是发送文件的
然后接收文件是下面代码
FileTransferListener fileTransferListener = new FileTransferListener(){
@Override
public void fileTransferRequest(FileTransferRequest request) {
IncomingFileTransfer accept = request.accept();
try {
if (file != null) {
accept.recieveFile(file);
}
System.out.println("接收文件=====");
} catch (IOException e) {
e.printStackTrace();
} catch (SmackException e) {
e.printStackTrace();
}
}
}
FileTransferManager fileTransferManager = FileTransferManager.getInstanceFor(connection);
fileTransferManager.addFileTransferListener(fileTransferListener);
这是我网上找到smack发送图片信息跟文件信息的一些代码,然后这个对我好像没用,我都是报503错误,这个估计是服务器需要做什么配置,希望有知道的可以告诉我一下。
我来说说我后面实现的思路,我这边后面的实现思路是这样子的,先将语音跟图片转成Base64的字符串然自定义element然后通过文本消息发送过去,最后在接收消息的那边将Base64字符串转成文件,下面我贴一下自定义element的代码
class ImageElement : ExtensionElement {
var imageUrl: String? = null
constructor(imageUrl: String?) {
this.imageUrl = imageUrl
}
constructor() {}
override fun getNamespace(): String {
return nameSpace
}
override fun getElementName(): String {
return Companion.elementName
}
override fun toXML(): CharSequence {
return "<" +
Companion.elementName +
" xmlns=\"http://mangga.me/protocol/image\"" +
" type=\"image/jpeg\"" +
">" +
imageUrl +
"</" +
Companion.elementName +
">"
}
companion object {
const val elementName = "image"
}
}
public class ImageExtensionProvider extends ExtensionElementProvider {
@Override
public Element parse(XmlPullParser parser, int initialDepth) throws XmlPullParserException, IOException, SmackException {
boolean done = false;
ImageElement element = new ImageElement();
int eventType = parser.next();
String name = parser.getName();
if (eventType == XmlPullParser.TEXT) {
element.setImageUrl( parser.getText());
}
return element;
}
}
然后在发送文本消息的时候加上这句话
msg.addExtension(new ImageElement(“iamgeurl”));
还有配置添加拓展信息加上
ProviderManager.addExtensionProvider(ImageElement.elementName, ImageElement.nameSpace, new ImageExtensionProvider());
最后在接收信息这里拿到字符串去转文件
ImageElement element1 = msg.getExtension(ImageElement.elementName, ImageElement.nameSpace);
element.getImageUrl就可以拿到base64的字符串了
上面就是我发送语音消息跟图片消息的具体实现,如果有错的,希望大佬能指出来,还有那个sendFile报503的问题也希望有人可以告诉我一下,文章到此就告一段落啦,有可以问的,也可以跟我一起继续探讨,有什么好建议我也会听取各位大考的意见的,因为android跟ejabberd的相关资料比较少,所以就记录一下,希望可以帮到你们。