android-pushNotification-消息推送-学习笔记

最近,公司有一个跟消息推送有关的项目,老大叫我做,也给了我国外的一个例子 androidpn,(下载地址http://sourceforge.net/projects/androidpn/),我想大家应该很熟悉,我自己下载后,直接解压后运行androidpn-server-0.5.0/bin/run.sh,当然这个是在linux下,windows则是run.bat,然后我解压了adnroidpn-client-0.5.0,用eclipce加载进去,修改project/res/raw/androidpn.properties文件里面的xmppHost,这个参数是你运行androidpn服务器的地址,改完直接运行,你可以在log里面看到客户端的工作信息(connect..login...等等);到这里你就可以用浏览器打开localhost:7070(如果服务器重启失败,看后面),你可以看到androidpn服务器的web界面,在Users里面显示了有登录过的帐号,Sessions里面是在线的帐号的信息,有IP,时间等,接下来就是Notifications,这个就是我们要的推送功能,这边可以选择对全体推送也可以对单用户进行推送。就这样,整个demo就演示完了。不过老大过来看了之后就说,“啊,这个能不能向QQ那样,做个用户树啊,显示在线用户,还有能不能发送文件啊”,我就是自己的想法,乱说一通,“额,这个应该可以的,就是每次登录的时候,让服务器在发送个文件过来,客户端接收并处理就好了,文件传输嘛,在开个端口,用那个什么FTP传或者HTTP下载下来...”,哈哈,我老大就不想多说什么了,你们懂的。老大走了之后我就继续埋头看资料了。


上面废话了一堆这边简单说下,androidpn运行流程:

1.androidpn-server-0.5.0/bin/run.sh

2.adnroidpn-client-0.5.0/res/raw/androidpn.properties (xmppHost=你服务器的IP)

3.运行adnroidpn-client-0.5.0

4.OK


看到一堆代码,我@_@ ing,过了好些天,我一直没有突破,我看了很多关于android消息推送的文章,有了点小突破,就算服务器端大致是在openfire平台修改而来,客户端和服务器通信是用XMPP协议,其中使用了SMACK这个库,这个我在看客户端源代码的时候也看到过,引用了很多org.jivesoftware.smack.*,有网友说XMPP协议里面客户端的运行很简单,麻烦的是服务器,所以我在回头认真看源代码,终于看到了核心了XmppManager,这个类里面做了很多事:链接服务器connection.connect(),给链接添加packetListener和PacketFilter,之后是登录connection.login();这些是比较关键的,其余的还有监听手机状态,重新链接,android Notification的弹出,还有一个我不清楚的IQProvider等,服务器没看,没有web编程经验,感觉看不来,当然理清了要重搭服务器还是要看的。看到这个突破口只有一个connection这个类,也就是XmppConnection,看了帮助手册,看了网上资料,这个类是最关键的,但是我还没法给其他人发送消息,即便我看到了Chat chat = connection.create("JID",MsgListener);,更不用说好友状态和发送文件了。对于好友状态我后来找到了roster这个类,当然还是没法得到在线好友,即使我在localhost:7070看到有好几个测试帐号都在线。。。我再次@_@ ing。其中有个小插曲让我有兴奋起来,那就是我可以登录我的gtalk,同时也可以获取好友信息,哇哈哈,这才像话嘛,经过了几番折腾,我在android-pn里面都没法获取,在看了文档(...Pluggable Roster Support Guide...),个人猜测是androidpn服务器没有配置roster,所以80%是想放弃这个DEMO了。

隔天,我便不想用这个DEMO了,我直接上http://xmpp.org/找例子,上面有好多server和client,我当然就找最近有看到的openfire(http://www.igniterealtime.org/),从openfire网站了解到已经有可用的服务器openfire和客户端Spark、Sparkweb还有smack库,我下载了release版本和用svn将整个源代码同步下来,经过测试,都OK哈,老大想要的功能这边都能实现,至于修改嘛,有源代码怕什么呢。在建立服务器的时候,你要先准备一个数据库用,服务器初始化用的,我用的是mysql,这个自己也就网上搜的,没什么难度的。


流程:

0.算是准备步骤吧,用Mysql建立一个数据库,当然你也可以建立其他类型的数据库了

1.解压release版的文件,执行openfire/bin/openfire.sh

2.打开浏览器,输入localhost:9090

3.按找提示初始化,填入之前建立的数据库,初始化数据库一个比较有趣的是千万不能写jdbc:mysql://[localhost]/[openfire_db]应该是jdbc:mysql://localhost/openfire_db我就搞了半天没弄明白,哈哈,水货一个啊

4.解压release版的Spark,运行./Spark,要是出出错再运行starter下,我也忘了这个是干嘛的,有点初始化的感觉。

5.你可以看到Spark的界面,点击注册,当然也可要在服务器直接添加帐号,输入用户名,服务器和密码后,点击login就登录啦。万一你linux是中文语言,这时候界面的文字可能会显示异常,我会在下面发一张界面给大家参考,登录后修改语言就没事了(软件的菜单Action->languages->English)。

6.这样就好了,想怎么测试就怎么测试去吧。

7.如果你想重新初始化openfire服务器,那就修改openfire/conf/openfire.xml文件,去掉倒数第二句<setup>true</setup>,或者删掉<connection...> </setup>,有必要的话也把数据库删了mysqladmin drop databasenam -p ,然后从0开始。


利用这个openfire平台,我先建立java prcj,调用smack库,这边的测试很简单,在这边我按照samck的documentation进行列出流程。

// Create the configuration for this new connection
ConnectionConfiguration config = new ConnectionConfiguration("jabber.org", 5222);
config.setCompressionEnabled(true); //可能你在android项目会无法登录openfire服务器,那就把这两项set false,我是根据log这样处理的
config.setSASLAuthenticationEnabled(true);

Connection connection = new XMPPConnection(config);//这边就是根据那个config创建链接
// Connect to the server
connection.connect();//链接到服务器
// Log into the server
connection.login("username", "password", "SomeResource");//登录~~~当然前提是你有帐号了,这边可先在服务器(http://localhost:9090/user-summary.jsp)申请,后面会有代码用于申请帐号,据资料记载"SomeResource"是用于判断同一帐号不同客户端登录。
//注意如果你这边没有界面,也就所程序一下就跑完了,你要加个while死循环,不然链接一下就断了,你在服务器就看不到登录状态的。
// Disconnect from the server
connection.disconnect();//断开链接

 
 
到这边,都还没实现androidpn的推送功能呢,不过你看下服务器,你就会发现服务器的会话栏也就是session栏里面有个工具/tool,点进去你会发现这个是用来发送管理信息的,那肯定是可以发给所有人啦,随便输些文字后发送,Spark和SparkWeb都能接收到,而你的程序不行~~,嗯嗯,根据文档,你需要加入包监听器和包过滤器,方法如下:
connection.addPacketListener(new PacketListener() {
	@Override
	public void processPacket(Packet packet) {
	// TODO Auto-generated method stub
	   //这边对收到的包进行处理
	}
  }, new PacketFilter() {
        @Override
	public boolean accept(Packet packet) {
	// TODO Auto-generated method stub
	   return false; //改成return true; 传来什么包就收什么包
	}
});
官网给出了更好的例子,只接收来自特定用户的包,(PacketCollector本人还没用到,就不说了)
// Create a packet filter to listen for new messages from a particular
// user. We use an AndFilter to combine two other filters.
PacketFilter filter = new AndFilter(new PacketTypeFilter(Message.class), 
        new FromContainsFilter("mary@jivesoftware.com"));
// Assume we've created a Connection name "connection".

// First, register a packet collector using the filter we created.
PacketCollector myCollector = connection.createPacketCollector(filter);
// Normally, you'd do something with the collector, like wait for new packets.

// Next, create a packet listener. We use an anonymous inner class for brevity.
PacketListener myListener = new PacketListener() {
        public void processPacket(Packet packet) {
            // Do something with the incoming packet here.
        }
    };
// Register the listener.
connection.addPacketListener(myListener, filter);

服务器能发消息客户端当然也要能发消息给服务器了。来点官网的原汁原味的东西吧。
Each message to the XMPP server from a client is called a packet and is sent as XML. The org.jivesoftware.smack.packet package contains classes that encapsulate the three different basic packet types allowed by XMPP (message, presence, and IQ). Classes such as Chat and GroupChat provide higher-level constructs that manage creating and sending packets automatically, but you can also create and send packets directly. 
翻译:每个从客户端发送给服务器的消息叫做包,同时是以XML形式发送的。在org.jivesoftware.smack.packet包里面的类封装了三个被XMPP协议允许的不同的基本包(message, presence, and IQ)。比如Chat和GroupChat这些类提供了高级的架构用于管理自动创建和发送包,但是我们也可以直接创建和发送包,而不使用一些高度封装的类。
下面这个就是发送一个Presence包用于更新自己的状态。
Presence presence = new Presence(Presence.Type.unavailable);
presence.setStatus("Gone fishing");
// Send the packet (assume we have a Connection instance called "con").
con.sendPacket(presence);
message 和 IQ 将于后面讲到。

能收到服务器的推送了,那接下来就是获取好友的状态,那就是花名册Roster,代码如下:

Roster roster = connection.getRoster(); //这个要在login之后获取,不然获取不到花名册
//1.
Collection<RosterEntry> entries = roster.getEntries();
for (RosterEntry entry : entries) {
    System.out.println(entry.getUser());
}


加入代码运行后,你会发现,一个user都没,我也一样,不过我在gtalk测试并不是这样,我能得到结果,

后来我就在1.处加入了  roster.createEntry("admin@xxxxxxxx", "admin", null); 把他加入你的花名册就好了,应该是说你没有好友,那花名册就是空的嘛,有点废话,不过这边你加进去后服务器同时也保存了你的roster在服务器上,下次登录后就能获取到了。当然这边加好友只是单方面加好友,后面有种是询问对方是否同意还有就是让对方也加自己为好友。对于花名册,从服务器->用户/组->你的帐号->Roster可以看到一个SubScription的项,意思是订阅,就是加好友的关系,你订阅了对方的信息,那他就是好友,这样你就能收到來至服务器的好友状态更新信息。

现在能获取花名册了,当然就想着能实时同步好友状态嘛,RosterListener也就这样诞生了(官网提示最好在login前就添加Listener),使用如下,

roster.addRosterListener(new RosterListener() {
    // Ignored events public void entriesAdded(Collection<String> addresses) {}
    public void entriesDeleted(Collection<String> addresses) {}    
    public void entriesUpdated(Collection<String> addresses) {}
    public void presenceChanged(Presence presence) {
        System.out.println("Presence changed: " + presence.getFrom() + " " + presence);
    }
});

看监听器里面的函数名称就能知道这个函数是干嘛的,所以不解释了,这个有可能会出现对方更新了,而你收不到更新信息的情况,那很有可能是因为roster是在login之前就申请了,我就是遇到这样的情况,移到login后面就好了。


现在花名册能获取,也能同步好友状态了,那接下来就是对话功能啦,简单点说就是发送信息给对方,然后对方回复等。这些都是简单的。(给自己的提示,每个用户应该都要一个Listener。多用户的情况下怎么处理,还有一种情况就是不加好友状态时的对话),当然不是上面的Chat chat = connection.create("JID",MsgListener);这样。

// Assume we've created a Connection name "connection".
ChatManager chatmanager = connection.getChatManager(); //这边加入了一个ChatManager
Chat newChat = chatmanager.createChat("jsmith@jivesoftware.com", new MessageListener() { 
    public void processMessage(Chat chat, Message message) { // 这边也有一个chat,这个就是newChat了,这个就像BroadcastReceiver的onRecevie(Context c,Intent i)一样
        System.out.println("Received message: " + message.getBody(););   //接收消息
    }
});
try {
    newChat.sendMessage("Howdy!");   //发送消息
//   or
    Message newMessage = new Message(); 
    newMessage.setBody("Howdy!");     //发送消息
    message.setProperty("favoriteColor", "red");
    newChat.sendMessage(newMessage); 
}
catch (XMPPException e) {
    System.out.println("Error Delivering block");
}

有来有回,那对话也就形成了,就像上面给我自己的提示,不可能每个用户都加一个Listener吧,开发者肯定也想到了,所以又加入了ChatManagerListener,如下:

ChatManager chatmanager = connection.getChatManager().addChatListener(
 new ChatManagerListener() {
     @Override
     public void chatCreated(Chat chat, boolean createdLocally)
     {
         if (!createdLocally)
             chat.addMessageListener(new MyNewMessageListener());;
     }
 });

至于和谁聊天嘛,chat.getParticipant()可以得到聊天对方的JID,JAVADOC里面是写着“Returns the name of the user the chat is with. ”,这样就可以分别处理了。


还不是最后,但是也是一个很重要的东西,那就是文件传输,这边还没测试,就此先搁笔。

原文我放http://download.csdn.net/detail/shmcclmm/4923948

后面还要记录IQ这个东西。

PacketCollector也还没测试。


(转载请注明原文地址:http://blog.csdn.net/shmcclmm/article/details/8425151)

需要的东西: androidpn,openfire,Spark,smack,ant,mysql,jdk,如果是编译androidpn源码,用 maven..


# 对于想重启androidpn服务器失败,被提示Address is already used还是什么的,看提示可以猜到是端口被占用了,可以用 lsof | grep 查看是那个进程占用了该端口,然后用kill -9 PID杀掉这个进程就好了。

输入命令 lsof,系统输出如下: 

COMMAND     PID       USER   FD      TYPE     DEVICE    SIZE/OFF       NODE NAME

....


#小插曲,相关代码

XMPPConnection connection = new XMPPConnection(new ConnectionConfiguration("talk.google.com",5222,"google.com"));
connection.login("xxxxxxx@gmail.com", "***********"); //帐号+密码
......
chat = connection.getChatManager().createChat("xxx对方帐号xxx@gmail.com", new MessageListener() {
@Override
public void processMessage(Chat arg0, Message arg1) {
// TODO Auto-generated method stub
System.out.println(arg1.getBody());

}
});
try {
chat.sendMessage(arg1.getBody());
} catch (XMPPException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


#Spark 界面,当然也可以直接使用Spakrweb客户端啦









  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值