无法使用教程“使用 Smack 实现基于 XMPP 的应用服务器的 Java 示例”
Posted
技术标签:
【中文标题】无法使用教程“使用 Smack 实现基于 XMPP 的应用服务器的 Java 示例”【英文标题】:Could not use Tutorial "Java sample implementing an XMPP-based App Server using the Smack" 【发布时间】:2015-05-19 17:24:55 【问题描述】:从一开始我就是 Java 开发的新手...我尝试在 NetBeans IDE 上使用以下 Java 代码:
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.PacketInterceptor;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.DefaultPacketExtension;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.provider.PacketExtensionProvider;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.util.StringUtils;
import org.json.simple.JSONValue;
import org.json.simple.parser.ParseException;
import org.xmlpull.v1.XmlPullParser;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.SSLSocketFactory;
/**
* Sample Smack implementation of a client for GCM Cloud Connection Server. This
* code can be run as a standalone CCS client.
*
* <p>For illustration purposes only.
*/
public class SmackCcsClient
private static final Logger logger = Logger.getLogger("SmackCcsClient");
private static final String GCM_SERVER = "gcm.googleapis.com";
private static final int GCM_PORT = 5235;
private static final String GCM_ELEMENT_NAME = "gcm";
private static final String GCM_NAMESPACE = "google:mobile:data";
static
ProviderManager.addExtensionProvider(GCM_ELEMENT_NAME, GCM_NAMESPACE,
new PacketExtensionProvider()
@Override
public PacketExtension parseExtension(XmlPullParser parser) throws
Exception
String json = parser.nextText();
return new GcmPacketExtension(json);
);
private XMPPConnection connection;
/**
* Indicates whether the connection is in draining state, which means that it
* will not accept any new downstream messages.
*/
protected volatile boolean connectionDraining = false;
/**
* Sends a downstream message to GCM.
*
* @return true if the message has been successfully sent.
*/
public boolean sendDownstreamMessage(String jsonRequest) throws
NotConnectedException
if (!connectionDraining)
send(jsonRequest);
return true;
logger.info("Dropping downstream message since the connection is draining");
return false;
/**
* Returns a random message id to uniquely identify a message.
*
* <p>Note: This is generated by a pseudo random number generator for
* illustration purpose, and is not guaranteed to be unique.
*/
public String nextMessageId()
return "m-" + UUID.randomUUID().toString();
/**
* Sends a packet with contents provided.
*/
protected void send(String jsonRequest) throws NotConnectedException
Packet request = new GcmPacketExtension(jsonRequest).toPacket();
connection.sendPacket(request);
/**
* Handles an upstream data message from a device application.
*
* <p>This sample echo server sends an echo message back to the device.
* Subclasses should override this method to properly process upstream messages.
*/
protected void handleUpstreamMessage(Map<String, Object> jsonObject)
// PackageName of the application that sent this message.
String category = (String) jsonObject.get("category");
String from = (String) jsonObject.get("from");
@SuppressWarnings("unchecked")
Map<String, String> payload = (Map<String, String>) jsonObject.get("data");
payload.put("ECHO", "Application: " + category);
// Send an ECHO response back
String echo = createJsonMessage(from, nextMessageId(), payload,
"echo:CollapseKey", null, false);
try
sendDownstreamMessage(echo);
catch (NotConnectedException e)
logger.log(Level.WARNING, "Not connected anymore, echo message is
not sent", e);
/**
* Handles an ACK.
*
* <p>Logs a INFO message, but subclasses could override it to
* properly handle ACKs.
*/
protected void handleAckReceipt(Map<String, Object> jsonObject)
String messageId = (String) jsonObject.get("message_id");
String from = (String) jsonObject.get("from");
logger.log(Level.INFO, "handleAckReceipt() from: " + from + ",
messageId: " + messageId);
/**
* Handles a NACK.
*
* <p>Logs a INFO message, but subclasses could override it to
* properly handle NACKs.
*/
protected void handleNackReceipt(Map<String, Object> jsonObject)
String messageId = (String) jsonObject.get("message_id");
String from = (String) jsonObject.get("from");
logger.log(Level.INFO, "handleNackReceipt() from: " + from + ",
messageId: " + messageId);
protected void handleControlMessage(Map<String, Object> jsonObject)
logger.log(Level.INFO, "handleControlMessage(): " + jsonObject);
String controlType = (String) jsonObject.get("control_type");
if ("CONNECTION_DRAINING".equals(controlType))
connectionDraining = true;
else
logger.log(Level.INFO, "Unrecognized control type: %s. This could
happen if new features are " + "added to the CCS protocol.",
controlType);
/**
* Creates a JSON encoded GCM message.
*
* @param to RegistrationId of the target device (Required).
* @param messageId Unique messageId for which CCS sends an
* "ack/nack" (Required).
* @param payload Message content intended for the application. (Optional).
* @param collapseKey GCM collapse_key parameter (Optional).
* @param timeToLive GCM time_to_live parameter (Optional).
* @param delayWhileIdle GCM delay_while_idle parameter (Optional).
* @return JSON encoded GCM message.
*/
public static String createJsonMessage(String to, String messageId,
Map<String, String> payload, String collapseKey, Long timeToLive,
Boolean delayWhileIdle)
Map<String, Object> message = new HashMap<String, Object>();
message.put("to", to);
if (collapseKey != null)
message.put("collapse_key", collapseKey);
if (timeToLive != null)
message.put("time_to_live", timeToLive);
if (delayWhileIdle != null && delayWhileIdle)
message.put("delay_while_idle", true);
message.put("message_id", messageId);
message.put("data", payload);
return JSONValue.toJSONString(message);
/**
* Creates a JSON encoded ACK message for an upstream message received
* from an application.
*
* @param to RegistrationId of the device who sent the upstream message.
* @param messageId messageId of the upstream message to be acknowledged to CCS.
* @return JSON encoded ack.
*/
protected static String createJsonAck(String to, String messageId)
Map<String, Object> message = new HashMap<String, Object>();
message.put("message_type", "ack");
message.put("to", to);
message.put("message_id", messageId);
return JSONValue.toJSONString(message);
/**
* Connects to GCM Cloud Connection Server using the supplied credentials.
*
* @param senderId Your GCM project number
* @param apiKey API Key of your project
*/
public void connect(long senderId, String apiKey)
throws XMPPException, IOException, SmackException
ConnectionConfiguration config =
new ConnectionConfiguration(GCM_SERVER, GCM_PORT);
config.setSecurityMode(SecurityMode.enabled);
config.setReconnectionAllowed(true);
config.setRosterLoadedAtLogin(false);
config.setSendPresence(false);
config.setSocketFactory(SSLSocketFactory.getDefault());
connection = new XMPPTCPConnection(config);
connection.connect();
connection.addConnectionListener(new LoggingConnectionListener());
// Handle incoming packets
connection.addPacketListener(new PacketListener()
@Override
public void processPacket(Packet packet)
logger.log(Level.INFO, "Received: " + packet.toXML());
Message incomingMessage = (Message) packet;
GcmPacketExtension gcmPacket =
(GcmPacketExtension) incomingMessage.
getExtension(GCM_NAMESPACE);
String json = gcmPacket.getJson();
try
@SuppressWarnings("unchecked")
Map<String, Object> jsonObject =
(Map<String, Object>) JSONValue.
parseWithException(json);
// present for "ack"/"nack", null otherwise
Object messageType = jsonObject.get("message_type");
if (messageType == null)
// Normal upstream data message
handleUpstreamMessage(jsonObject);
// Send ACK to CCS
String messageId = (String) jsonObject.get("message_id");
String from = (String) jsonObject.get("from");
String ack = createJsonAck(from, messageId);
send(ack);
else if ("ack".equals(messageType.toString()))
// Process Ack
handleAckReceipt(jsonObject);
else if ("nack".equals(messageType.toString()))
// Process Nack
handleNackReceipt(jsonObject);
else if ("control".equals(messageType.toString()))
// Process control message
handleControlMessage(jsonObject);
else
logger.log(Level.WARNING,
"Unrecognized message type (%s)",
messageType.toString());
catch (ParseException e)
logger.log(Level.SEVERE, "Error parsing JSON " + json, e);
catch (Exception e)
logger.log(Level.SEVERE, "Failed to process packet", e);
, new PacketTypeFilter(Message.class));
// Log all outgoing packets
connection.addPacketInterceptor(new PacketInterceptor()
@Override
public void interceptPacket(Packet packet)
logger.log(Level.INFO, "Sent: 0", packet.toXML());
, new PacketTypeFilter(Message.class));
connection.login(senderId + "@gcm.googleapis.com", apiKey);
public static void main(String[] args) throws Exception
final long senderId = 1234567890L; // your GCM sender id
final String password = "Your API key";
SmackCcsClient ccsClient = new SmackCcsClient();
ccsClient.connect(senderId, password);
// Send a sample hello downstream message to a device.
String toRegId = "RegistrationIdOfTheTargetDevice";
String messageId = ccsClient.nextMessageId();
Map<String, String> payload = new HashMap<String, String>();
payload.put("Hello", "World");
payload.put("CCS", "Dummy Message");
payload.put("EmbeddedMessageId", messageId);
String collapseKey = "sample";
Long timeToLive = 10000L;
String message = createJsonMessage(toRegId, messageId, payload,
collapseKey, timeToLive, true);
ccsClient.sendDownstreamMessage(message);
/**
* XMPP Packet Extension for GCM Cloud Connection Server.
*/
private static final class GcmPacketExtension extends DefaultPacketExtension
private final String json;
public GcmPacketExtension(String json)
super(GCM_ELEMENT_NAME, GCM_NAMESPACE);
this.json = json;
public String getJson()
return json;
@Override
public String toXML()
return String.format("<%s xmlns=\"%s\">%s</%s>",
GCM_ELEMENT_NAME, GCM_NAMESPACE,
StringUtils.escapeForXML(json), GCM_ELEMENT_NAME);
public Packet toPacket()
Message message = new Message();
message.addExtension(this);
return message;
private static final class LoggingConnectionListener
implements ConnectionListener
@Override
public void connected(XMPPConnection xmppConnection)
logger.info("Connected.");
@Override
public void authenticated(XMPPConnection xmppConnection)
logger.info("Authenticated.");
@Override
public void reconnectionSuccessful()
logger.info("Reconnecting..");
@Override
public void reconnectionFailed(Exception e)
logger.log(Level.INFO, "Reconnection failed.. ", e);
@Override
public void reconnectingIn(int seconds)
logger.log(Level.INFO, "Reconnecting in %d secs", seconds);
@Override
public void connectionClosedOnError(Exception e)
logger.info("Connection closed on error.");
@Override
public void connectionClosed()
logger.info("Connection closed.");
我在以下链接中找到的源代码: http://developer.android.com/google/gcm/ccs.html#implement
我已经导入了 Smack 4.1.1 以及 json-simple-1.1.1、xmlpull-1.1.3.1、junit...
问题在于 Smack 库,我遇到了很多错误,即使我已经从中导入了所有 jar 文件......我知道 Smack 库在开发过程中有着悠久的历史......我仍然想了解什么我正在做...在以下链接上找到了可能的解决方案: GCM XMPP Server using Smack 4.1.0
也许我可以使用它,也许不能……有教程吗?也许有一些更好的例子? Smack 上的每个版本都有自己的文档吗?
【问题讨论】:
您是否编辑过 build.gradle 文件? 我正在尝试.. 我是 Android 应用开发的新手,但没有成功 【参考方案1】:build.gradle(模块:app)
apply plugin: 'com.android.application'
android
compileSdkVersion 22
buildToolsVersion "22.0.1"
defaultConfig
applicationId "com.example.sqltest2"
minSdkVersion 16
targetSdkVersion 22
versionCode 1
versionName "1.0"
buildTypes
release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
dependencies
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.1.1'
compile 'com.google.android.gms:play-services:7.3.0'
compile "org.igniterealtime.smack:smack-android:4.1.0-rc1"
compile "org.igniterealtime.smack:smack-tcp:4.1.0-rc1"
compile "org.igniterealtime.smack:smack-extensions:4.1.0-rc1"
compile "org.igniterealtime.smack:smack-im:4.1.0-rc1"
【讨论】:
以上是关于无法使用教程“使用 Smack 实现基于 XMPP 的应用服务器的 Java 示例”的主要内容,如果未能解决你的问题,请参考以下文章
使用 GPU 无法在 tensorflow 教程中运行词嵌入示例
Azure 数字孪生 API 无法使用教程中所述的 DefaultAzureCredential 身份验证方法