JPush極光推送的原理與簡單demo的實現會遇到的問題

相信開發者們必定不陌生JPush極光推送,像QQ、微信的推送機制,QQ採用的是APNS推送服務,微信則採用google的GCM推送機制,很 多人都說APNS是一個死流氓服務,我也沒去了解,而GCM有點像IOS自帶的推送,有待了解。不少項目作一些通信功能,大部分人都會選擇JPush極光 推送,由於用起來簡單,代碼量也少,JPush官網上的開發文檔也寫的至關清楚,一些步驟也清晰明瞭。今天在這邊主要就是講一下推送的原理,以及demo 測試中會遇到的問題,這也是移植到項目中易出錯的地方。java

極光推送的功能:主動 即時的向用戶發起交互,能夠發送聊天信息等;
——做用:經過向精準的目標用戶推送有價值的消息,能夠提供用戶的忠誠度,提升留存率。android

(1)推送方式
——發送通知:推送的文本內容,展現在通知欄上面;
——自定義消息:推送自定義消息,給用戶自行處理;
——富媒體:推送的是HTML網頁內容。api

(2)推送目標
——廣播推送:向全部用戶發送廣播信息;
——標籤推送 Tag:根據用戶設置自定義的標籤分組,向某一組推送消息;
——別名推送 Alias:客戶端綁定用戶自定義的用戶別名,向單個用戶推送消息。服務器

(3)用戶分羣
——用戶分羣:能夠根據JPush提供的多條件組合,對用戶進行羣組劃分,實現實時篩選推送。微信

(4)推送歷史
——推送歷史:經過WEB或者API發出的推送,均可以在推送歷史記錄中查詢到,並能夠實時顯示推送結果數據。網絡

推送框架

——推送的數據源:本身開發的服務器端或者使用極光推送官網的WEB後臺;
——JPush API:部署在服務器端,開發者的服務器端發起推送時,將數據傳到JPush API中,而後向下傳遞;
——創建長連接:集成JPush的SDK客戶端啓動後會創建一個到JPush Cloud的長連接,提供App永遠在線的能力(能夠參考極光推送官方博客);
——原理圖:
原理圖app

客戶端原理

IP地址的分配原理
——IP地址有限:IPv4的IP地址數量有限,運營商要動態的爲手機分配IP地址,這些IP地址都是運營商的內網IP;
——網絡地址轉換(NAT):全稱Network Address Translation,網關維護一個外網IP地址,與內網的IP地址對應;
——外網IP不固定:因爲運營商持有的外網IP數量有限,須要動態的爲分配給接入運營商的用戶,所以在手機一段時間沒有數據傳輸時會將該手機分配的外網IP地址收回,分配給其餘用戶;
——解決方案:Android手機端想要保持長連接,首先外網IP地址不能變,不能讓運營商收回這個IP地址。框架

Android手機端實現方案
——心跳:爲了長時間保持外網IP,須要客戶端按期發送心跳給運營商,以便刷新NAT列表;
——Timer定時方法:該類計劃循環執行定時任務,可是使用該類會使CPU保持喚醒狀態,比較費電。
——AlarmManager定時方法:該類封裝了Android手機的RTC硬件時鐘模塊,能夠在CPU休眠時正常運行,保持任務執行時再喚醒CPU,這樣作到了電量節省。less

簡單demo容易出錯的地方
·Appcation中初始化JPush
——JPushInterface.init(this); // 初始化 JPush
·啓動的主程序裏面必定要複寫兩個生命週期:eclipse

