谷歌云消息传递 - 使用 smack 的 xmpp 服务器端不起作用
Posted
技术标签:
【中文标题】谷歌云消息传递 - 使用 smack 的 xmpp 服务器端不起作用【英文标题】:google cloud messaging - xmpp server side using smack not working 【发布时间】:2013-08-13 14:43:01 【问题描述】:当使用以下代码向使用 smack libary 3.3.0 的设备发送消息时
遇到错误
SASL authentication PLAIN failed: text:
at org.jivesoftware.smack.SASLAuthentication.authenticate(SASLAuthentication.java:342)
at org.jivesoftware.smack.XMPPConnection.login(XMPPConnection.java:221)
at org.jivesoftware.smack.Connection.login(Connection.java:366)
at com.test.xmpp.SmackCcsClient.connect(SmackCcsClient.java:335)
at com.test.xmpp.SmackCcsClient.main(SmackCcsClient.java:345)
当切换到 HTTP 服务器端时,消息正在工作
/**
* Sample Smack implementation of a client for GCM Cloud Connection Server.
*
* <p>For illustration purposes only.
*/
public class SmackCcsClient
Logger logger = Logger.getLogger("SmackCcsClient");
public static final String GCM_SERVER = "gcm.googleapis.com";
public static final int GCM_PORT = 5235;
public static final String GCM_ELEMENT_NAME = "gcm";
public static final String GCM_NAMESPACE = "google:mobile:data";
static Random random = new Random();
XMPPConnection connection;
ConnectionConfiguration config;
/**
* XMPP Packet Extension for GCM Cloud Connection Server.
*/
class GcmPacketExtension extends DefaultPacketExtension
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, json, GCM_ELEMENT_NAME);
@SuppressWarnings("unused")
public Packet toPacket()
return new Message()
// Must override toXML() because it includes a <body>
@Override
public String toXML()
StringBuilder buf = new StringBuilder();
buf.append("<message");
if (getXmlns() != null)
buf.append(" xmlns=\"").append(getXmlns()).append("\"");
if (getLanguage() != null)
buf.append(" xml:lang=\"").append(getLanguage()).append("\"");
if (getPacketID() != null)
buf.append(" id=\"").append(getPacketID()).append("\"");
if (getTo() != null)
buf.append(" to=\"").append(StringUtils.escapeForXML(getTo())).append("\"");
if (getFrom() != null)
buf.append(" from=\"").append(StringUtils.escapeForXML(getFrom())).append("\"");
buf.append(">");
buf.append(GcmPacketExtension.this.toXML());
buf.append("</message>");
return buf.toString();
;
public SmackCcsClient()
// Add GcmPacketExtension
ProviderManager.getInstance().addExtensionProvider(GCM_ELEMENT_NAME,
GCM_NAMESPACE, new PacketExtensionProvider()
@Override
public PacketExtension parseExtension(XmlPullParser parser)
throws Exception
String json = parser.nextText();
GcmPacketExtension packet = new GcmPacketExtension(json);
return packet;
);
/**
* 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 getRandomMessageId()
return "m-" + Long.toString(random.nextLong());
/**
* Sends a downstream GCM message.
*/
public void send(String jsonRequest)
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 process an upstream message.
*/
public void handleIncomingDataMessage(Map<String, Object> jsonObject)
String from = jsonObject.get("from").toString();
// PackageName of the application that sent this message.
String category = jsonObject.get("category").toString();
// Use the packageName as the collapseKey in the echo packet
String collapseKey = "echo:CollapseKey";
@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, getRandomMessageId(), payload, collapseKey, null, false);
send(echo);
/**
* Handles an ACK.
*
* <p>By default, it only logs a INFO message, but subclasses could override it to
* properly handle ACKS.
*/
public void handleAckReceipt(Map<String, Object> jsonObject)
String messageId = jsonObject.get("message_id").toString();
String from = jsonObject.get("from").toString();
logger.log(Level.INFO, "handleAckReceipt() from: " + from + ", messageId: " + messageId);
/**
* Handles a NACK.
*
* <p>By default, it only logs a INFO message, but subclasses could override it to
* properly handle NACKS.
*/
public void handleNackReceipt(Map<String, Object> jsonObject)
String messageId = jsonObject.get("message_id").toString();
String from = jsonObject.get("from").toString();
logger.log(Level.INFO, "handleNackReceipt() from: " + from + ", messageId: " + messageId);
/**
* Creates a JSON encoded GCM message.
*
* @param to RegistrationId of the target device (Required).
* @param messageId Unique messageId for which CCS will send 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.
*/
public 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 username GCM_SENDER_ID@gcm.googleapis.com
* @param password API Key
* @throws XMPPException
*/
public void connect(String username, String password) throws XMPPException
config = new ConnectionConfiguration(GCM_SERVER, GCM_PORT);
config.setSecurityMode(SecurityMode.enabled);
config.setReconnectionAllowed(true);
config.setRosterLoadedAtLogin(false);
config.setSendPresence(false);
config.setSocketFactory(SSLSocketFactory.getDefault());
// NOTE: Set to true to launch a window with information about packets sent and received
config.setDebuggerEnabled(true);
// -Dsmack.debugEnabled=true
XMPPConnection.DEBUG_ENABLED = true;
connection = new XMPPConnection(config);
connection.connect();
connection.addConnectionListener(new ConnectionListener()
@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.log(Level.INFO, "Connection closed on error.");
@Override
public void connectionClosed()
logger.info("Connection closed.");
);
// 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
handleIncomingDataMessage(jsonObject);
// Send ACK to CCS
String messageId = jsonObject.get("message_id").toString();
String from = jsonObject.get("from").toString();
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
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, "Couldn't send echo.", 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(username, password);
public static void main(String [] args)
final String userName = "124079202908" + "@gcm.googleapis.com";
final String password = "AIzaSyAMt1y_xILk72wiQybuqVEdiq7uGXBEUhQ";
SmackCcsClient ccsClient = new SmackCcsClient();
try
ccsClient.connect(userName, password);
catch (XMPPException e)
e.printStackTrace();
另外,我在一个多星期前提交了使用 API 的请求,但尚未收到回复。
【问题讨论】:
你改变了这些行吗? ` final String userName = "你的 GCM 发件人 ID" + "@gcm.googleapis.com";最终字符串密码 = "API 密钥";` 是的,这两个值都已更新,当将它们与 HTTP 实现一起使用时,会收到消息。这是调试窗口中的错误输出问题已解决。问题确实是该项目没有注册。在要求 API 接收确认后,我收到了来自 Google 2 周的电子邮件。 这种情况下的错误确实应该得到改进,如果谷歌写下大约多久可以收到电子邮件,那就太好了。 只是想更新遇到问题的其他人。
【讨论】:
【参考方案2】:@user2679041 我猜你说得对。我今天刚刚注册了我的 gcm 项目 ID,但我还没有收到任何确认电子邮件。这真的很烦人,还有谁要等两个星期?我在@*** 看到很少有人说在3 months too. 之后有请求被谷歌批准的查询 我已经关注了这个link
它有一个注释说:
在 API 控制台中创建启用 GCM 的项目后,您必须填写此表单并成为试用合作伙伴,才能通过 CCS 使用上游消息传递和用户通知。访问仅限于填写表格的人。您将收到一封来自 Google 的电子邮件,通知您现在可以访问; Google 还会向您发送回显服务器的地址,您可以使用该地址将消息退回到您的应用程序。
所以我们可以说谷歌发布了数量有限的测试版。访问权限。
【讨论】:
以上是关于谷歌云消息传递 - 使用 smack 的 xmpp 服务器端不起作用的主要内容,如果未能解决你的问题,请参考以下文章