歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Android實現推送PushService通知Notification

Android實現推送PushService通知Notification

日期:2017/3/1 10:19:52   编辑:Linux編程

請先參考:Android推送通知指南 http://www.linuxidc.com/Linux/2011-10/45373.htm

這裡使用了IBM提供的MQTT協議實現了推送。有一個wmqtt.jar包需要導入到工程,見附件。

然後編寫PushService類實現一個服務,其中有個內部類:
MQTTConnection 實現了 MqttSimpleCallback接口,重寫其中的publishArrived方法,我這裡是當接受到推送的數據後顯示一個Notification,點擊該Notification後跳轉到一個Activity上。
具體看PushService類,關鍵的地方我都用中文字說明了:

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

PushService是根據你的設備號來准確定位你的手機的,它是從SharedPreferences取得該設備號的,所以你得事先將你的設備號保存在SharedPreferences中,如下:

  1. //啟動PUSH服務
  2. mDeviceID = Secure.getString(this.getContentResolver(), Secure.ANDROID_ID);
  3. Editor editor = getSharedPreferences(PushService.TAG, MODE_PRIVATE).edit();
  4. editor.putString(PushService.PREF_DEVICE_ID, mDeviceID);
  5. editor.commit();
  6. Log.i("tag", "mDeviceID====="+mDeviceID);
  7. PushService.actionStart(getApplicationContext());

將上面的代碼寫在需要的Activity中即可。至於服務器端代碼,我們使用php寫的,這裡請參考Android推送通知指南 http://www.linuxidc.com/Linux/2011-10/45373.htm

代碼下載

免費下載地址在 http://linux.linuxidc.com/

用戶名與密碼都是www.linuxidc.com

具體下載目錄在 /2012年資料/6月/13日/Android實現推送PushService通知Notification/

Copyright © Linux教程網 All Rights Reserved