@Override
    protected void onPause() {
        isForeground = false;
        super.onPause();
        JPushInterface.onPause(MainActivity.this);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
@Override
    protected void onResume() {
        isForeground = true;
        super.onResume();
        JPushInterface.onResume(MainActivity.this);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

注意:若是主程序裏面的Activity繼承的是InstrumentedActivity,則不須要寫 JPushInterface.onResume(MainActivity.this);個人MainActivity繼承的是 FragmentActivity,因此加上了這句。

這是個人demo代碼,貼出來你們看的比較清晰些:

package com.lai.jpushdemo;

import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.FragmentActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.Toast;

import com.ms.stock.R;

import java.util.LinkedHashSet;
import java.util.Set;

import cn.jpush.android.api.JPushInterface;
import cn.jpush.android.api.TagAliasCallback;


public class MainActivity extends FragmentActivity{
    private static final String TAG = "JPush";


    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setTag("abc");
    }

    /**
     * 設置tags
     */
    private void setTag(String tag){

        // 檢查 tag 的有效性
        if (TextUtils.isEmpty(tag)) {
            Toast.makeText(MainActivity.this,R.string.error_tag_empty, Toast.LENGTH_SHORT).show();
            return;
        }
        // ","隔開的多個 轉換成 Set
        String[] sArray = tag.split(",");
        Set<String> tagSet = new LinkedHashSet<String>();
        for (String sTagItme : sArray) {
            if (!ExampleUtil.isValidTagAndAlias(sTagItme)) {
                Toast.makeText(MainActivity.this,R.string.error_tag_gs_empty, Toast.LENGTH_SHORT).show();
                return;
            }
            tagSet.add(sTagItme);
        }
        //調用JPush API設置Tag
        mHandler.sendMessage(mHandler.obtainMessage(MSG_SET_TAGS, tagSet));

    }


    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK){
            finish();
        }
        return super.onKeyDown(keyCode, event);
    }




    private final TagAliasCallback mTagsCallback = new TagAliasCallback() {

        @Override
        public void gotResult(int code, String alias, Set<String> tags) {
            String logs ;
            switch (code) {
            case 0:
                logs = "設置別名和標籤成功!";
                Log.i(TAG, logs);
                break;

            case 6002:
                logs = "設置超時,60s後重試!";
                Log.i(TAG, logs);
                if (ExampleUtil.isConnected(getApplicationContext())) {
                    mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SET_TAGS, tags), 1000 * 60);
                } else {
                    Log.i(TAG, "沒有鏈接網絡");
                }
                break;

            default:
                logs = "失敗代碼 = " + code;
                Log.e(TAG, logs);
            }

            ExampleUtil.showToast(logs, getApplicationContext());
        }

    };
    private static final int MSG_SET_TAGS = 1002;


    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(android.os.Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {

            case MSG_SET_TAGS:
                Log.d(TAG, "在handler裏面設置tags");
                JPushInterface.setAliasAndTags(getApplicationContext(), null, (Set<String>) msg.obj, mTagsCallback);
                break;

            default:
                Log.i(TAG, "handler沒有內容 - " + msg.what);
            }
        }
    };

    public static boolean isForeground = false;

    @Override
    protected void onResume() {
        isForeground = true;
        super.onResume();
        JPushInterface.onResume(MainActivity.this);
    }


    @Override
    protected void onPause() {
        isForeground = false;
        super.onPause();
        JPushInterface.onPause(MainActivity.this);
    }

}
  • 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

這裏設置的Tag值是寫死的(我項目中只用到Tag),寫成動態的話,後面你們能夠寫到Appcation裏面。

·別忘記添加jar包和.so文件
  若是博友用eclipse開發的話,直接把jar和.so文件添加到libs目錄中便可,若是用的是android studio,則須要把.so文件單獨放進jniLibs文件夾中(注意:studio新建的文件夾自帶是jni,這邊的jniLibs目錄是須要手動去 重命名文件夾,經測試,若是是jni文件夾,項目會異常,找不到文件,因此必須是jniLibs)。

·AndroidManifest.xml
  *權限(uses-permission)必定要放在appcation前面。
這點你們注意下,昨天由於這個問題折騰了很久,個人習慣就是先寫一個demo,而後再移植到本身的項目中,這樣作起來比較快,也不會太亂。偏偏這個問題讓我很是痛苦,最後看了日誌才發現的,值得你們注意。

源碼下載地址 這個是我修改過得demo,只須要在AndroidManifest.xml中修改包名,以及包名的Appkey值便可,你們也能夠去官網上下載。

相關文章
相關標籤/搜索