Google GCM XMPP代码示例 [英] Google GCM XMPP code samples
问题描述
https://developers.google.com/cloud-messaging/ccs
我已将此答案加入书签任何时候我想要查看实现
对Google GCM XMPP的困惑 a>
但是那个答案中的所有东西都没有了。谷歌删除了它们。
但是现在,他们已经删除了所有内容,并添加了一个页面来解释它的功能。当然,但是示例java代码会很好。我试图去github上的示例站点,他们链接到
https://github.com/ google / gcm
但它仅提供HTTP GCM服务器版本的示例。
请有人指点我一个有效的代码示例吗?或者有没有一个库可以在C#中工作?如果不是的话,我也只会解决Java版本。
谢谢。
下面是我为一个类示例编写的一个示例(删除了一些非XMPP部分以保持足够小,发布代码,但在 http://people.eku.edu/styere/GcmPushServer拥有完整的服务器.java ):
//派生自https://developer.android.com/google/gcm/ ccs.html
import javax.swing。*;
import java.awt。*;
import java.awt.event。*;
// import javax.swing.JScrollPane;
// import javax.swing.SwingUtilities;
导入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;
导入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.JSONObject;
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.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Random;
导入java.net。*;
import java.io. *;
import java.util。*;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.HttpsURLConnection;
//所有用户和相关设备的列表
class UserList {
//(--deleted--)
//构造函数/读现有数据来自文件
public UserList(){
//(--deleted--)
}
//向现有用户添加新设备(从网络线程调用)
//重复的ID被安静地接受
public synchronized void addDevice(String uname,String newRegToken){
//(--deleted--)
}
//生成组地址/通知键
// !!!!!!!!!!!!!!!警告 !!!!!!!!!!!!!!!
//如果组地址/通知键丢失,它当前不能被恢复/重建
public String createNotificationKey(String nKeyName,String addr){
String [] idset = new String [ 1];
idset [0] = addr;
String newGroupAddr;
尝试{
//创建https连接以创建notification_key
网址url =新网址(https://android.googleapis.com/gcm/notification) ;
HttpsURLConnection conn =(HttpsURLConnection)url.openConnection();
//作为POST请求发送
conn.setRequestMethod(POST);
//添加请求参数
conn.addRequestProperty(project_id,+ GcmPushServer.senderId);
conn.addRequestProperty(Authorization,key =+ GcmPushServer.password);
//使用set,因为这可能已经存在
conn.setRequestProperty(Content-Type,application / json);
//创建要发送的数据
Map< String,Object> sendData = new HashMap<>();
//创建一个新的通知键
sendData.put(operation,create);
sendData.put(notification_key_name,(--deleted--));
sendData.put(registration_ids,(--deleted--));
String strData = JSONValue.toJSONString(sendData);
//发送帖子请求
conn.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
wr.writeBytes(strData);
wr.flush();
wr.close();
//成功了吗?
int rc = conn.getResponseCode();
//System.out.println(\"ResponseCode =+ rc);
//读取响应
扫描仪输入=新扫描仪(conn.getInputStream());
String resp =;
//读取/显示行
while(input.hasNextLine()){
String s = input.nextLine();
resp + = s;
}
//System.out.println(\"Response content:+ resp);
if(rc == HttpsURLConnection.HTTP_OK){
JSONObject obj =(JSONObject)JSONValue.parse(resp);
newGroupAddr =(String)obj.get(notification_key);
//System.out.println(new notification_key:+ newGroupAddr);
返回newGroupAddr;
} else {
}
} catch(Exception e){
//System.out.println(\"-- Exception:+ e.getMessage( ));
}
返回null;
}
//向通知键添加/删除单个地址
//(如果doAdd为true,则添加,否则删除)
//删除最终地址将静静地删除键
public static void modifyNotificationKey(String nKeyName,String nKey,
String addr,boolean doAdd){
String [] idset = new String [1];
idset [0] = addr;
尝试{
//创建https连接以创建notification_key
网址url =新网址(https://android.googleapis.com/gcm/notification) ;
HttpsURLConnection conn =(HttpsURLConnection)url.openConnection();
//作为POST请求发送
conn.setRequestMethod(POST);
//添加请求参数
conn.addRequestProperty(project_id,+ GcmPushServer.senderId);
conn.addRequestProperty(Authorization,key =+ GcmPushServer.password);
//使用set,因为这可能已经存在
conn.setRequestProperty(Content-Type,application / json);
//创建要发送的数据
Map< String,Object> sendData = new HashMap<>();
//创建一个新的通知键
sendData.put(operation,doAdd?add:remove); //添加或删除密钥?
sendData.put(notification_key_name,(--deleted--));
sendData.put(notification_key,(--deleted--));
sendData.put(registration_ids,(--deleted--));
String strData = JSONValue.toJSONString(sendData);
//System.out.println(\"genGroupAddress POST data:+ strData);
//发送帖子请求
conn.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
wr.writeBytes(strData);
wr.flush();
wr.close();
//conn.openConnection();
//成功了吗?
int rc = conn.getResponseCode();
//System.out.println(\"ResponseCode =+ rc);
扫描仪输入=新扫描仪(conn.getInputStream());
//读取/显示行
while(input.hasNextLine()){
System.out.println(Response content:);
String s = input.nextLine();
System.out.println(s);
}
} catch(Exception e){
// do nothing
}
}
}
// text日志消息的区域
class LogTextArea扩展JTextArea {
//用指定消息更新log
public void logMessage(String msg){
//(--deleted - )
}
}
class CcsServer {
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;
//显示/记录区域
LogTextArea logArea;
UserList用户;
CcsServer(LogTextArea lta,UserList u){
logArea = lta;
users = u;
$ b $ {
ProviderManager.addExtensionProvider(GCM_ELEMENT_NAME,GCM_NAMESPACE,
new PacketExtensionProvider(){
@Override
public PacketExtension parseExtension( XmlPullParser解析器)抛出
异常{
字符串json = parser.nextText();
返回新的GcmPacketExtension(json);
}
});
}
私有XMPPConnection连接;
/ **
*表示连接是否处于排空状态,这意味着
*不会接受任何新的下游消息。
* /
保护volatile boolean connectionDraining = false;
/ **
*向GCM发送下游消息。
*
* @如果邮件已成功发送,则返回true。
* /
public boolean sendDownstreamMessage(String jsonRequest)throws
NotConnectedException {
if(!connectionDraining){
send(jsonRequest);
返回true;
}
logArea.logMessage(由于连接正在耗尽而丢弃下游消息);
返回false;
}
/ **
*返回一个随机消息ID来唯一标识一条消息。
*
*< p>注意:这是由伪随机数生成器生成的,用于
*插图的目的,并不保证是唯一的。
* /
public String nextMessageId(){
returnm-+ UUID.randomUUID()。toString();
}
/ **
*发送包含所提供内容的数据包。
* /
protected void send(String jsonRequest)throws NotConnectedException {
数据包请求= new GcmPacketExtension(jsonRequest).toPacket();
connection.sendPacket(request);
}
/ **
*处理来自设备应用程序的上游数据消息。
*
*< p>此示例回显服务器将回显消息发送回设备。
*子类应该重写此方法以正确处理上游消息。
* /
protected void handleUpstreamMessage(Map< String,Object> jsonObject){
//发送此消息的应用程序的PackageName。
String category =(String)jsonObject.get(category);
String from =(String)jsonObject.get(from);
@SuppressWarnings(unchecked)
Map< String,String> payload =(Map< String,String>)jsonObject.get(data);
//这是什么类型的上游信息?
if(!payload.containsKey(my_action))
{
//嗯 - 这不应该发生!
logArea.logMessage(handleUpstreamMessage - 传入消息缺少my_action);
//只是忽略消息
return;
}
//他们想要什么动作?
String my_action =(String)payload.get(my_action);
if(my_action.equals(edu.eku.styere.gcmpushclient.REGISTER)){
//注册请求
字符串username =(String)payload.get(username) ;
logArea.logMessage(Registration request:user =+ username +,ID / Token =+ from);
//保存信息
users.addDevice(username,from);
return;
} else {
//采取默认回应消息的动作
payload.put(ECHO,Application:+ category);
//发送一个ECHO回应
String echo = createJsonMessage(from,nextMessageId(),payload,
echo:CollapseKey,null,false);
尝试{
sendDownstreamMessage(echo);
} catch(NotConnectedException e){
logArea.logMessage(不再连接,echo消息不发送:+ e.getMessage());
}
}
}
/ **
*处理ACK。
*
*< p>记录一条INFO消息,但子类可以覆盖它为
*正确处理ACK。
* /
protected void handleAckReceipt(Map< String,Object> jsonObject){
String messageId =(String)jsonObject.get(message_id);
String from =(String)jsonObject.get(from);
logArea.logMessage(handleAckReceipt()from:+ from +,messageId:+ messageId);
}
/ **
*处理一个NACK。
*
*< p>记录一条INFO消息,但是子类可以覆盖它到
*正确处理NACK。
* /
protected void handleNackReceipt(Map< String,Object> jsonObject){
String messageId =(String)jsonObject.get(message_id);
String from =(String)jsonObject.get(from);
logArea.logMessage(handleNackReceipt()from:+ from +,messageId:+ messageId);
$ b $ protected void handleControlMessage(Map< String,Object> jsonObject){
logArea.logMessage(handleControlMessage():+ jsonObject);
String controlType =(String)jsonObject.get(control_type);
if(CONNECTION_DRAINING.equals(controlType)){
connectionDraining = true;
} else {
logArea.logMessage(无法识别的控制类型:+ controlType +。如果新功能+添加到CCS协议中,可能会发生+
。 );
}
}
/ **
*创建一个JSON编码的GCM消息。
*
* @param到目标设备的RegistrationId(必需)。
* @param messageId CCS发送
*ack / nack唯一的messageId(必需)。
* @param payload用于应用程序的消息内容。 (可选的)。
* @param collapseKey GCM collapse_key参数(可选)。
* @param timeToLive GCM time_to_live参数(可选)。
* @param delayWhileIdle GCM delay_while_idle参数(可选)。
* @返回JSON编码的GCM消息。
* /
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);
}
/ **
*为来自应用程序的上游消息
*创建JSON编码的ACK消息。
*
* @param发送给发送上行消息的设备的RegistrationId。
* @param messageId要向CCS确认的上游消息的messageId。
* @return JSON编码的ack。
* /
protected 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);
}
/ **
*使用提供的凭证连接到GCM云连接服务器。
*
* @param senderId您的GCM项目编号
* @param apiKey您项目的API密钥
* /
public void connect(long senderId,String apiKey)
抛出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());
//处理传入数据包
connection.addPacketListener(new PacketListener(){
@Override
public void processPacket(Packet packet){
logArea.logMessage(Received:+ packet.toXML());
Message incomingMessage =(Message)包;
GcmPacketExtension gcmPacket =
(GcmPacketExtension)incomingMessage。
getExtension(GCM_NAMESPACE);
String json = gcmPacket.getJson();
try {
@SuppressWarnings(unchecked)
Map< String,Object> jsonObject =
(Map< String,Object>)JSONValue。
parseWithException(json);
//表示ack/nack,否则为null
Object messageType = jsonObject获得(message_t YPE);
if(messageType == null){
//正常上游数据消息
handleUpstreamMessage(jsonObject);
//发送ACK到CCS
字符串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())){
//进程确认
handleAckReceipt(jsonObject);
} else if(nack.equals(messageType.toString())){
// Process Nack
handleNackReceipt(jsonObject);
} else if(control.equals(messageType.toString())){
//过程控制消息
handleControlMessage(jsonObject);
} else {
logArea.logMessage(Unrecognized message type:+
messageType.toString());
} catch(ParseException e){
logArea.logMessage(Error parsing JSON+ json);
} catch(Exception e){
logArea.logMessage(无法处理数据包);
}
}
},新的PacketTypeFilter(Message.class));
//记录所有传出数据包
connection.addPacketInterceptor(new PacketInterceptor(){
@Override
public void interceptPacket(Packet packet){
logArea .logMessage(Sent:+ packet.toXML());
}
},new PacketTypeFilter(Message.class));
connection.login(senderId +@ gcm.googleapis.com,apiKey);
}
// ----------支持类----------
/ ** $ b GCM云连接服务器的$ b * XMPP数据包扩展。
* /
private static 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);
返回消息;
类LoggingConnectionListener实现ConnectionListener {
@Override
public void connected(XMPPConnection xmppConnection){
logArea .logMessage(连接。);
}
@Override
public void authenticated(XMPPConnection xmppConnection){
logArea.logMessage(Authenticated。);
}
@Override
public void reconnectionSuccessful(){
logArea.logMessage(Reconnecting ..);
}
@Override
public void reconnectionFailed(Exception e){
logArea.logMessage(Reconnection failed ..+ e.getMessage());
}
@Override
public void reconnectingIn(int seconds){
logArea.logMessage(Reconnecting in+ seconds +secs);
}
@Override
public void connectionClosedOnError(Exception e){
logArea.logMessage(Connection on error。);
}
@Override
public void connectionClosed(){
logArea.logMessage(Connection closed。);
}
}
}
//目标地址的不可编辑组合(下拉框)
类DestComboBox扩展JComboBox< String> {
//(删除以节省空间)
}
//用于发送消息的屏幕面板$ b $ class SendMessagePanel扩展JPanel实现ActionListener,ItemListener {
//消息类型
protected final int MSGTYPE_NOTIFICATION = 1;
protected final int MSGTYPE_NOTIFICATION_DATA = 2;
protected final int MSGTYPE_DATA_COLLAPSE = 3;
protected final int MSGTYPE_DATA_NONCOLLAPSE = 4;
//日志窗口
LogTextArea消息;
//服务器类
CcsServer ccsServer;
//构造函数
SendMessagePanel(UserList u,LogTextArea m,CcsServer c){
//(删除以节省空间)
}
//响应按钮
@Override
public void actionPerformed(ActionEvent e){
String toAddr =zzzzzz; //目标地址
//可能是设备,通知密钥或主题地址
ttl = 2419200; //秒钟生存时间
//什么类型的消息?
int msgTypeIndex =(--deleted--);
//创建消息
Map< String,Object> message = new HashMap< String,Object>();
message.put(to,toAddr);
if(msgTypeIndex == MSGTYPE_NOTIFICATION ||
msgTypeIndex == MSGTYPE_NOTIFICATION_DATA ||
msgTypeIndex == MSGTYPE_DATA_COLLAPSE){
//创建折叠键
message.put(collapse_key,ck+ msgTypeIndex);
}
message.put(time_to_live,ttl);
message.put(message_id,ccsServer.nextMessageId());
//包含通知?
if(msgTypeIndex == MSGTYPE_NOTIFICATION ||
msgTypeIndex == MSGTYPE_NOTIFICATION_DATA){
//创建通知负载
HashMap< String,String> notePayload = new HashMap<>();
notePayload.put(title,Gcm Push Message Example);
notePayload.put(body,(--deleted--));
//标识哪些通知应该替换旧版本
notePayload.put(tag,ntag+ msgTypeIndex);
notePayload.put(icon,@ drawable / new_picture); //通知图标
//额外的东西,如果我们也有数据
if(msgTypeIndex == MSGTYPE_NOTIFICATION_DATA){
//用户打开通知时的操作
notePayload.put(click_action,OPEN_MAIN_ACTIVITY);
}
message.put(notification,notePayload);
}
//包含数据?
if(msgTypeIndex == MSGTYPE_NOTIFICATION_DATA ||
msgTypeIndex == MSGTYPE_DATA_COLLAPSE ||
msgTypeIndex == MSGTYPE_DATA_NONCOLLAPSE){
HashMap< String,String> dataPayload = new HashMap<>();
dataPayload.put(contents,(--deleted--));
message.put(data,dataPayload);
}
//实际发送消息
try {
ccsServer.sendDownstreamMessage(JSONValue.toJSONString(message));
} catch(NotConnectedException enc){
msgs.logMessage(不再连接,echo消息不发送:+ enc.getMessage());
}
}
}
class BorderPanel扩展JPanel {
//(--deleted--)
}
public class GcmPushServer
{
//(--deleted--)
}
So, Google used to have a nice page where they gave code sample on how to implement a GCM Xmpp server on this page: https://developers.google.com/cloud-messaging/ccs
I had bookmarked this answer anytime I wanted to view the implementation Confused about Google GCM XMPP
But everything linked from in that answer is gone. Google deleted them.
But now, they have removed everything, and added a page that just explains what it does. Sure, but the sample java code would be nice. I tried to go to the sample site on github that they link to https://github.com/google/gcm
but it only provides samples of HTTP GCM server version.
Can somebody point me to a working code sample please? Or Is there a library out there that would work with c# at all? if not, I would just settle with the java version too.
Thanks.
Here is one I wrote for a class example (with some non-XMPP parts deleted to keep it small enough so I can post the code, but have the full server at http://people.eku.edu/styere/GcmPushServer.java):
// derived from https://developer.android.com/google/gcm/ccs.html
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
//import javax.swing.JScrollPane;
//import javax.swing.SwingUtilities;
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.JSONObject;
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.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Random;
import java.net.*;
import java.io.*;
import java.util.*;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.HttpsURLConnection;
// list of all users and associated devices
class UserList {
// (--deleted--)
// constructor/read existing data from file
public UserList() {
// (--deleted--)
}
// add a new device to an existing user (called from networking thread)
// duplicate IDs are quietly accepted
public synchronized void addDevice( String uname, String newRegToken ) {
// (--deleted--)
}
// generate a group address/notification key
// !!!!!!!!!!!!!!! W A R N I N G !!!!!!!!!!!!!!!
// If the group addr/notification key is lost, it currently CANNOT be recovered/rebuilt
public String createNotificationKey( String nKeyName, String addr ) {
String[] idset = new String[1];
idset[0] = addr;
String newGroupAddr;
try {
// create a https connection to create the notification_key
URL url = new URL( "https://android.googleapis.com/gcm/notification" );
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
// send as a POST request
conn.setRequestMethod("POST");
// add request parameters
conn.addRequestProperty( "project_id", ""+GcmPushServer.senderId );
conn.addRequestProperty( "Authorization", "key="+GcmPushServer.password );
// use "set" since this may already exist
conn.setRequestProperty( "Content-Type", "application/json" );
// create data to send with request
Map<String,Object> sendData = new HashMap<>();
// create a new notification key
sendData.put( "operation", "create" );
sendData.put( "notification_key_name", (--deleted--) );
sendData.put( "registration_ids", (--deleted--) );
String strData = JSONValue.toJSONString(sendData);
// Send post request
conn.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
wr.writeBytes( strData );
wr.flush();
wr.close();
// successful?
int rc = conn.getResponseCode();
//System.out.println("ResponseCode = " + rc );
// read the response
Scanner input = new Scanner( conn.getInputStream() );
String resp="";
// read/display lines
while( input.hasNextLine() ) {
String s = input.nextLine();
resp += s;
}
//System.out.println("Response content: " + resp);
if ( rc == HttpsURLConnection.HTTP_OK ) {
JSONObject obj = (JSONObject) JSONValue.parse(resp);
newGroupAddr = (String) obj.get( "notification_key" );
//System.out.println(" new notification_key: " + newGroupAddr );
return newGroupAddr;
} else {
}
} catch ( Exception e ) {
//System.out.println("-- Exception: " + e.getMessage() );
}
return null;
}
// add/delete a single address to/from a notification key
// (add if doAdd is true, delete otherwise)
// removing final address will quietly delete the key
public static void modifyNotificationKey( String nKeyName, String nKey,
String addr, boolean doAdd ) {
String[] idset = new String[1];
idset[0] = addr;
try {
// create a https connection to create the notification_key
URL url = new URL( "https://android.googleapis.com/gcm/notification" );
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
// send as a POST request
conn.setRequestMethod("POST");
// add request parameters
conn.addRequestProperty( "project_id", ""+GcmPushServer.senderId );
conn.addRequestProperty( "Authorization", "key="+GcmPushServer.password );
// use "set" since this may already exist
conn.setRequestProperty( "Content-Type", "application/json" );
// create data to send with request
Map<String,Object> sendData = new HashMap<>();
// create a new notification key
sendData.put( "operation", doAdd? "add" : "remove" ); // add or delete key?
sendData.put( "notification_key_name", (--deleted--) );
sendData.put( "notification_key", (--deleted--) );
sendData.put( "registration_ids", (--deleted--) );
String strData = JSONValue.toJSONString(sendData);
//System.out.println("genGroupAddress POST data: " + strData );
// Send post request
conn.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
wr.writeBytes( strData );
wr.flush();
wr.close();
//conn.openConnection();
// successful?
int rc = conn.getResponseCode();
//System.out.println("ResponseCode = " + rc );
Scanner input = new Scanner( conn.getInputStream() );
// read/display lines
while( input.hasNextLine() ) {
System.out.println("Response content:");
String s = input.nextLine();
System.out.println( s );
}
} catch ( Exception e ) {
// do nothing
}
}
}
// text area for log messages
class LogTextArea extends JTextArea {
// update the "log" with the specified message
public void logMessage( String msg ) {
// (--deleted--)
}
}
class CcsServer {
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";
// display/log area
LogTextArea logArea;
UserList users;
CcsServer( LogTextArea lta, UserList u ) {
logArea = lta;
users = u;
}
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;
}
logArea.logMessage("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");
// what type of upstream message is this?
if ( ! payload.containsKey( "my_action" ) )
{
// Hmmm - this shouldn't happen!
logArea.logMessage( "handleUpstreamMessage - incoming message is missing my_action" );
// just ignore the message
return;
}
// what action do they want?
String my_action = (String) payload.get( "my_action" );
if ( my_action.equals( "edu.eku.styere.gcmpushclient.REGISTER" ) ) {
// registration request
String username = (String) payload.get( "username" );
logArea.logMessage( "Registration request: user=" + username + ", ID/Token=" + from );
// save the information
users.addDevice( username, from );
return;
} else {
// take default action of echoing the message
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) {
logArea.logMessage( "Not connected anymore, echo message is not sent: " + e.getMessage() );
}
}
}
/**
* 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");
logArea.logMessage( "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");
logArea.logMessage( "handleNackReceipt() from: " + from + ", messageId: " + messageId );
}
protected void handleControlMessage(Map<String, Object> jsonObject) {
logArea.logMessage( "handleControlMessage(): " + jsonObject );
String controlType = (String) jsonObject.get("control_type");
if ("CONNECTION_DRAINING".equals(controlType)) {
connectionDraining = true;
} else {
logArea.logMessage( "Unrecognised control type: " + controlType + ". This could "+
"happen if new features are " + "added to the CCS protocol." );
}
}
/**
* 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) {
logArea.logMessage( "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 {
logArea.logMessage( "Unrecognised message type: " +
messageType.toString() );
}
} catch (ParseException e) {
logArea.logMessage( "Error parsing JSON " + json );
} catch (Exception e) {
logArea.logMessage( "Failed to process packet" );
}
}
}, new PacketTypeFilter(Message.class));
// Log all outgoing packets
connection.addPacketInterceptor(new PacketInterceptor() {
@Override
public void interceptPacket(Packet packet) {
logArea.logMessage( "Sent: " + packet.toXML());
}
}, new PacketTypeFilter(Message.class));
connection.login(senderId + "@gcm.googleapis.com", apiKey);
}
//---------- support classes ----------
/**
* XMPP Packet Extension for GCM Cloud Connection Server.
*/
private static 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;
}
}
class LoggingConnectionListener implements ConnectionListener {
@Override
public void connected(XMPPConnection xmppConnection) {
logArea.logMessage( "Connected." );
}
@Override
public void authenticated(XMPPConnection xmppConnection) {
logArea.logMessage( "Authenticated." );
}
@Override
public void reconnectionSuccessful() {
logArea.logMessage( "Reconnecting.." );
}
@Override
public void reconnectionFailed(Exception e) {
logArea.logMessage( "Reconnection failed.. " + e.getMessage() );
}
@Override
public void reconnectingIn(int seconds) {
logArea.logMessage( "Reconnecting in " + seconds + " secs" );
}
@Override
public void connectionClosedOnError(Exception e) {
logArea.logMessage( "Connection closed on error." );
}
@Override
public void connectionClosed() {
logArea.logMessage( "Connection closed." );
}
}
}
// a non-editable combo (drop-down) box for destination addresses
class DestComboBox extends JComboBox<String> {
// (deleted to save space)
}
// screen panel for sending a message
class SendMessagePanel extends JPanel implements ActionListener, ItemListener {
// Message Types
protected final int MSGTYPE_NOTIFICATION = 1;
protected final int MSGTYPE_NOTIFICATION_DATA = 2;
protected final int MSGTYPE_DATA_COLLAPSE = 3;
protected final int MSGTYPE_DATA_NONCOLLAPSE = 4;
// log window
LogTextArea msgs;
// server class
CcsServer ccsServer;
// constructor
SendMessagePanel( UserList u, LogTextArea m, CcsServer c ) {
// (deleted to save space)
}
// respond to the button
@Override
public void actionPerformed(ActionEvent e) {
String toAddr = "zzzzzz"; // destination address
// may be device, notification_key, or topic address
ttl = 2419200; // time-to-live in seconds
// what type of message?
int msgTypeIndex = (--deleted--);
// create the message
Map<String, Object> message = new HashMap<String, Object>();
message.put("to", toAddr);
if ( msgTypeIndex == MSGTYPE_NOTIFICATION ||
msgTypeIndex == MSGTYPE_NOTIFICATION_DATA ||
msgTypeIndex == MSGTYPE_DATA_COLLAPSE ) {
// create a collapse key
message.put("collapse_key", "ck"+msgTypeIndex );
}
message.put("time_to_live", ttl);
message.put("message_id", ccsServer.nextMessageId());
// notification included?
if ( msgTypeIndex == MSGTYPE_NOTIFICATION ||
msgTypeIndex == MSGTYPE_NOTIFICATION_DATA ) {
// create the notification payload
HashMap<String, String> notePayload = new HashMap<>();
notePayload.put( "title", "Gcm Push Message Example" );
notePayload.put( "body", (--deleted--) );
// identify which notifications should replace older versions
notePayload.put( "tag", "ntag" + msgTypeIndex );
notePayload.put( "icon", "@drawable/new_picture" ); // notification icon
// additional stuff if we also have data
if ( msgTypeIndex == MSGTYPE_NOTIFICATION_DATA ) {
// what to do when the user opens the notification
notePayload.put( "click_action", "OPEN_MAIN_ACTIVITY" );
}
message.put( "notification", notePayload );
}
// data included?
if ( msgTypeIndex == MSGTYPE_NOTIFICATION_DATA ||
msgTypeIndex == MSGTYPE_DATA_COLLAPSE ||
msgTypeIndex == MSGTYPE_DATA_NONCOLLAPSE ) {
HashMap<String, String> dataPayload = new HashMap<>();
dataPayload.put( "contents", (--deleted--) );
message.put("data", dataPayload);
}
// actually send the message
try {
ccsServer.sendDownstreamMessage( JSONValue.toJSONString(message) );
} catch (NotConnectedException enc ) {
msgs.logMessage( "Not connected anymore, echo message is not sent: " + enc.getMessage() );
}
}
}
class BorderPanel extends JPanel {
// (--deleted--)
}
public class GcmPushServer
{
// (--deleted--)
}
这篇关于Google GCM XMPP代码示例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!