Android实现推送PushService通知Notification

请先参考: Android推送通知指南

这里使用了IBM提供的MQTT协议实现了推送。有一个wmqtt.jar包需要导入到工程,见附件。

然后编写PushService类实现一个服务,其中有个内部类:
MQTTConnection 实现了 MqttSimpleCallback接口,重写其中的publishArrived方法,我这里是当接受到推送的数据后显示一个Notification,点击该Notification后跳转到一个Activity上。
具体看PushService类,关键的地方我都用中文字说明了:
Java代码 复制代码  收藏代码
  1. package com.ata.push;   
  2.   
  3. import org.json.JSONException;   
  4. import org.json.JSONObject;   
  5.   
  6. import android.R;   
  7. import android.app.AlarmManager;   
  8. import android.app.Notification;   
  9. import android.app.NotificationManager;   
  10. import android.app.PendingIntent;   
  11. import android.app.Service;   
  12. import android.content.BroadcastReceiver;   
  13. import android.content.Context;   
  14. import android.content.Intent;   
  15. import android.content.IntentFilter;   
  16. import android.content.SharedPreferences;   
  17. import android.net.ConnectivityManager;   
  18. import android.net.NetworkInfo;   
  19. import android.os.IBinder;   
  20. import android.util.Log;   
  21.   
  22. import com.ata.view.NewMesageInfoActivity;   
  23. import com.ibm.mqtt.IMqttClient;   
  24. import com.ibm.mqtt.MqttClient;   
  25. import com.ibm.mqtt.MqttException;   
  26. import com.ibm.mqtt.MqttPersistence;   
  27. import com.ibm.mqtt.MqttPersistenceException;   
  28. import com.ibm.mqtt.MqttSimpleCallback;   
  29.   
  30. /*   
  31.  * PushService that does all of the work.  
  32.  * Most of the logic is borrowed from KeepAliveService.  
  33.  * http://code.google.com/p/android-random/source/browse/trunk/TestKeepAlive/src/org/devtcg/demo/keepalive/KeepAliveService.java?r=219  
  34.  */  
  35. public class PushService extends Service   
  36. {   
  37.     // this is the log tag   
  38.     public static final String      TAG = "PushService";   
  39.   
  40.     // the IP address, where your MQTT broker is running.   
  41.     private static final String     MQTT_HOST = "172.16.26.41";//需要改成服务器IP   
  42.     // the port at which the broker is running.    
  43.     private static int              MQTT_BROKER_PORT_NUM      = 1883;//需要改成服务器port   
  44.     // Let's not use the MQTT persistence.   
  45.     private static MqttPersistence  MQTT_PERSISTENCE          = null;   
  46.     // We don't need to remember any state between the connections, so we use a clean start.    
  47.     private static boolean          MQTT_CLEAN_START          = true;   
  48.     // Let's set the internal keep alive for MQTT to 15 mins. I haven't tested this value much. It could probably be increased.   
  49.     private static short            MQTT_KEEP_ALIVE           = 60 * 15;   
  50.     // Set quality of services to 0 (at most once delivery), since we don't want push notifications    
  51.     // arrive more than once. However, this means that some messages might get lost (delivery is not guaranteed)   
  52.     private static int[]            MQTT_QUALITIES_OF_SERVICE = { 0 } ;   
  53.     private static int              MQTT_QUALITY_OF_SERVICE   = 0;   
  54.     // The broker should not retain any messages.   
  55.     private static boolean          MQTT_RETAINED_PUBLISH     = false;   
  56.            
  57.     // MQTT client ID, which is given the broker. In this example, I also use this for the topic header.    
  58.     // You can use this to run push notifications for multiple apps with one MQTT broker.    
  59.     public static String            MQTT_CLIENT_ID = "ata";//需要改成自己需要的名称   
  60.   
  61.     // These are the actions for the service (name are descriptive enough)   
  62.     private static final String     ACTION_START = MQTT_CLIENT_ID + ".START";   
  63.     private static final String     ACTION_STOP = MQTT_CLIENT_ID + ".STOP";   
  64.     private static final String     ACTION_KEEPALIVE = MQTT_CLIENT_ID + ".KEEP_ALIVE";   
  65.     private static final String     ACTION_RECONNECT = MQTT_CLIENT_ID + ".RECONNECT";   
  66.        
  67.     // Connection log for the push service. Good for debugging.   
  68.     //private ConnectionLog             mLog;   
  69.        
  70.     // Connectivity manager to determining, when the phone loses connection   
  71.     private ConnectivityManager     mConnMan;   
  72.     // Notification manager to displaying arrived push notifications    
  73.     private NotificationManager     mNotifMan;   
  74.   
  75.     // Whether or not the service has been started.    
  76.     private boolean                 mStarted;   
  77.   
  78.     // This the application level keep-alive interval, that is used by the AlarmManager   
  79.     // to keep the connection active, even when the device goes to sleep.   
  80.     private static final long       KEEP_ALIVE_INTERVAL = 1000 * 60 * 28;   
  81.   
  82.     // Retry intervals, when the connection is lost.   
  83.     private static final long       INITIAL_RETRY_INTERVAL = 1000 * 10;   
  84.     private static final long       MAXIMUM_RETRY_INTERVAL = 1000 * 60 * 30;   
  85.   
  86.     // Preferences instance    
  87.     private SharedPreferences       mPrefs;   
  88.     // We store in the preferences, whether or not the service has been started   
  89.     //判断Service是否已经启动,不要重复启动!   
  90.     public static final String      PREF_STARTED = "isStarted";   
  91.     // We also store the deviceID (target)   
  92.     //需要提供手机设备号,该设备号应该事先保存在SharedPreferences中   
  93.     public static final String      PREF_DEVICE_ID = "deviceID";   
  94.     // We store the last retry interval   
  95.     public static final String      PREF_RETRY = "retryInterval";   
  96.   
  97.     // Notification title   
  98.     public static String            NOTIF_TITLE = "ata"//需要改成自己需要的title      
  99.     // Notification id   
  100.     private static final int        NOTIF_CONNECTED = 0;       
  101.            
  102.     // This is the instance of an MQTT connection.   
  103.     private MQTTConnection          mConnection;   
  104.     private long                    mStartTime;   
  105.        
  106.   
  107.     // Static method to start the service   
  108.     //在需要的地方直接调用该方法就启动监听了   
  109.     public static void actionStart(Context ctx) {   
  110.         Intent i = new Intent(ctx, PushService.class);   
  111.         i.setAction(ACTION_START);   
  112.         ctx.startService(i);   
  113.     }   
  114.   
  115.     // Static method to stop the service   
  116.     public static void actionStop(Context ctx) {   
  117.         Intent i = new Intent(ctx, PushService.class);   
  118.         i.setAction(ACTION_STOP);   
  119.         ctx.startService(i);   
  120.     }   
  121.        
  122.     // Static method to send a keep alive message   
  123.     public static void actionPing(Context ctx) {   
  124.         Intent i = new Intent(ctx, PushService.class);   
  125.         i.setAction(ACTION_KEEPALIVE);   
  126.         ctx.startService(i);   
  127.     }   
  128.   
  129.     @Override  
  130.     public void onCreate() {   
  131.         super.onCreate();   
  132.            
  133.         log("Creating service");   
  134.         mStartTime = System.currentTimeMillis();   
  135.   
  136.         /*try {  
  137.             //mLog = new ConnectionLog();  
  138.             //Log.i(TAG, "Opened log at " + mLog.getPath());  
  139.         } catch (IOException e) {  
  140.             Log.e(TAG, "Failed to open log", e);  
  141.         }*/  
  142.   
  143.         // Get instances of preferences, connectivity manager and notification manager   
  144.         mPrefs = getSharedPreferences(TAG, MODE_PRIVATE);   
  145.         mConnMan = (ConnectivityManager)getSystemService(CONNECTIVITY_SERVICE);   
  146.         mNotifMan = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);   
  147.        
  148.         /* If our process was reaped by the system for any reason we need  
  149.          * to restore our state with merely a call to onCreate.  We record  
  150.          * the last "started" value and restore it here if necessary. */  
  151.         handleCrashedService();   
  152.     }   
  153.        
  154.     // This method does any necessary clean-up need in case the server has been destroyed by the system   
  155.     // and then restarted   
  156.     private void handleCrashedService() {   
  157.         if (wasStarted() == true) {   
  158.             log("Handling crashed service...");   
  159.              // stop the keep alives   
  160.             stopKeepAlives();    
  161.                    
  162.             // Do a clean start   
  163.             start();   
  164.         }   
  165.     }   
  166.        
  167.     @Override  
  168.     public void onDestroy() {   
  169.         log("Service destroyed (started=" + mStarted + ")");   
  170.   
  171.         // Stop the services, if it has been started   
  172.         if (mStarted == true) {   
  173.             stop();   
  174.         }   
  175.            
  176.     /*  try {  
  177.             if (mLog != null)  
  178.                 mLog.close();  
  179.         } catch (IOException e) {}      */  
  180.     }   
  181.        
  182.     @Override  
  183.     public void onStart(Intent intent, int startId) {   
  184.         super.onStart(intent, startId);   
  185.         log("Service started with intent=" + intent);   
  186.   
  187.         // Do an appropriate action based on the intent.   
  188.         if (intent.getAction().equals(ACTION_STOP) == true) {   
  189.             stop();   
  190.             stopSelf();   
  191.         } else if (intent.getAction().equals(ACTION_START) == true) {   
  192.             start();   
  193.         } else if (intent.getAction().equals(ACTION_KEEPALIVE) == true) {   
  194.             keepAlive();   
  195.         } else if (intent.getAction().equals(ACTION_RECONNECT) == true) {   
  196.             if (isNetworkAvailable()) {   
  197.                 reconnectIfNecessary();   
  198.             }   
  199.         }   
  200.     }   
  201.        
  202.     @Override  
  203.     public IBinder onBind(Intent intent) {   
  204.         return null;   
  205.     }   
  206.   
  207.     // log helper function   
  208.     private void log(String message) {   
  209.         log(message, null);   
  210.     }   
  211.     private void log(String message, Throwable e) {   
  212.         if (e != null) {   
  213.             Log.e(TAG, message, e);   
  214.                
  215.         } else {   
  216.             Log.i(TAG, message);               
  217.         }   
  218.            
  219.         /*if (mLog != null)  
  220.         {  
  221.             try {  
  222.                 mLog.println(message);  
  223.             } catch (IOException ex) {}  
  224.         }       */  
  225.     }   
  226.        
  227.     // Reads whether or not the service has been started from the preferences   
  228.     private boolean wasStarted() {   
  229.         return mPrefs.getBoolean(PREF_STARTED, false);   
  230.     }   
  231.   
  232.     // Sets whether or not the services has been started in the preferences.   
  233.     private void setStarted(boolean started) {   
  234.         mPrefs.edit().putBoolean(PREF_STARTED, started).commit();          
  235.         mStarted = started;   
  236.     }   
  237.   
  238.     private synchronized void start() {   
  239.         log("Starting service...");   
  240.            
  241.         // Do nothing, if the service is already running.   
  242.         if (mStarted == true) {   
  243.             Log.w(TAG, "Attempt to start connection that is already active");   
  244.             return;   
  245.         }   
  246.            
  247.         // Establish an MQTT connection   
  248.         connect();   
  249.            
  250.         // Register a connectivity listener   
  251.         registerReceiver(mConnectivityChanged, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));         
  252.     }   
  253.   
  254.     private synchronized void stop() {   
  255.         // Do nothing, if the service is not running.   
  256.         if (mStarted == false) {   
  257.             Log.w(TAG, "Attempt to stop connection not active.");   
  258.             return;   
  259.         }   
  260.   
  261.         // Save stopped state in the preferences   
  262.         setStarted(false);   
  263.   
  264.         // Remove the connectivity receiver   
  265.         unregisterReceiver(mConnectivityChanged);   
  266.         // Any existing reconnect timers should be removed, since we explicitly stopping the service.   
  267.         cancelReconnect();   
  268.   
  269.         // Destroy the MQTT connection if there is one   
  270.         if (mConnection != null) {   
  271.             mConnection.disconnect();   
  272.             mConnection = null;   
  273.         }   
  274.     }   
  275.        
  276.     //    
  277.     private synchronized void connect() {          
  278.         log("Connecting...");   
  279.         // fetch the device ID from the preferences.   
  280.         String deviceID = mPrefs.getString(PREF_DEVICE_ID, null);   
  281.         // Create a new connection only if the device id is not NULL   
  282.         if (deviceID == null) {   
  283.             log("Device ID not found.");   
  284.         } else {   
  285.             try {   
  286.                 mConnection = new MQTTConnection(MQTT_HOST, deviceID);   
  287.             } catch (MqttException e) {   
  288.                 // Schedule a reconnect, if we failed to connect   
  289.                 log("MqttException: " + (e.getMessage() != null ? e.getMessage() : "NULL"));   
  290.                 if (isNetworkAvailable()) {   
  291.                     scheduleReconnect(mStartTime);   
  292.                 }   
  293.             }   
  294.             setStarted(true);   
  295.         }   
  296.     }   
  297.   
  298.     private synchronized void keepAlive() {   
  299.         try {   
  300.             // Send a keep alive, if there is a connection.   
  301.             if (mStarted == true && mConnection != null) {   
  302.                 mConnection.sendKeepAlive();   
  303.             }   
  304.         } catch (MqttException e) {   
  305.             log("MqttException: " + (e.getMessage() != null? e.getMessage(): "NULL"), e);   
  306.                
  307.             mConnection.disconnect();   
  308.             mConnection = null;   
  309.             cancelReconnect();   
  310.         }   
  311.     }   
  312.   
  313.     // Schedule application level keep-alives using the AlarmManager   
  314.     private void startKeepAlives() {   
  315.         Intent i = new Intent();   
  316.         i.setClass(this, PushService.class);   
  317.         i.setAction(ACTION_KEEPALIVE);   
  318.         PendingIntent pi = PendingIntent.getService(this0, i, 0);   
  319.         AlarmManager alarmMgr = (AlarmManager)getSystemService(ALARM_SERVICE);   
  320.         alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP,   
  321.           System.currentTimeMillis() + KEEP_ALIVE_INTERVAL,   
  322.           KEEP_ALIVE_INTERVAL, pi);   
  323.     }   
  324.   
  325.     // Remove all scheduled keep alives   
  326.     private void stopKeepAlives() {   
  327.         Intent i = new Intent();   
  328.         i.setClass(this, PushService.class);   
  329.         i.setAction(ACTION_KEEPALIVE);   
  330.         PendingIntent pi = PendingIntent.getService(this0, i, 0);   
  331.         AlarmManager alarmMgr = (AlarmManager)getSystemService(ALARM_SERVICE);   
  332.         alarmMgr.cancel(pi);   
  333.     }   
  334.   
  335.     // We schedule a reconnect based on the starttime of the service   
  336.     public void scheduleReconnect(long startTime) {   
  337.         // the last keep-alive interval   
  338.         long interval = mPrefs.getLong(PREF_RETRY, INITIAL_RETRY_INTERVAL);   
  339.   
  340.         // Calculate the elapsed time since the start   
  341.         long now = System.currentTimeMillis();   
  342.         long elapsed = now - startTime;   
  343.   
  344.   
  345.         // Set an appropriate interval based on the elapsed time since start    
  346.         if (elapsed < interval) {   
  347.             interval = Math.min(interval * 4, MAXIMUM_RETRY_INTERVAL);   
  348.         } else {   
  349.             interval = INITIAL_RETRY_INTERVAL;   
  350.         }   
  351.            
  352.         log("Rescheduling connection in " + interval + "ms.");   
  353.   
  354.         // Save the new internval   
  355.         mPrefs.edit().putLong(PREF_RETRY, interval).commit();   
  356.   
  357.         // Schedule a reconnect using the alarm manager.   
  358.         Intent i = new Intent();   
  359.         i.setClass(this, PushService.class);   
  360.         i.setAction(ACTION_RECONNECT);   
  361.         PendingIntent pi = PendingIntent.getService(this0, i, 0);   
  362.         AlarmManager alarmMgr = (AlarmManager)getSystemService(ALARM_SERVICE);   
  363.         alarmMgr.set(AlarmManager.RTC_WAKEUP, now + interval, pi);   
  364.     }   
  365.        
  366.     // Remove the scheduled reconnect   
  367.     public void cancelReconnect() {   
  368.         Intent i = new Intent();   
  369.         i.setClass(this, PushService.class);   
  370.         i.setAction(ACTION_RECONNECT);   
  371.         PendingIntent pi = PendingIntent.getService(this0, i, 0);   
  372.         AlarmManager alarmMgr = (AlarmManager)getSystemService(ALARM_SERVICE);   
  373.         alarmMgr.cancel(pi);   
  374.     }   
  375.        
  376.     private synchronized void reconnectIfNecessary() {         
  377.         if (mStarted == true && mConnection == null) {   
  378.             log("Reconnecting...");   
  379.             connect();   
  380.         }   
  381.     }   
  382.   
  383.     // This receiver listeners for network changes and updates the MQTT connection   
  384.     // accordingly   
  385.     private BroadcastReceiver mConnectivityChanged = new BroadcastReceiver() {   
  386.         @Override  
  387.         public void onReceive(Context context, Intent intent) {   
  388.             // Get network info   
  389.             NetworkInfo info = (NetworkInfo)intent.getParcelableExtra (ConnectivityManager.EXTRA_NETWORK_INFO);   
  390.                
  391.             // Is there connectivity?   
  392.             boolean hasConnectivity = (info != null && info.isConnected()) ? true : false;   
  393.   
  394.             log("Connectivity changed: connected=" + hasConnectivity);   
  395.   
  396.             if (hasConnectivity) {   
  397.                 reconnectIfNecessary();   
  398.             } else if (mConnection != null) {   
  399.                 // if there no connectivity, make sure MQTT connection is destroyed   
  400.                 mConnection.disconnect();   
  401.                 cancelReconnect();   
  402.                 mConnection = null;   
  403.             }   
  404.         }   
  405.     };   
  406.        
  407.     // Display the topbar notification   
  408.     private void showNotification(String content) {   
  409.         Notification n = new Notification();   
  410.                    
  411.         n.flags |= Notification.FLAG_SHOW_LIGHTS;   
  412.         n.flags |= Notification.FLAG_AUTO_CANCEL;   
  413.   
  414.         n.defaults = Notification.DEFAULT_ALL;   
  415.            
  416.         n.icon = R.drawable.ic_dialog_info;   
  417.         n.when = System.currentTimeMillis();   
  418.   
  419.         Log.i("PushService""json==="+content);   
  420.         String alert=null;   
  421.         String id=null;   
  422.         try {   
  423.             JSONObject json = new JSONObject(content);   
  424.             alert = json.optString("alert");   
  425.             id = json.optString("id");   
  426.         } catch (JSONException e) {   
  427.             // TODO Auto-generated catch block   
  428.             e.printStackTrace();   
  429.         }   
  430.            
  431.         Intent intent = new Intent(this,NewMesageInfoActivity.class);          
  432.         intent.putExtra("url""http://testing.portal.ataudc.com/message/"+id);   
  433.         intent.putExtra("id", id);   
  434.         PendingIntent pi = PendingIntent.getActivity(this0,intent, PendingIntent.FLAG_ONE_SHOT);   
  435.         // Change the name of the notification here   
  436.         n.setLatestEventInfo(this, NOTIF_TITLE, alert, pi);   
  437.   
  438.         mNotifMan.notify(NOTIF_CONNECTED, n);   
  439.     }   
  440.        
  441.     // Check if we are online   
  442.     private boolean isNetworkAvailable() {   
  443.         NetworkInfo info = mConnMan.getActiveNetworkInfo();   
  444.         if (info == null) {   
  445.             return false;   
  446.         }   
  447.         return info.isConnected();   
  448.     }   
  449.        
  450.     // This inner class is a wrapper on top of MQTT client.   
  451.     private class MQTTConnection implements MqttSimpleCallback {   
  452.         IMqttClient mqttClient = null;   
  453.            
  454.         // Creates a new connection given the broker address and initial topic   
  455.         public MQTTConnection(String brokerHostName, String initTopic) throws MqttException {   
  456.             // Create connection spec   
  457.             String mqttConnSpec = "tcp://" + brokerHostName + "@" + MQTT_BROKER_PORT_NUM;   
  458.                 // Create the client and connect   
  459.                 mqttClient = MqttClient.createMqttClient(mqttConnSpec, MQTT_PERSISTENCE);   
  460.                 String clientID = MQTT_CLIENT_ID + "/" + mPrefs.getString(PREF_DEVICE_ID, "");   
  461.                 mqttClient.connect(clientID, MQTT_CLEAN_START, MQTT_KEEP_ALIVE);   
  462.   
  463.                 // register this client app has being able to receive messages   
  464.                 mqttClient.registerSimpleHandler(this);   
  465.                    
  466.                 // Subscribe to an initial topic, which is combination of client ID and device ID.   
  467.                 initTopic = MQTT_CLIENT_ID + "/" + initTopic;   
  468.                 subscribeToTopic(initTopic);   
  469.            
  470.                 log("Connection established to " + brokerHostName + " on topic " + initTopic);   
  471.            
  472.                 // Save start time   
  473.                 mStartTime = System.currentTimeMillis();   
  474.                 // Star the keep-alives   
  475.                 startKeepAlives();                         
  476.         }   
  477.            
  478.         // Disconnect   
  479.         public void disconnect() {   
  480.             try {              
  481.                 stopKeepAlives();   
  482.                 mqttClient.disconnect();   
  483.             } catch (MqttPersistenceException e) {   
  484.                 log("MqttException" + (e.getMessage() != null? e.getMessage():" NULL"), e);   
  485.             }   
  486.         }   
  487.         /*  
  488.          * Send a request to the message broker to be sent messages published with   
  489.          *  the specified topic name. Wildcards are allowed.      
  490.          */  
  491.         private void subscribeToTopic(String topicName) throws MqttException {   
  492.                
  493.             if ((mqttClient == null) || (mqttClient.isConnected() == false)) {   
  494.                 // quick sanity check - don't try and subscribe if we don't have   
  495.                 //  a connection   
  496.                 log("Connection error" + "No connection");     
  497.             } else {                                       
  498.                 String[] topics = { topicName };   
  499.                 mqttClient.subscribe(topics, MQTT_QUALITIES_OF_SERVICE);   
  500.             }   
  501.         }      
  502.         /*  
  503.          * Sends a message to the message broker, requesting that it be published  
  504.          *  to the specified topic.  
  505.          */  
  506.         private void publishToTopic(String topicName, String message) throws MqttException {           
  507.             if ((mqttClient == null) || (mqttClient.isConnected() == false)) {   
  508.                 // quick sanity check - don't try and publish if we don't have   
  509.                 //  a connection                   
  510.                 log("No connection to public to");         
  511.             } else {   
  512.                 mqttClient.publish(topicName,    
  513.                                    message.getBytes(),   
  514.                                    MQTT_QUALITY_OF_SERVICE,    
  515.                                    MQTT_RETAINED_PUBLISH);   
  516.             }   
  517.         }          
  518.            
  519.         /*  
  520.          * Called if the application loses it's connection to the message broker.  
  521.          */  
  522.         public void connectionLost() throws Exception {   
  523.             log("Loss of connection" + "connection downed");   
  524.             stopKeepAlives();   
  525.             // null itself   
  526.             mConnection = null;   
  527.             if (isNetworkAvailable() == true) {   
  528.                 reconnectIfNecessary();    
  529.             }   
  530.         }          
  531.            
  532.         /*  
  533.          * Called when we receive a message from the message broker.   
  534.          * 在这里处理服务器推送过来的数据  
  535.          */  
  536.         public void publishArrived(String topicName, byte[] payload, int qos, boolean retained) {   
  537.             // Show a notification   
  538.             String s = new String(payload);   
  539.             showNotification(s);       
  540.         }      
  541.            
  542.         public void sendKeepAlive() throws MqttException {   
  543.             log("Sending keep alive");   
  544.             // publish to a keep-alive topic   
  545.             publishToTopic(MQTT_CLIENT_ID + "/keepalive", mPrefs.getString(PREF_DEVICE_ID, ""));   
  546.         }          
  547.     }   
  548. }  
