乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      構建Android Push Notification Service服務端及客戶端[含代碼] - 48 views

       香山早秋 2012-03-24

      終于又開始上班了,只有在值班的時候,才是我比較清閑的時候,可以靜下來做自己喜歡的事情,看自己喜歡的文章,寫自己喜歡的博客。在Android架構部分,幾個比較難啃的骨頭里面,Android Push Notification Service算一個。我想今天來解釋一下她的實現(xiàn)以及使用。

      1 這個服務的必要性問題

      在手機的使用過程中,我們知道,正睡覺呢,突然響起了短信聲,打開一看,原來是移動/電信在提醒我們該上廁所了,或者天邊冷了,多穿點衣服吧之類的話語。而在使用Android手機的時候,我們發(fā)現(xiàn),如果有Gmail端,收到郵件的時候,會彈出一個提示,你有一條新郵件,并包含郵件的標題和相關信息。不知道你會不會好奇,這是如何實現(xiàn)的呢?我很好奇,所以便有了此文的寫作動機。而對于QQ、安卓市場之類的軟件,時不時的也彈出來這類信息,相信大家可以明白,這東西應該是有點用處的。比如我們開發(fā)一款應用,需要實時的提醒我們的安裝用戶一些事情,相信,你就會明白,這個服務是很有必要的,相信,在未來移動互聯(lián)網(wǎng)、物聯(lián)網(wǎng)占據(jù)大片江山的時候,也是很有必要的。

      2 幾個問題
      好了,我們提出了這個東西的必要性,但是在做的時候,我們必須要考慮幾個問題。
      2.1 俺的電池不怎么抗用,可千萬別太耗我的電量啊,這是哥最在意的啊。
      2.2 除了花點流量,這玩意不要花我另外的錢,我可是月光族啊。
      2.3 我著急要收到這個消息,別半小時后才把消息發(fā)給我,那樣的話,會損失我的訂單的。
      2.4 必須要可靠哦,別用著用著,不好使了。

      秉著以上的幾個關鍵問題,我們開始了下一部分的探討了。

      3 幾種可能的方案
      我們來思考一下,要實現(xiàn)實時得到信息,有哪幾種方法呢?
      1 通過http/https或者其他協(xié)議,客戶端以服務的方式,每隔10分鐘或者10秒鐘,向服務器請求一次,服務器判斷這段時間是否有新消息,需要發(fā)給客戶端,如果有就通過json或者xml方式發(fā)給客戶端。
      2 通過短信的方式,服務器端通過SMS的方式,將所需要的消息及時發(fā)送回來。
      3 使用tcp長連接和心跳包的機制,實現(xiàn)數(shù)據(jù)定時推送。

      4 采用的方案
      從我的能力,我目前只能想到這么幾種辦法,下面我們來根據(jù)第二條里面的準則來分析上面提到的幾種方案。
      第一條通過http或者https的方式,向服務器每隔多長時間請求一次的方式,的確可以實現(xiàn)我們的功能,但是違反了我們的2.1和2.3原則。首先這種方式會耗電,當然你可以說時間設置長一點,但是這樣又違背了2.3原則。所以這條一般是不會被采納的。除非某些特殊應用。
      第二條呢,2.1、2.3、2.4都符合,可是,違背了2.2,所以我們也不會考慮的。
      第三條呢,好像全部符合,但是有一個小問題在里面,就是如果以Service的方式進行,由于Android系統(tǒng)的特殊性,在內(nèi)存不夠用的時候,會主動結束一些服務,這個服務包括了我們的定義服務,這么說,他違背了2.4。

      但是,我們還是有辦法的。

      5 被采用方案的可實施方法
      在Android 2.2以后,Google放出了C2DM【Android Cloud to Device Messaging Framework】服務,從服務的使用方法上,我們就可以明白他們采用了第三種方式。
      隨著他們推出這個服務后,很多公司開始基于這個服務做一些應用,如推送廣告、推送定制信息等。如xtifyairpush等,國內(nèi)也有一些企業(yè)加入了這種陣營,如單獨提供服務的push-notification,當然QQ也有這樣的服務存在。

      在這種方案里面,有幾個細節(jié)地方,需要來解釋一下。
      5.1 傳輸?shù)臅r候使用什么協(xié)議?
      5.2 傳輸?shù)臅r候如何保證數(shù)據(jù)的安全性?
      5.3 對于多平臺,多用戶的push如何保證惟一性?
      5.4 服務器端的如何部署?

      5.1的問題目前有幾種方式,使用xmpp協(xié)議、IBM的MQTT、自定義協(xié)議。 目前有一些開源的項目中,大都采用第一種和第二種,當然,如果有特殊需求,可以采取自定義協(xié)議的。
      5.2的問題可以對數(shù)據(jù)進行可逆加密。
      5.3的問題,一般是將手機的ID傳遞到服務器端進行惟一性驗證。
      5.4的問題,服務器端可以自己使用任何語言開發(fā),也可以使用Nginx + 腳本語言部署。

      6 實例說明
      本文的實例采用了mqtt的架構,完全按照tokudu兄的文章而來,并成功實現(xiàn)了。里面采取的不是IBM的Really Small Message Broker,而是采用的開源Mosquitto實現(xiàn),

      準備工作:

      6.1 Android真機,本文為三星I809
      6.2 Apache + Php環(huán)境
      6.3 tokudu兄的Android源代碼
      6.4 tukudu兄的php代碼
      6.5 mosquitto的可執(zhí)行程序。

      步驟1:
      下載mosquitto的可執(zhí)行程序,我選擇的是cygwin版本的,安裝后,進入目錄雙擊mosquitto.exe執(zhí)行即可。

      步驟2:下載tokudu兄的php代碼,官方地址為:https://github.com/tokudu/PhpMQTTClient
      我這里也提供下載:androidpushservice

      主要代碼為如下:

      <?php
        
      require('SAM/php_sam.php');
        
      //create a new connection object
      $conn = new SAMConnection();
        
      //start initialise the connection
      $conn->connect(SAM_MQTT, array(SAM_HOST => '202.198.21.131',
                                     SAM_PORT => 1883));
      //create a new MQTT message with the output of the shell command as the body
      $msgCpu = new SAMMessage($_REQUEST['message']);
        
      //send the message on the topic cpu
      $conn->send('topic://'.$_REQUEST['target'], $msgCpu);
        
      $conn->disconnect();         
        
      echo 'MQTT Message to ' . $_REQUEST['target'] . ' sent: ' . $_REQUEST['message']; 
        
      ?>

      將代碼部署到php環(huán)境目錄里面。輸入地址:http://localhost/androidpushservice/

      步驟三:下載tokudu兄的android代碼:
      地址:https://github.com/tokudu/AndroidPushNotificationsDemo
      本文提供下載:
      tokudu-AndroidPushNotificationsDemo-ea18b09

      導入項目,編譯,在真機上面使用打開即可。

      這里有一個Device Target號碼需要在php的界面里面輸入。才可以發(fā)送成功。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      /*
      * $Id$
      */


      package com.tokudu.demo;

      import java.io.BufferedWriter;
      import java.io.File;
      import java.io.FileWriter;
      import java.io.IOException;
      import java.io.Writer;
      import java.text.SimpleDateFormat;
      import java.util.Date;

      import android.os.Environment;

      public class ConnectionLog
      {
      private String mPath;
      private Writer mWriter;

      private static final SimpleDateFormat TIMESTAMP_FMT =
      new SimpleDateFormat("[HH:mm:ss] ");

      public ConnectionLog()
      throws IOException
      {
      File sdcard = Environment.getExternalStorageDirectory();
      File logDir = new File(sdcard, "tokudu/log/");
      if (!logDir.exists()) {
      logDir.mkdirs();
      // do not allow media scan
      new File(logDir, ".nomedia").createNewFile();
      }

      open(logDir.getAbsolutePath() + "/push.log");
      }

      public ConnectionLog(String basePath)
      throws IOException
      {
      open(basePath);
      }

      protected void open(String basePath)
      throws IOException
      {
      File f = new File(basePath + "-" + getTodayString());
      mPath = f.getAbsolutePath();
      mWriter = new BufferedWriter(new FileWriter(mPath), 2048);

      println("Opened log.");
      }

      private static String getTodayString()
      {
      SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd-hhmmss");
      return df.format(new Date());
      }

      public String getPath()
      {
      return mPath;
      }

      public void println(String message)
      throws IOException
      {
      mWriter.write(TIMESTAMP_FMT.format(new Date()));
      mWriter.write(message);
      mWriter.write('\n');
      mWriter.flush();
      }

      public void close()
      throws IOException
      {
      mWriter.close();
      }
      }
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      package com.tokudu.demo;

      import android.app.Activity;
      import android.content.SharedPreferences;
      import android.content.SharedPreferences.Editor;
      import android.os.Bundle;
      import android.provider.Settings.Secure;
      import android.view.View;
      import android.view.View.OnClickListener;
      import android.widget.Button;
      import android.widget.TextView;

      public class PushActivity extends Activity {
      private String mDeviceID;
      /** Called when the activity is first created. */
      @Override
      public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);

      mDeviceID = Secure.getString(this.getContentResolver(), Secure.ANDROID_ID);
      ((TextView) findViewById(R.id.target_text)).setText(mDeviceID);

      final Button startButton = ((Button) findViewById(R.id.start_button));
      final Button stopButton = ((Button) findViewById(R.id.stop_button));
      startButton.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
      Editor editor = getSharedPreferences(PushService.TAG, MODE_PRIVATE).edit();
      editor.putString(PushService.PREF_DEVICE_ID, mDeviceID);
      editor.commit();
      PushService.actionStart(getApplicationContext());
      startButton.setEnabled(false);
      stopButton.setEnabled(true);
      }
      });
      stopButton.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
      PushService.actionStop(getApplicationContext());
      startButton.setEnabled(true);
      stopButton.setEnabled(false);
      }
      });
      }

      @Override
      protected void onResume() {
      super.onResume();

      SharedPreferences p = getSharedPreferences(PushService.TAG, MODE_PRIVATE);
      boolean started = p.getBoolean(PushService.PREF_STARTED, false);

      ((Button) findViewById(R.id.start_button)).setEnabled(!started);
      ((Button) findViewById(R.id.stop_button)).setEnabled(started);
      }
      }
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128
      129
      130
      131
      132
      133
      134
      135
      136
      137
      138
      139
      140
      141
      142
      143
      144
      145
      146
      147
      148
      149
      150
      151
      152
      153
      154
      155
      156
      157
      158
      159
      160
      161
      162
      163
      164
      165
      166
      167
      168
      169
      170
      171
      172
      173
      174
      175
      176
      177
      178
      179
      180
      181
      182
      183
      184
      185
      186
      187
      188
      189
      190
      191
      192
      193
      194
      195
      196
      197
      198
      199
      200
      201
      202
      203
      204
      205
      206
      207
      208
      209
      210
      211
      212
      213
      214
      215
      216
      217
      218
      219
      220
      221
      222
      223
      224
      225
      226
      227
      228
      229
      230
      231
      232
      233
      234
      235
      236
      237
      238
      239
      240
      241
      242
      243
      244
      245
      246
      247
      248
      249
      250
      251
      252
      253
      254
      255
      256
      257
      258
      259
      260
      261
      262
      263
      264
      265
      266
      267
      268
      269
      270
      271
      272
      273
      274
      275
      276
      277
      278
      279
      280
      281
      282
      283
      284
      285
      286
      287
      288
      289
      290
      291
      292
      293
      294
      295
      296
      297
      298
      299
      300
      301
      302
      303
      304
      305
      306
      307
      308
      309
      310
      311
      312
      313
      314
      315
      316
      317
      318
      319
      320
      321
      322
      323
      324
      325
      326
      327
      328
      329
      330
      331
      332
      333
      334
      335
      336
      337
      338
      339
      340
      341
      342
      343
      344
      345
      346
      347
      348
      349
      350
      351
      352
      353
      354
      355
      356
      357
      358
      359
      360
      361
      362
      363
      364
      365
      366
      367
      368
      369
      370
      371
      372
      373
      374
      375
      376
      377
      378
      379
      380
      381
      382
      383
      384
      385
      386
      387
      388
      389
      390
      391
      392
      393
      394
      395
      396
      397
      398
      399
      400
      401
      402
      403
      404
      405
      406
      407
      408
      409
      410
      411
      412
      413
      414
      415
      416
      417
      418
      419
      420
      421
      422
      423
      424
      425
      426
      427
      428
      429
      430
      431
      432
      433
      434
      435
      436
      437
      438
      439
      440
      441
      442
      443
      444
      445
      446
      447
      448
      449
      450
      451
      452
      453
      454
      455
      456
      457
      458
      459
      460
      461
      462
      463
      464
      465
      466
      467
      468
      469
      470
      471
      472
      473
      474
      475
      476
      477
      478
      479
      480
      481
      482
      483
      484
      485
      486
      487
      488
      489
      490
      491
      492
      493
      494
      495
      496
      497
      498
      499
      500
      501
      502
      503
      504
      505
      506
      507
      508
      509
      510
      511
      512
      513
      514
      515
      516
      517
      518
      519
      520
      521
      522
      523
      524
      525
      526
      527
      528
      package com.tokudu.demo;

      import java.io.IOException;

      import com.ibm.mqtt.IMqttClient;
      import com.ibm.mqtt.MqttClient;
      import com.ibm.mqtt.MqttException;
      import com.ibm.mqtt.MqttPersistence;
      import com.ibm.mqtt.MqttPersistenceException;
      import com.ibm.mqtt.MqttSimpleCallback;

      import android.app.AlarmManager;
      import android.app.Notification;
      import android.app.NotificationManager;
      import android.app.PendingIntent;
      import android.app.Service;
      import android.content.BroadcastReceiver;
      import android.content.Context;
      import android.content.Intent;
      import android.content.IntentFilter;
      import android.content.SharedPreferences;
      import android.net.ConnectivityManager;
      import android.net.NetworkInfo;
      import android.os.IBinder;
      import android.util.Log;

      /*
      * PushService that does all of the work.
      * Most of the logic is borrowed from KeepAliveService.
      * http://code.google.com/p/android-random/source/browse/trunk/TestKeepAlive/src/org/devtcg/demo/keepalive/KeepAliveService.java?r=219
      */

      public class PushService extends Service
      {
      // this is the log tag
      public static final String TAG = "DemoPushService";

      // the IP address, where your MQTT broker is running.
      private static final String MQTT_HOST = "88.88.88.111";
      // the port at which the broker is running.
      private static int MQTT_BROKER_PORT_NUM = 1883;
      // Let's not use the MQTT persistence.
      private static MqttPersistence MQTT_PERSISTENCE = null;
      // We don't need to remember any state between the connections, so we use a clean start.
      private static boolean MQTT_CLEAN_START = true;
      // Let's set the internal keep alive for MQTT to 15 mins. I haven't tested this value much. It could probably be increased.
      private static short MQTT_KEEP_ALIVE = 60 * 15;
      // Set quality of services to 0 (at most once delivery), since we don't want push notifications
      // arrive more than once. However, this means that some messages might get lost (delivery is not guaranteed)
      private static int[] MQTT_QUALITIES_OF_SERVICE = { 0 } ;
      private static int MQTT_QUALITY_OF_SERVICE = 0;
      // The broker should not retain any messages.
      private static boolean MQTT_RETAINED_PUBLISH = false;

      // MQTT client ID, which is given the broker. In this example, I also use this for the topic header.
      // You can use this to run push notifications for multiple apps with one MQTT broker.
      public static String MQTT_CLIENT_ID = "tokudu";

      // These are the actions for the service (name are descriptive enough)
      private static final String ACTION_START = MQTT_CLIENT_ID + ".START";
      private static final String ACTION_STOP = MQTT_CLIENT_ID + ".STOP";
      private static final String ACTION_KEEPALIVE = MQTT_CLIENT_ID + ".KEEP_ALIVE";
      private static final String ACTION_RECONNECT = MQTT_CLIENT_ID + ".RECONNECT";

      // Connection log for the push service. Good for debugging.
      private ConnectionLog mLog;

      // Connectivity manager to determining, when the phone loses connection
      private ConnectivityManager mConnMan;
      // Notification manager to displaying arrived push notifications
      private NotificationManager mNotifMan;

      // Whether or not the service has been started.
      private boolean mStarted;

      // This the application level keep-alive interval, that is used by the AlarmManager
      // to keep the connection active, even when the device goes to sleep.
      private static final long KEEP_ALIVE_INTERVAL = 1000 * 60 * 28;

      // Retry intervals, when the connection is lost.
      private static final long INITIAL_RETRY_INTERVAL = 1000 * 10;
      private static final long MAXIMUM_RETRY_INTERVAL = 1000 * 60 * 30;

      // Preferences instance
      private SharedPreferences mPrefs;
      // We store in the preferences, whether or not the service has been started
      public static final String PREF_STARTED = "isStarted";
      // We also store the deviceID (target)
      public static final String PREF_DEVICE_ID = "deviceID";
      // We store the last retry interval
      public static final String PREF_RETRY = "retryInterval";

      // Notification title
      public static String NOTIF_TITLE = "Tokudu";
      // Notification id
      private static final int NOTIF_CONNECTED = 0;

      // This is the instance of an MQTT connection.
      private MQTTConnection mConnection;
      private long mStartTime;

      // Static method to start the service
      public static void actionStart(Context ctx) {
      Intent i = new Intent(ctx, PushService.class);
      i.setAction(ACTION_START);
      ctx.startService(i);
      }

      // Static method to stop the service
      public static void actionStop(Context ctx) {
      Intent i = new Intent(ctx, PushService.class);
      i.setAction(ACTION_STOP);
      ctx.startService(i);
      }

      // Static method to send a keep alive message
      public static void actionPing(Context ctx) {
      Intent i = new Intent(ctx, PushService.class);
      i.setAction(ACTION_KEEPALIVE);
      ctx.startService(i);
      }

      @Override
      public void onCreate() {
      super.onCreate();

      log("Creating service");
      mStartTime = System.currentTimeMillis();

      try {
      mLog = new ConnectionLog();
      Log.i(TAG, "Opened log at " + mLog.getPath());
      } catch (IOException e) {
      Log.e(TAG, "Failed to open log", e);
      }

      // Get instances of preferences, connectivity manager and notification manager
      mPrefs = getSharedPreferences(TAG, MODE_PRIVATE);
      mConnMan = (ConnectivityManager)getSystemService(CONNECTIVITY_SERVICE);
      mNotifMan = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);

      /* If our process was reaped by the system for any reason we need
      * to restore our state with merely a call to onCreate. We record
      * the last "started" value and restore it here if necessary. */

      handleCrashedService();
      }

      // This method does any necessary clean-up need in case the server has been destroyed by the system
      // and then restarted
      private void handleCrashedService() {
      if (wasStarted() == true) {
      log("Handling crashed service...");
      // stop the keep alives
      stopKeepAlives();

      // Do a clean start
      start();
      }
      }

      @Override
      public void onDestroy() {
      log("Service destroyed (started=" + mStarted + ")");

      // Stop the services, if it has been started
      if (mStarted == true) {
      stop();
      }

      try {
      if (mLog != null)
      mLog.close();
      } catch (IOException e) {}
      }

      @Override
      public void onStart(Intent intent, int startId) {
      super.onStart(intent, startId);
      log("Service started with intent=" + intent);

      // Do an appropriate action based on the intent.
      if (intent.getAction().equals(ACTION_STOP) == true) {
      stop();
      stopSelf();
      } else if (intent.getAction().equals(ACTION_START) == true) {
      start();
      } else if (intent.getAction().equals(ACTION_KEEPALIVE) == true) {
      keepAlive();
      } else if (intent.getAction().equals(ACTION_RECONNECT) == true) {
      if (isNetworkAvailable()) {
      reconnectIfNecessary();
      }
      }
      }

      @Override
      public IBinder onBind(Intent intent) {
      return null;
      }

      // log helper function
      private void log(String message) {
      log(message, null);
      }
      private void log(String message, Throwable e) {
      if (e != null) {
      Log.e(TAG, message, e);

      } else {
      Log.i(TAG, message);
      }

      if (mLog != null)
      {
      try {
      mLog.println(message);
      } catch (IOException ex) {}
      }
      }

      // Reads whether or not the service has been started from the preferences
      private boolean wasStarted() {
      return mPrefs.getBoolean(PREF_STARTED, false);
      }

      // Sets whether or not the services has been started in the preferences.
      private void setStarted(boolean started) {
      mPrefs.edit().putBoolean(PREF_STARTED, started).commit();
      mStarted = started;
      }

      private synchronized void start() {
      log("Starting service...");

      // Do nothing, if the service is already running.
      if (mStarted == true) {
      Log.w(TAG, "Attempt to start connection that is already active");
      return;
      }

      // Establish an MQTT connection
      connect();

      // Register a connectivity listener
      registerReceiver(mConnectivityChanged, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
      }

      private synchronized void stop() {
      // Do nothing, if the service is not running.
      if (mStarted == false) {
      Log.w(TAG, "Attempt to stop connection not active.");
      return;
      }

      // Save stopped state in the preferences
      setStarted(false);

      // Remove the connectivity receiver
      unregisterReceiver(mConnectivityChanged);
      // Any existing reconnect timers should be removed, since we explicitly stopping the service.
      cancelReconnect();

      // Destroy the MQTT connection if there is one
      if (mConnection != null) {
      mConnection.disconnect();
      mConnection = null;
      }
      }

      //
      private synchronized void connect() {
      log("Connecting...");
      // fetch the device ID from the preferences.
      String deviceID = mPrefs.getString(PREF_DEVICE_ID, null);
      // Create a new connection only if the device id is not NULL
      if (deviceID == null) {
      log("Device ID not found.");
      } else {
      try {
      mConnection = new MQTTConnection(MQTT_HOST, deviceID);
      } catch (MqttException e) {
      // Schedule a reconnect, if we failed to connect
      log("MqttException: " + (e.getMessage() != null e.getMessage() : "NULL"));
      if (isNetworkAvailable()) {
      scheduleReconnect(mStartTime);
      }
      }
      setStarted(true);
      }
      }

      private synchronized void keepAlive() {
      try {
      // Send a keep alive, if there is a connection.
      if (mStarted == true &amp;&amp; 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 &lt; 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 &amp;&amp; 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 &amp;&amp; info.isConnected()) true : false;

      log("Connectivity changed: connected=" + hasConnectivity);

      if (hasConnectivity) {
      reconnectIfNecessary();
      } else if (mConnection != null) {
      // if there no connectivity, make sure MQTT connection is destroyed
      mConnection.disconnect();
      cancelReconnect();
      mConnection = null;
      }
      }
      };

      // Display the topbar notification
      private void showNotification(String text) {
      Notification n = new Notification();

      n.flags |= Notification.FLAG_SHOW_LIGHTS;
      n.flags |= Notification.FLAG_AUTO_CANCEL;

      n.defaults = Notification.DEFAULT_ALL;

      n.icon = com.tokudu.demo.R.drawable.icon;
      n.when = System.currentTimeMillis();

      // Simply open the parent activity
      PendingIntent pi = PendingIntent.getActivity(this, 0,
      new Intent(this, PushActivity.class), 0);

      // Change the name of the notification here
      n.setLatestEventInfo(this, NOTIF_TITLE, text, pi);

      mNotifMan.notify(NOTIF_CONNECTED, n);
      }

      // Check if we are online
      private boolean isNetworkAvailable() {
      NetworkInfo info = mConnMan.getActiveNetworkInfo();
      if (info == null) {
      return false;
      }
      return info.isConnected();
      }

      // This inner class is a wrapper on top of MQTT client.
      private class MQTTConnection implements MqttSimpleCallback {
      IMqttClient mqttClient = null;

      // Creates a new connection given the broker address and initial topic
      public MQTTConnection(String brokerHostName, String initTopic) throws MqttException {
      // Create connection spec
      String mqttConnSpec = "tcp://" + brokerHostName + "@" + MQTT_BROKER_PORT_NUM;
      // Create the client and connect
      mqttClient = MqttClient.createMqttClient(mqttConnSpec, MQTT_PERSISTENCE);
      String clientID = MQTT_CLIENT_ID + "/" + mPrefs.getString(PREF_DEVICE_ID, "");
      mqttClient.connect(clientID, MQTT_CLEAN_START, MQTT_KEEP_ALIVE);

      // register this client app has being able to receive messages
      mqttClient.registerSimpleHandler(this);

      // Subscribe to an initial topic, which is combination of client ID and device ID.
      initTopic = MQTT_CLIENT_ID + "/" + initTopic;
      subscribeToTopic(initTopic);

      log("Connection established to " + brokerHostName + " on topic " + initTopic);

      // Save start time
      mStartTime = System.currentTimeMillis();
      // Star the keep-alives
      startKeepAlives();
      }

      // Disconnect
      public void disconnect() {
      try {
      stopKeepAlives();
      mqttClient.disconnect();
      } catch (MqttPersistenceException e) {
      log("MqttException" + (e.getMessage() != null e.getMessage():" NULL"), e);
      }
      }
      /*
      * Send a request to the message broker to be sent messages published with
      * the specified topic name. Wildcards are allowed.
      */

      private void subscribeToTopic(String topicName) throws MqttException {

      if ((mqttClient == null) || (mqttClient.isConnected() == false)) {
      // quick sanity check - don't try and subscribe if we don't have
      // a connection
      log("Connection error" + "No connection");
      } else {
      String[] topics = { topicName };
      mqttClient.subscribe(topics, MQTT_QUALITIES_OF_SERVICE);
      }
      }
      /*
      * Sends a message to the message broker, requesting that it be published
      * to the specified topic.
      */

      private void publishToTopic(String topicName, String message) throws MqttException {
      if ((mqttClient == null) || (mqttClient.isConnected() == false)) {
      // quick sanity check - don't try and publish if we don't have
      // a connection
      log("No connection to public to");
      } else {
      mqttClient.publish(topicName,
      message.getBytes(),
      MQTT_QUALITY_OF_SERVICE,
      MQTT_RETAINED_PUBLISH);
      }
      }

      /*
      * Called if the application loses it's connection to the message broker.
      */

      public void connectionLost() throws Exception {
      log("Loss of connection" + "connection downed");
      stopKeepAlives();
      // null itself
      mConnection = null;
      if (isNetworkAvailable() == true) {
      reconnectIfNecessary();
      }
      }

      /*
      * Called when we receive a message from the message broker.
      */

      public void publishArrived(String topicName, byte[] payload, int qos, boolean retained) {
      // Show a notification
      String s = new String(payload);
      showNotification(s);
      log("Got message: " + s);
      }

      public void sendKeepAlive() throws MqttException {
      log("Sending keep alive");
      // publish to a keep-alive topic
      publishToTopic(MQTT_CLIENT_ID + "/keepalive", mPrefs.getString(PREF_DEVICE_ID, ""));
      }
      }
      }

      7 代碼下載

      tokudu-AndroidPushNotificationsDemo-ea18b09

      androidpushservice

      MQTT實現(xiàn):http:///download/

      8 尾聲

      我們目前已經(jīng)完成了整個功能,如果要商業(yè)使用,還有一些問題擺在我們面前,如連接數(shù)的問題,大并發(fā)的問題,Apikey的問題等等。我們也會在tokudu兄的基礎上,嘗試完善一下,在這里對tokudu兄致以深深的敬意。

      參考文章:

      1 http:///2010/how-to-implement-push-notifications-for-android/【主參考】
      2 http:///projects/androidpn/
      3 http://blog./2011/03/simple-google-android-c2dm-tutorial-push-notifications-for-android/
      4 http:///download/
      5 http://hi.baidu.com/zhu410289616/blog/item/b697f5328b0c405fad4b5f83.html
      6 http://blog.csdn.net/joshua_yu/article/details/6563587
      7 http://blog./2011/03/simple-google-android-c2dm-tutorial-push-notifications-for-android/
      8 http://www./Articles/339162/Android-push-notification-implementation-using-ASP
      9 http://www./thread-97603-1-1.html
      10 https://www14.software.ibm.com/webapp/iwm/web/reg/acceptLogin.do?source=AW-0U9&lang=en_US
      11 http:///
      12 https://github.com/tokudu/AndroidPushNotificationsDemo
      13 http://code.google.com/intl/zh-CN/android/c2dm/
      14 http:///questions/1378671/push-notifications-in-android-platform
      15 http:///blog/?p=938
      16 http:///
      17 http:///questions/1243066/does-android-support-near-real-time-push-notification
      18 http://www./2010/09/android-push-notification
      19 http://www./

      -END-

        本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
        轉藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多