请先参考:
Android推送通知指南
这里使用了IBM提供的MQTT协议实现了推送。有一个wmqtt.jar包需要导入到工程,见附件。
然后编写PushService类实现一个服务,其中有个内部类:
MQTTConnection 实现了 MqttSimpleCallback接口,重写其中的publishArrived方法,我这里是当接受到推送的数据后显示一个Notification,点击该Notification后跳转到一个Activity上。
具体看PushService类,关键的地方我都用中文字说明了:
PushService是根据你的设备号来准确定位你的手机的,它是从SharedPreferences取得该设备号的,所以你得事先将你的设备号保存在SharedPreferences中,如下:
如果要关闭服务,只需要将下面的代码添加到想要的地方:
至于服务器端代码,我们使用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
这里使用了IBM提供的MQTT协议实现了推送。有一个wmqtt.jar包需要导入到工程,见附件。
然后编写PushService类实现一个服务,其中有个内部类:
MQTTConnection 实现了 MqttSimpleCallback接口,重写其中的publishArrived方法,我这里是当接受到推送的数据后显示一个Notification,点击该Notification后跳转到一个Activity上。
具体看PushService类,关键的地方我都用中文字说明了:
- 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, ""));
- }
- }
- }
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中,如下:
- 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) {
- // 更新进度
- }
- }
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) {
// 更新进度
}
}
- PushTask task=new PushTask();
- task.execute();
PushTask task=new PushTask();
task.execute();
如果要关闭服务,只需要将下面的代码添加到想要的地方:
- 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