Я реализовал новый GCM CCS для двунаправленных сообщений между приложением Android и веб-сервером. Нисходящие сообщения (веб-устройство) работают отлично. К сожалению, восходящие сообщения (device-web) на сервер не поступают. Похоже, что они отправляются на стороне клиента (см. сообщение журнала приложения Android ниже), но сервер ничего не получает.
D/GCM﹕ GcmService start Intent { act=com.google.android.gcm.intent.SEND flg=0x10 pkg=com.google.android.gms cmp=com.google.android.gms/.gcm.GcmService (has extras) } com.google.android.gcm.intent.SEND
Я предполагаю, что на стороне Android все в порядке, а на стороне сервера. Дело в том, что я не могу понять, что не так, потому что соединение все еще живо, и я получаю некоторые сообщения от сервера GCM, такие как ACK. Так почему нормальные сообщения не приходят? У кого-нибудь есть идеи?
Некоторые другие детали, о которых стоит упомянуть, заключаются в том, что используемый веб-сервер — это Glassfish, и что я запускаю соединение XMPP внутри сервлета. Некоторые фрагменты ниже.
РЕДАКТИРОВАНИЕ: как я уже говорил в ответе, основная проблема, препятствовавшая получению любого сообщения на сервере, была решена. Однако довольно много сообщений до сих пор не доходит (около 50%).
Например, я отправляю 2 сообщения сразу одно за другим в фоновом потоке каждый раз, когда пользователь вносит изменения в приложение Android (нажимает кнопку, так что между каждым пакетом из 2 сообщений проходит как минимум пара секунд). Иногда я получаю оба сообщения на сервер, иногда я получаю только одно из них, иногда вообще ничего не происходит... Это серьезная проблема, особенно для приложений, в основе которых лежит эта технология. Может ли кто-нибудь помочь в устранении неполадок?
Дополнительная информация: я почти уверен, что это не связано с клиентом, так как каждое сообщение отправляется, как вы видите в журнале logcat выше, и я также получаю "event :sent" трансляция GCM через некоторое время (хотя и не сразу, может быть, около 5 минут). Так что это должно быть что-то основанное на GCM или на сервере.
public class CcsServlet extends HttpServlet
{
private static Logger logger = Logger.getLogger(CcsServlet.class.getName());
public void init(ServletConfig config) throws ServletException
{
CcsManager ccsManager = CcsManager.getInstance();
try
{
ccsManager.connect();
}
catch (Exception e)
{
logger.warning("Cannot connect to CCS server.");
e.printStackTrace();
}
}
}
public class CcsManager
{
private static XMPPConnection connection;
private static Logger logger = Logger.getLogger(CcsManager.class.getName());
public static final String GCM_SERVER = "gcm.googleapis.com";
public static final int GCM_PORT = 5235;
private static CcsManager sInstance = null;
private static final String USERNAME = "xxxxxxxxxx" + "@gcm.googleapis.com";
private static final String PASSWORD = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
public CcsManager()
{
// Add GcmPacketExtension
ProviderManager.getInstance().addExtensionProvider(
GcmPacketExtension.GCM_ELEMENT_NAME,
GcmPacketExtension.GCM_NAMESPACE, new PacketExtensionProvider()
{
public PacketExtension parseExtension(XmlPullParser parser) throws Exception
{
String json = parser.nextText();
return new GcmPacketExtension(json);
}
});
}
public static CcsManager getInstance()
{
if (sInstance == null)
sInstance = new CcsManager();
return sInstance;
}
/**
* Connects to GCM Cloud Connection Server
*/
public void connect() throws IOException, XMPPException
{
ConnectionConfiguration config = new ConnectionConfiguration(GCM_SERVER, GCM_PORT);
config.setSecurityMode(ConnectionConfiguration.SecurityMode.enabled);
config.setReconnectionAllowed(true);
config.setRosterLoadedAtLogin(false);
config.setSendPresence(false);
config.setSocketFactory(SSLSocketFactory.getDefault());
config.setDebuggerEnabled(false);
connection = new XMPPConnection(config);
connection.connect();
connection.addConnectionListener(new ConnectionListener()
{
public void reconnectionSuccessful()
{
logger.info("Reconnecting..");
}
public void reconnectionFailed(Exception e)
{
logger.log(Level.INFO, "Reconnection failed.. ", e);
}
public void reconnectingIn(int seconds)
{
logger.log(Level.INFO, "Reconnecting in %s secs", seconds);
}
public void connectionClosedOnError(Exception e)
{
logger.info("Connection closed on error.");
}
public void connectionClosed()
{
logger.info("Connection closed.");
}
});
// Handle incoming packets
connection.addPacketListener(new PacketListener()
{
public void processPacket(Packet packet)
{
logger.log(Level.INFO, "Received: " + packet.toXML());
Message incomingMessage = (Message) packet;
GcmPacketExtension gcmPacket =
(GcmPacketExtension) incomingMessage.getExtension(GcmPacketExtension.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()
{
public void interceptPacket(Packet packet)
{
logger.log(Level.INFO, "Sent: {0}", packet.toXML());
}
}, new PacketTypeFilter(Message.class));
connection.login(USERNAME, PASSWORD);
}
}