Android aSmack - How to create a custom message extension for sending files?
I am trying to implement an offline file extension for my chat application. I am using PacketExtension and EmbeddedExtensionProvider to add and parse a custom extension. I can see that the values and tags are added when the message is sent, but they are missing at the end of the receiver. What am I doing wrong?
Sending message:
<message id="224K2-7" to="testfirzan@sushant" type="chat">
<body>hi</body>
<custom xmlns="jabber2:x2:oob2">
<url>URL</url>
<desc>Description</desc>
</custom>
</message>
Receiving a message:
System.out(734): EmbeddedExtensionProvider
<message id="224K2-7" to="testfirzan@sushant" from="testsushant@sushant/Smack" type="chat">
<body>hi</body>
<custom xmlns="jabber2:x2:oob2"></custom>
</message>
File Extension description:(734): <custom xmlns="jabber2:x2:oob2"></custom>
Package extension and provider manager code:
public class FileExtension implements PacketExtension {
public static final String ELEMENT = "custom";
public static final String NAMESPACE = "jabber2:x2:oob2";
String description;
String url;
@Override
public String getElementName() {
return "custom";
}
@Override
public String getNamespace() {
return "jabber2:x2:oob2";
}
@Override
public String toXML() {
StringBuilder builder = new StringBuilder();
builder.append("<" + getElementName() + " xmlns=\"" + getNamespace()
+ "\">");
if (url != null) {
builder.append("<url>").append(url).append("</url>");
}
if (description != null) {
builder.append("<desc>").append(description).append("</desc>");
}
builder.append("</" + getElementName() + ">");
return builder.toString();
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUrl() {
return url;
}
public void setUrl(String imageUrl) {
this.url = imageUrl;
}
public static class FileExtensionProvider extends EmbeddedExtensionProvider {
@Override
protected PacketExtension createReturnExtension(String currentElement,
String currentNamespace, Map<String, String> attributeMap,
List<? extends PacketExtension> content) {
System.out.println("EmbeddedExtensionProvider");
return new FileExtension();
}
}
}
Supplier registration:
ProviderManager.getInstance().addExtensionProvider(
FileExtension.ELEMENT, FileExtension.NAMESPACE,
new FileExtension.FileExtensionProvider());
When sending a message:
FileExtension fileExt = new FileExtension("URL");
fileExt.setDescription("Description");
fileExt.setUrl("URL");
msg.addExtension(fileExt);
After receiving the message:
FileExtension fileExt = (FileExtension) message
.getExtension("jabber2:x2:oob2");
Log.i("File Extension description:", fileExt.toXML());
source to share
Below is the complete solution for creating a custom extension using aSmack:
1st I had to create PacketExtension:
public class ExtensionFile implements PacketExtension {
public static final String ELEMENT = "file";
public static final String NAMESPACE = "file:namespace";
private String fileURL;
private String fileSize;
@Override
public String getElementName() {
return ELEMENT;
}
@Override
public String getNamespace() {
return NAMESPACE;
}
@Override
public String toXML() {
StringBuilder builder = new StringBuilder();
builder.append("<" + getElementName() + " xmlns=\"" + getNamespace()
+ "\">");
if (fileURL != null) {
builder.append("<fileURL>").append(fileURL).append("</fileURL>");
}
if (fileSize != null) {
builder.append("<fileSize>").append(fileSize).append("</fileSize>");
}
builder.append("</" + getElementName() + ">");
return builder.toString();
}
public void setFileURL(String fileURL) {
this.fileURL = fileURL;
}
public String getFileURL() {
return fileURL;
}
public void setFileSize(String fileSize) {
this.fileSize = fileSize;
}
public String getFileSize() {
return fileSize;
}
}
Then the vendor to parse this package:
public class ExtensionProviderFile implements PacketExtensionProvider {
@Override
public PacketExtension parseExtension(XmlPullParser parser)
throws Exception {
ExtensionFile fileExt = new ExtensionFile();
int eventType = parser.next();
while (eventType == XmlPullParser.START_TAG) {
String name = parser.getName();
switch (parser.getEventType()) {
case XmlPullParser.START_TAG:
if (name.equals("fileURL")) {
fileExt.setFileURL(parser.nextText());
} else if (name.equals("fileSize")) {
fileExt.setFileSize(parser.nextText());
}
}
eventType = parser.next();
}
return fileExt;
}
}
Send message with file extension:
private void sendMessage(String recipient, String message){
Message msg = new Message(recipient,Message.Type.chat);
msg.setBody(message);
//Create extension and set values
ExtensionFile fileExt = new ExtensionFile();
fileExt.setFileURL("http://www.example.com/upload_files/"+ abc.jpg);
fileExt.setFileSize(fileSize);
//add extension to message
msg.addExtension(fileExt);
//send message
xmppConnection.sendPacket(msg);
}
To get this message, run PacketListener
and override processPacket()
:
@Override
public void processPacket(Packet packet) {
Message message = (Message) packet;
//Get extension from message
ExtensionFile extFile = (ExtensionFile) message
.getExtension("file:namespace");
if (extFile != null) {
//Get values from extension
String filePath = extFile.getFileURL();
String fileSize = extFile.getFileSize();
System.out.println("Message :" + message.getBody() + " File url:" + filePath + " File size:" + fileSize);
}
}
and add this sentence before connecting to xmpp server:
ProviderManager.getInstance().addExtensionProvider(
ExtensionFile.ELEMENT, ExtensionFile.NAMESPACE,
new ExtensionProviderFile());
source to share
In the latest Smack 4.1.7 the PacketExtensionProvider has been removed ( see this ). Therefore, the ExtensionProviderFile can be created after extending the ExtensionElementProvider. Please check the code below -
public class ExtensionProviderFile extends ExtensionElementProvider {
@Override
public Element parse(XmlPullParser parser, int initialDepth) throws XmlPullParserException, IOException, SmackException {
ChatExtension extensionFile = new ChatExtension();
int eventType = parser.next();
while (eventType == XmlPullParser.START_TAG){
String name = parser.getName();
switch (parser.getEventType()) {
case XmlPullParser.START_TAG:
if (name.equals("fileName")) {
extensionFile.setFileName(parser.nextText());
}
else if (name.equals("fullName")) {
extensionFile.setFullName(parser.nextText());
}
}
eventType = parser.next();
}
return extensionFile;
}
}
Hope this helps someone.
source to share