终于又开始上班了,只有在值班的时候,才是我比较清闲的时候,可以静下来做自己喜欢的事情,看自己喜欢的文章,写自己喜欢的博客。在Android架构部分,几个比较难啃的骨头里面,Android Push Notification Service算一个。我想今天来解释一下她的实现以及使用。
1 这个服务的必要性问题
在手机的使用过程中,我们知道,正睡觉呢,突然响起了短信声,打开一看,原来是移动/电信在提醒我们该上厕所了,或者天边冷了,多穿点衣服吧之类的话语。而在使用Android手机的时候,我们发现,如果有Gmail端,收到邮件的时候,会弹出一个提示,你有一条新邮件,并包含邮件的标题和相关信息。不知道你会不会好奇,这是如何实现的呢?我很好奇,所以便有了此文的写作动机。而对于QQ、安卓市场之类的软件,时不时的也弹出来这类信息,相信大家可以明白,这东西应该是有点用处的。比如我们开发一款应用,需要实时的提醒我们的安装用户一些事情,相信,你就会明白,这个服务是很有必要的,相信,在未来移动互联网、物联网占据大片江山的时候,也是很有必要的。
2 几个问题
好了,我们提出了这个东西的必要性,但是在做的时候,我们必须要考虑几个问题。
2.1 俺的电池不怎么抗用,可千万别太耗我的电量啊,这是哥最在意的啊。
2.2 除了花点流量,这玩意不要花我另外的钱,我可是月光族啊。
2.3 我着急要收到这个消息,别半小时后才把消息发给我,那样的话,会损失我的订单的。
2.4 必须要可靠哦,别用着用着,不好使了。
秉着以上的几个关键问题,我们开始了下一部分的探讨了。
3 几种可能的方案
我们来思考一下,要实现实时得到信息,有哪几种方法呢?
1 通过http/https或者其他协议,客户端以服务的方式,每隔10分钟或者10秒钟,向服务器请求一次,服务器判断这段时间是否有新消息,需要发给客户端,如果有就通过json或者xml方式发给客户端。
2 通过短信的方式,服务器端通过SMS的方式,将所需要的消息及时发送回来。
3 使用tcp长连接和心跳包的机制,实现数据定时推送。
4 采用的方案
从我的能力,我目前只能想到这么几种办法,下面我们来根据第二条里面的准则来分析上面提到的几种方案。
第一条通过http或者https的方式,向服务器每隔多长时间请求一次的方式,的确可以实现我们的功能,但是违反了我们的2.1和2.3原则。首先这种方式会耗电,当然你可以说时间设置长一点,但是这样又违背了2.3原则。所以这条一般是不会被采纳的。除非某些特殊应用。
第二条呢,2.1、2.3、2.4都符合,可是,违背了2.2,所以我们也不会考虑的。
第三条呢,好像全部符合,但是有一个小问题在里面,就是如果以Service的方式进行,由于Android系统的特殊性,在内存不够用的时候,会主动结束一些服务,这个服务包括了我们的定义服务,这么说,他违背了2.4。
但是,我们还是有办法的。
5 被采用方案的可实施方法
在Android 2.2以后,Google放出了C2DM【Android Cloud to Device Messaging Framework】服务,从服务的使用方法上,我们就可以明白他们采用了第三种方式。
随着他们推出这个服务后,很多公司开始基于这个服务做一些应用,如推送广告、推送定制信息等。如xtify和airpush等,国内也有一些企业加入了这种阵营,如单独提供服务的push-notification,当然QQ也有这样的服务存在。
在这种方案里面,有几个细节地方,需要来解释一下。
5.1 传输的时候使用什么协议?
5.2 传输的时候如何保证数据的安全性?
5.3 对于多平台,多用户的push如何保证惟一性?
5.4 服务器端的如何部署?
5.1的问题目前有几种方式,使用xmpp协议、IBM的MQTT、自定义协议。 目前有一些开源的项目中,大都采用第一种和第二种,当然,如果有特殊需求,可以采取自定义协议的。
5.2的问题可以对数据进行可逆加密。
5.3的问题,一般是将手机的ID传递到服务器端进行惟一性验证。
5.4的问题,服务器端可以自己使用任何语言开发,也可以使用Nginx + 脚本语言部署。
6 实例说明
本文的实例采用了mqtt的架构,完全按照tokudu兄的文章而来,并成功实现了。里面采取的不是IBM的Really Small Message Broker,而是采用的开源Mosquitto实现,
准备工作:
6.1 Android真机,本文为三星I809
6.2 Apache + Php环境
6.3 tokudu兄的Android源代码
6.4 tukudu兄的php代码
6.5 mosquitto的可执行程序。
步骤1:
下载mosquitto的可执行程序,我选择的是cygwin版本的,安装后,进入目录双击mosquitto.exe执行即可。
步骤2:下载tokudu兄的php代码,官方地址为:https://github.com/tokudu/PhpMQTTClient
我这里也提供下载:androidpushservice
主要代码为如下:
- <?php
- require('SAM/php_sam.php');
- //create a new connection object
- $conn = new SAMConnection();
- //start initialise the connection
- $conn->connect(SAM_MQTT, array(SAM_HOST => '202.198.21.131',
- SAM_PORT => 1883));
- //create a new MQTT message with the output of the shell command as the body
- $msgCpu = new SAMMessage($_REQUEST['message']);
- //send the message on the topic cpu
- $conn->send('topic://'.$_REQUEST['target'], $msgCpu);
- $conn->disconnect();
- echo 'MQTT Message to ' . $_REQUEST['target'] . ' sent: ' . $_REQUEST['message'];
- ?>
将代码部署到php环境目录里面。输入地址:http://localhost/androidpushservice/
步骤三:下载tokudu兄的android代码:
地址:https://github.com/tokudu/AndroidPushNotificationsDemo
本文提供下载:
tokudu-AndroidPushNotificationsDemo-ea18b09
这里有一个Device Target号码需要在php的界面里面输入。才可以发送成功。
- /*
- * $Id$
- */
- package com.tokudu.demo;
- import java.io.BufferedWriter;
- import java.io.File;
- import java.io.FileWriter;
- import java.io.IOException;
- import java.io.Writer;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- import android.os.Environment;
- public class ConnectionLog
- {
- private String mPath;
- private Writer mWriter;
- private static final SimpleDateFormat TIMESTAMP_FMT =
- new SimpleDateFormat("[HH:mm:ss] ");
- public ConnectionLog()
- throws IOException
- {
- File sdcard = Environment.getExternalStorageDirectory();
- File logDir = new File(sdcard, "tokudu/log/");
- if (!logDir.exists()) {
- logDir.mkdirs();
- // do not allow media scan
- new File(logDir, ".nomedia").createNewFile();
- }
- open(logDir.getAbsolutePath() + "/push.log");
- }
- public ConnectionLog(String basePath)
- throws IOException
- {
- open(basePath);
- }
- protected void open(String basePath)
- throws IOException
- {
- File f = new File(basePath + "-" + getTodayString());
- mPath = f.getAbsolutePath();
- mWriter = new BufferedWriter(new FileWriter(mPath), 2048);
- println("Opened log.");
- }
- private static String getTodayString()
- {
- SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd-hhmmss");
- return df.format(new Date());
- }
- public String getPath()
- {
- return mPath;
- }
- public void println(String message)
- throws IOException
- {
- mWriter.write(TIMESTAMP_FMT.format(new Date()));
- mWriter.write(message);
- mWriter.write('\n');
- mWriter.flush();
- }
- public void close()
- throws IOException
- {
- mWriter.close();
- }
- }
- <span style="font-family:Arial, Helvetica, sans-serif;"><span style="white-space: normal;">
- </span></span>
- <span style="font-family:Arial, Helvetica, sans-serif;"><span style="white-space: normal;"></span></span><pre name="code" class="java">package com.tokudu.demo;
- import java.io.IOException;
- import com.ibm.mqtt.IMqttClient;
- import com.ibm.mqtt.MqttClient;
- import com.ibm.mqtt.MqttException;
- import com.ibm.mqtt.MqttPersistence;
- import com.ibm.mqtt.MqttPersistenceException;
- import com.ibm.mqtt.MqttSimpleCallback;
- import android.app.AlarmManager;
- import android.app.Notification;
- import android.app.NotificationManager;
- import android.app.PendingIntent;
- import android.app.Service;
- import android.content.BroadcastReceiver;
- import android.content.Context;
- import android.content.Intent;
- import android.content.IntentFilter;
- import android.content.SharedPreferences;
- import android.net.ConnectivityManager;
- import android.net.NetworkInfo;
- import android.os.IBinder;
- import android.util.Log;
- /*
- * PushService that does all of the work.
- * Most of the logic is borrowed from KeepAliveService.
- * http://code.google.com/p/android-random/source/browse/trunk/TestKeepAlive/src/org/devtcg/demo/keepalive/KeepAliveService.java?r=219
- */
- public class PushService extends Service
- {
- // this is the log tag
- public static final String TAG = "DemoPushService";
- // the IP address, where your MQTT broker is running.
- private static final String MQTT_HOST = "88.88.88.111";
- // the port at which the broker is running.
- private static int MQTT_BROKER_PORT_NUM = 1883;
- // Let's not use the MQTT persistence.
- private static MqttPersistence MQTT_PERSISTENCE = null;
- // We don't need to remember any state between the connections, so we use a clean start.
- private static boolean MQTT_CLEAN_START = true;
- // Let's set the internal keep alive for MQTT to 15 mins. I haven't tested this value much. It could probably be increased.
- private static short MQTT_KEEP_ALIVE = 60 * 15;
- // Set quality of services to 0 (at most once delivery), since we don't want push notifications
- // arrive more than once. However, this means that some messages might get lost (delivery is not guaranteed)
- private static int[] MQTT_QUALITIES_OF_SERVICE = { 0 } ;
- private static int MQTT_QUALITY_OF_SERVICE = 0;
- // The broker should not retain any messages.
- private static boolean MQTT_RETAINED_PUBLISH = false;
- // MQTT client ID, which is given the broker. In this example, I also use this for the topic header.
- // You can use this to run push notifications for multiple apps with one MQTT broker.
- public static String MQTT_CLIENT_ID = "tokudu";
- // These are the actions for the service (name are descriptive enough)
- private static final String ACTION_START = MQTT_CLIENT_ID + ".START";
- private static final String ACTION_STOP = MQTT_CLIENT_ID + ".STOP";
- private static final String ACTION_KEEPALIVE = MQTT_CLIENT_ID + ".KEEP_ALIVE";
- private static final String ACTION_RECONNECT = MQTT_CLIENT_ID + ".RECONNECT";
- // Connection log for the push service. Good for debugging.
- private ConnectionLog mLog;
- // Connectivity manager to determining, when the phone loses connection
- private ConnectivityManager mConnMan;
- // Notification manager to displaying arrived push notifications
- private NotificationManager mNotifMan;
- // Whether or not the service has been started.
- private boolean mStarted;
- // This the application level keep-alive interval, that is used by the AlarmManager
- // to keep the connection active, even when the device goes to sleep.
- private static final long KEEP_ALIVE_INTERVAL = 1000 * 60 * 28;
- // Retry intervals, when the connection is lost.
- private static final long INITIAL_RETRY_INTERVAL = 1000 * 10;
- private static final long MAXIMUM_RETRY_INTERVAL = 1000 * 60 * 30;
- // Preferences instance
- private SharedPreferences mPrefs;
- // We store in the preferences, whether or not the service has been started
- public static final String PREF_STARTED = "isStarted";
- // We also store the deviceID (target)
- public static final String PREF_DEVICE_ID = "deviceID";
- // We store the last retry interval
- public static final String PREF_RETRY = "retryInterval";
- // Notification title
- public static String NOTIF_TITLE = "Tokudu";
- // Notification id
- private static final int NOTIF_CONNECTED = 0;
- // This is the instance of an MQTT connection.
- private MQTTConnection mConnection;
- private long mStartTime;
- // Static method to start the service
- public static void actionStart(Context ctx) {
- Intent i = new Intent(ctx, PushService.class);
- i.setAction(ACTION_START);
- ctx.startService(i);
- }
- // Static method to stop the service
- public static void actionStop(Context ctx) {
- Intent i = new Intent(ctx, PushService.class);
- i.setAction(ACTION_STOP);
- ctx.startService(i);
- }
- // Static method to send a keep alive message
- public static void actionPing(Context ctx) {
- Intent i = new Intent(ctx, PushService.class);
- i.setAction(ACTION_KEEPALIVE);
- ctx.startService(i);
- }
- @Override
- public void onCreate() {
- super.onCreate();
- log("Creating service");
- mStartTime = System.currentTimeMillis();
- try {
- mLog = new ConnectionLog();
- Log.i(TAG, "Opened log at " + mLog.getPath());
- } catch (IOException e) {
- Log.e(TAG, "Failed to open log", e);
- }
- // Get instances of preferences, connectivity manager and notification manager
- mPrefs = getSharedPreferences(TAG, MODE_PRIVATE);
- mConnMan = (ConnectivityManager)getSystemService(CONNECTIVITY_SERVICE);
- mNotifMan = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
- /* If our process was reaped by the system for any reason we need
- * to restore our state with merely a call to onCreate. We record
- * the last "started" value and restore it here if necessary. */
- handleCrashedService();
- }
- // This method does any necessary clean-up need in case the server has been destroyed by the system
- // and then restarted
- private void handleCrashedService() {
- if (wasStarted() == true) {
- log("Handling crashed service...");
- // stop the keep alives
- stopKeepAlives();
- // Do a clean start
- start();
- }
- }
- @Override
- public void onDestroy() {
- log("Service destroyed (started=" + mStarted + ")");
- // Stop the services, if it has been started
- if (mStarted == true) {
- stop();
- }
- try {
- if (mLog != null)
- mLog.close();
- } catch (IOException e) {}
- }
- @Override
- public void onStart(Intent intent, int startId) {
- super.onStart(intent, startId);
- log("Service started with intent=" + intent);
- // Do an appropriate action based on the intent.
- if (intent.getAction().equals(ACTION_STOP) == true) {
- stop();
- stopSelf();
- } else if (intent.getAction().equals(ACTION_START) == true) {
- start();
- } else if (intent.getAction().equals(ACTION_KEEPALIVE) == true) {
- keepAlive();
- } else if (intent.getAction().equals(ACTION_RECONNECT) == true) {
- if (isNetworkAvailable()) {
- reconnectIfNecessary();
- }
- }
- }
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
- // log helper function
- private void log(String message) {
- log(message, null);
- }
- private void log(String message, Throwable e) {
- if (e != null) {
- Log.e(TAG, message, e);
- } else {
- Log.i(TAG, message);
- }
- if (mLog != null)
- {
- try {
- mLog.println(message);
- } catch (IOException ex) {}
- }
- }
- // Reads whether or not the service has been started from the preferences
- private boolean wasStarted() {
- return mPrefs.getBoolean(PREF_STARTED, false);
- }
- // Sets whether or not the services has been started in the preferences.
- private void setStarted(boolean started) {
- mPrefs.edit().putBoolean(PREF_STARTED, started).commit();
- mStarted = started;
- }
- private synchronized void start() {
- log("Starting service...");
- // Do nothing, if the service is already running.
- if (mStarted == true) {
- Log.w(TAG, "Attempt to start connection that is already active");
- return;
- }
- // Establish an MQTT connection
- connect();
- // Register a connectivity listener
- registerReceiver(mConnectivityChanged, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
- }
- private synchronized void stop() {
- // Do nothing, if the service is not running.
- if (mStarted == false) {
- Log.w(TAG, "Attempt to stop connection not active.");
- return;
- }
- // Save stopped state in the preferences
- setStarted(false);
- // Remove the connectivity receiver
- unregisterReceiver(mConnectivityChanged);
- // Any existing reconnect timers should be removed, since we explicitly stopping the service.
- cancelReconnect();
- // Destroy the MQTT connection if there is one
- if (mConnection != null) {
- mConnection.disconnect();
- mConnection = null;
- }
- }
- //
- private synchronized void connect() {
- log("Connecting...");
- // fetch the device ID from the preferences.
- String deviceID = mPrefs.getString(PREF_DEVICE_ID, null);
- // Create a new connection only if the device id is not NULL
- if (deviceID == null) {
- log("Device ID not found.");
- } else {
- try {
- mConnection = new MQTTConnection(MQTT_HOST, deviceID);
- } catch (MqttException e) {
- // Schedule a reconnect, if we failed to connect
- log("MqttException: " + (e.getMessage() != null ? e.getMessage() : "NULL"));
- if (isNetworkAvailable()) {
- scheduleReconnect(mStartTime);
- }
- }
- setStarted(true);
- }
- }
- private synchronized void keepAlive() {
- try {
- // Send a keep alive, if there is a connection.
- if (mStarted == true && mConnection != null) {
- mConnection.sendKeepAlive();
- }
- } catch (MqttException e) {
- log("MqttException: " + (e.getMessage() != null? e.getMessage(): "NULL"), e);
- mConnection.disconnect();
- mConnection = null;
- cancelReconnect();
- }
- }
- // Schedule application level keep-alives using the AlarmManager
- private void startKeepAlives() {
- Intent i = new Intent();
- i.setClass(this, PushService.class);
- i.setAction(ACTION_KEEPALIVE);
- PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
- AlarmManager alarmMgr = (AlarmManager)getSystemService(ALARM_SERVICE);
- alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP,
- System.currentTimeMillis() + KEEP_ALIVE_INTERVAL,
- KEEP_ALIVE_INTERVAL, pi);
- }
- // Remove all scheduled keep alives
- private void stopKeepAlives() {
- Intent i = new Intent();
- i.setClass(this, PushService.class);
- i.setAction(ACTION_KEEPALIVE);
- PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
- AlarmManager alarmMgr = (AlarmManager)getSystemService(ALARM_SERVICE);
- alarmMgr.cancel(pi);
- }
- // We schedule a reconnect based on the starttime of the service
- public void scheduleReconnect(long startTime) {
- // the last keep-alive interval
- long interval = mPrefs.getLong(PREF_RETRY, INITIAL_RETRY_INTERVAL);
- // Calculate the elapsed time since the start
- long now = System.currentTimeMillis();
- long elapsed = now - startTime;
- // Set an appropriate interval based on the elapsed time since start
- if (elapsed < interval) {
- interval = Math.min(interval * 4, MAXIMUM_RETRY_INTERVAL);
- } else {
- interval = INITIAL_RETRY_INTERVAL;
- }
- log("Rescheduling connection in " + interval + "ms.");
- // Save the new internval
- mPrefs.edit().putLong(PREF_RETRY, interval).commit();
- // Schedule a reconnect using the alarm manager.
- Intent i = new Intent();
- i.setClass(this, PushService.class);
- i.setAction(ACTION_RECONNECT);
- PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
- AlarmManager alarmMgr = (AlarmManager)getSystemService(ALARM_SERVICE);
- alarmMgr.set(AlarmManager.RTC_WAKEUP, now + interval, pi);
- }
- // Remove the scheduled reconnect
- public void cancelReconnect() {
- Intent i = new Intent();
- i.setClass(this, PushService.class);
- i.setAction(ACTION_RECONNECT);
- PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
- AlarmManager alarmMgr = (AlarmManager)getSystemService(ALARM_SERVICE);
- alarmMgr.cancel(pi);
- }
- private synchronized void reconnectIfNecessary() {
- if (mStarted == true && mConnection == null) {
- log("Reconnecting...");
- connect();
- }
- }
- // This receiver listeners for network changes and updates the MQTT connection
- // accordingly
- private BroadcastReceiver mConnectivityChanged = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- // Get network info
- NetworkInfo info = (NetworkInfo)intent.getParcelableExtra (ConnectivityManager.EXTRA_NETWORK_INFO);
- // Is there connectivity?
- boolean hasConnectivity = (info != null && info.isConnected()) ? true : false;
- log("Connectivity changed: connected=" + hasConnectivity);
- if (hasConnectivity) {
- reconnectIfNecessary();
- } else if (mConnection != null) {
- // if there no connectivity, make sure MQTT connection is destroyed
- mConnection.disconnect();
- cancelReconnect();
- mConnection = null;
- }
- }
- };
- // Display the topbar notification
- private void showNotification(String text) {
- Notification n = new Notification();
- n.flags |= Notification.FLAG_SHOW_LIGHTS;
- n.flags |= Notification.FLAG_AUTO_CANCEL;
- n.defaults = Notification.DEFAULT_ALL;
- n.icon = com.tokudu.demo.R.drawable.icon;
- n.when = System.currentTimeMillis();
- // Simply open the parent activity
- PendingIntent pi = PendingIntent.getActivity(this, 0,
- new Intent(this, PushActivity.class), 0);
- // Change the name of the notification here
- n.setLatestEventInfo(this, NOTIF_TITLE, text, pi);
- mNotifMan.notify(NOTIF_CONNECTED, n);
- }
- // Check if we are online
- private boolean isNetworkAvailable() {
- NetworkInfo info = mConnMan.getActiveNetworkInfo();
- if (info == null) {
- return false;
- }
- return info.isConnected();
- }
- // This inner class is a wrapper on top of MQTT client.
- private class MQTTConnection implements MqttSimpleCallback {
- IMqttClient mqttClient = null;
- // Creates a new connection given the broker address and initial topic
- public MQTTConnection(String brokerHostName, String initTopic) throws MqttException {
- // Create connection spec
- String mqttConnSpec = "tcp://" + brokerHostName + "@" + MQTT_BROKER_PORT_NUM;
- // Create the client and connect
- mqttClient = MqttClient.createMqttClient(mqttConnSpec, MQTT_PERSISTENCE);
- String clientID = MQTT_CLIENT_ID + "/" + mPrefs.getString(PREF_DEVICE_ID, "");
- mqttClient.connect(clientID, MQTT_CLEAN_START, MQTT_KEEP_ALIVE);
- // register this client app has being able to receive messages
- mqttClient.registerSimpleHandler(this);
- // Subscribe to an initial topic, which is combination of client ID and device ID.
- initTopic = MQTT_CLIENT_ID + "/" + initTopic;
- subscribeToTopic(initTopic);
- log("Connection established to " + brokerHostName + " on topic " + initTopic);
- // Save start time
- mStartTime = System.currentTimeMillis();
- // Star the keep-alives
- startKeepAlives();
- }
- // Disconnect
- public void disconnect() {
- try {
- stopKeepAlives();
- mqttClient.disconnect();
- } catch (MqttPersistenceException e) {
- log("MqttException" + (e.getMessage() != null? e.getMessage():" NULL"), e);
- }
- }
- /*
- * Send a request to the message broker to be sent messages published with
- * the specified topic name. Wildcards are allowed.
- */
- private void subscribeToTopic(String topicName) throws MqttException {
- if ((mqttClient == null) || (mqttClient.isConnected() == false)) {
- // quick sanity check - don't try and subscribe if we don't have
- // a connection
- log("Connection error" + "No connection");
- } else {
- String[] topics = { topicName };
- mqttClient.subscribe(topics, MQTT_QUALITIES_OF_SERVICE);
- }
- }
- /*
- * Sends a message to the message broker, requesting that it be published
- * to the specified topic.
- */
- private void publishToTopic(String topicName, String message) throws MqttException {
- if ((mqttClient == null) || (mqttClient.isConnected() == false)) {
- // quick sanity check - don't try and publish if we don't have
- // a connection
- log("No connection to public to");
- } else {
- mqttClient.publish(topicName,
- message.getBytes(),
- MQTT_QUALITY_OF_SERVICE,
- MQTT_RETAINED_PUBLISH);
- }
- }
- /*
- * Called if the application loses it's connection to the message broker.
- */
- public void connectionLost() throws Exception {
- log("Loss of connection" + "connection downed");
- stopKeepAlives();
- // null itself
- mConnection = null;
- if (isNetworkAvailable() == true) {
- reconnectIfNecessary();
- }
- }
- /*
- * Called when we receive a message from the message broker.
- */
- public void publishArrived(String topicName, byte[] payload, int qos, boolean retained) {
- // Show a notification
- String s = new String(payload);
- showNotification(s);
- log("Got message: " + s);
- }
- public void sendKeepAlive() throws MqttException {
- log("Sending keep alive");
- // publish to a keep-alive topic
- publishToTopic(MQTT_CLIENT_ID + "/keepalive", mPrefs.getString(PREF_DEVICE_ID, ""));
- }
- }
- }</pre><br>
- <br>
- <span style="color:#ff0000"><strong>7 代码下载</strong></span>
- <pre></pre>
- <pre name="code" class="java"><span style="color:#ff0000"><strong><a href="http://doandroid.info/wp-content/uploads/2012/03/tokudu-AndroidPushNotificationsDemo-ea18b09.zip">tokudu-AndroidPushNotifications</a></strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong><a href="http://doandroid.info/wp-content/uploads/2012/03/tokudu-AndroidPushNotificationsDemo-ea18b09.zip">Demo-ea18b09</a><a href="http://doandroid.info/wp-content/uploads/2012/03/androidpushservice.rar">androidpushservice</a></strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>MQTT实现:http://mosquitto.org/download/</strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>8 尾声我们目前已经完成了整个功能,如果要商业使用,还有一些问题摆在我们面前,如连接数的问题,大并发的问题,Apikey的问题等等。我们也会在tokudu兄的基础上,尝试完善一下,在这里对tokudu兄致以深深的敬意。</strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>参考文章:</strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>1 http://tokudu.com/2010/how-to-implement-push-notifications-for-android/【主参考】</strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>2 http://sourceforge.net/projects/androidpn/</strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>3 http://blog.mediarain.com/2011/03/simple-google-android-c2dm-tutorial-push-notifications-for-android/</strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>4 http://mosquitto.org/download/</strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>5 http://hi.baidu.com/zhu410289616/blog/item/b697f5328b0c405fad4b5f83.html</strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>6 http://blog.youkuaiyun.com/joshua_yu/article/details/6563587</strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>7 http://blog.mediarain.com/2011/03/simple-google-android-c2dm-tutorial-push-notifications-for-android/</strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>8 http://www.codeproject.com/Articles/339162/Android-push-notification-implementation-using-ASP</strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>9 http://www.eoeandroid.com/thread-97603-1-1.html</strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>10 https://www14.software.ibm.com/webapp/iwm/web/reg/acceptLogin.do?source=AW-0U9&lang=en_US</strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>11 http://mosquitto.org/</strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>12 https://github.com/tokudu/AndroidPushNotificationsDemo</strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>13 http://code.google.com/intl/zh-CN/android/c2dm/</strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>14 http://stackoverflow.com/questions/1378671/push-notifications-in-android-platform</strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>15 http://dalelane.co.uk/blog/?p=938</strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>16 http://mqtt.org/</strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>17 http://stackoverflow.com/questions/1243066/does-android-support-near-real-time-push-notification</strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>18 http://www.chengyunfeng.com/2010/09/android-push-notification</strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>19 http://www.airpush.com/</strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>-END-</strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>
- </strong></span></pre><pre name="code" class="java"><span style="color:#ff0000"><strong>本文同发地址:http://doandroid.info/2012/03/03/android-push-service/</strong></span><p></p><p></p><pre></pre>
- <pre></pre>
- </pre>