package com.ata.push;

import org.json.JSONException;
import org.json.JSONObject;

import android.R;
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;

import com.ata.view.NewMesageInfoActivity;
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;

/* 
 * 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 = "PushService";

	// the IP address, where your MQTT broker is running.
	private static final String		MQTT_HOST = "172.16.26.41";//需要改成服务器IP
	// the port at which the broker is running. 
	private static int				MQTT_BROKER_PORT_NUM      = 1883;//需要改成服务器port
	// 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 = "ata";//需要改成自己需要的名称

	// 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
	//判断Service是否已经启动,不要重复启动!
	public static final String		PREF_STARTED = "isStarted";
	// We also store the deviceID (target)
	//需要提供手机设备号,该设备号应该事先保存在SharedPreferences中
	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 = "ata"; //需要改成自己需要的title  	
	// 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 content) {
		Notification n = new Notification();
				
		n.flags |= Notification.FLAG_SHOW_LIGHTS;
      	n.flags |= Notification.FLAG_AUTO_CANCEL;

        n.defaults = Notification.DEFAULT_ALL;
      	
		n.icon = R.drawable.ic_dialog_info;
		n.when = System.currentTimeMillis();

		Log.i("PushService", "json==="+content);
		String alert=null;
		String id=null;
		try {
			JSONObject json = new JSONObject(content);
			alert = json.optString("alert");
			id = json.optString("id");
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		Intent intent = new Intent(this,NewMesageInfoActivity.class);		
		intent.putExtra("url", "http://testing.portal.ataudc.com/message/"+id);
		intent.putExtra("id", id);
		PendingIntent pi = PendingIntent.getActivity(this, 0,intent, PendingIntent.FLAG_ONE_SHOT);
		// Change the name of the notification here
		n.setLatestEventInfo(this, NOTIF_TITLE, alert, 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);	
		}   
		
		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, ""));
		}		
	}
}


PushService是根据你的设备号来准确定位你的手机的,它是从SharedPreferences取得该设备号的,所以你得事先将你的设备号保存在SharedPreferences中,如下:
Java代码 复制代码  收藏代码
  1. class PushTask extends AsyncTask<Void, Integer, Boolean> {   
  2.   
  3.         @Override  
  4.         protected Boolean doInBackground(Void... params) {   
  5.             // 启动PUSH服务   
  6.             Editor editor = getSharedPreferences(PushService.TAG, MODE_PRIVATE)   
  7.                     .edit();   
  8. String deviceID = Secure.getString(getContentResolver(),Secure.ANDROID_ID);   
  9.             editor.putString(PushService.PREF_DEVICE_ID, deviceID);   
  10.             editor.commit();   
  11.             try {   
  12.                 PushService.actionStart(getApplicationContext());   
  13.             } catch (Exception e) {   
  14.                 // TODO: handle exception   
  15. //              Log.i(tag, "启动PUSH服务失败.");   
  16.                 return false;   
  17.             }   
  18.             return true;   
  19.         }   
  20.   
  21.         @Override  
  22.         protected void onCancelled() {   
  23.             super.onCancelled();   
  24.         }   
  25.   
  26.         @Override  
  27.         protected void onPostExecute(Boolean result) {   
  28.             Log.i(tag, result?"启动PUSH服务成功.":"启动PUSH服务失败.");   
  29.         }   
  30.   
  31.         @Override  
  32.         protected void onPreExecute() {   
  33.             // 预处理   
  34.         }   
  35.   
  36.         @Override  
  37.         protected void onProgressUpdate(Integer... values) {   
  38.             // 更新进度   
  39.         }   
  40.     }  
class PushTask extends AsyncTask<Void, Integer, Boolean> {

		@Override
		protected Boolean doInBackground(Void... params) {
			// 启动PUSH服务
			Editor editor = getSharedPreferences(PushService.TAG, MODE_PRIVATE)
					.edit();
String deviceID = Secure.getString(getContentResolver(),Secure.ANDROID_ID);
			editor.putString(PushService.PREF_DEVICE_ID, deviceID);
			editor.commit();
			try {
				PushService.actionStart(getApplicationContext());
			} catch (Exception e) {
				// TODO: handle exception
//				Log.i(tag, "启动PUSH服务失败.");
				return false;
			}
			return true;
		}

		@Override
		protected void onCancelled() {
			super.onCancelled();
		}

		@Override
		protected void onPostExecute(Boolean result) {
			Log.i(tag, result?"启动PUSH服务成功.":"启动PUSH服务失败.");
		}

		@Override
		protected void onPreExecute() {
			// 预处理
		}

		@Override
		protected void onProgressUpdate(Integer... values) {
			// 更新进度
		}
	}

Java代码 复制代码  收藏代码
  1. PushTask task=new PushTask();   
  2. task.execute();  
PushTask task=new PushTask();
task.execute();

如果要关闭服务,只需要将下面的代码添加到想要的地方:
Java代码 复制代码  收藏代码
  1. PushService.actionStop(getApplicationContext());  
PushService.actionStop(getApplicationContext());

至于服务器端代码,我们使用php写的,这里请参考 Android推送通知指南

另一篇关于推送:
Android Push Notification实现信息推送使用
http://www.cnblogs.com/hanyonglu/archive/2012/03/16/2399655.html
http://www.apkbus.com/android-48367-1-1.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值