Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android高效率編碼-第三方SDK詳解系列(三)——JPush推送牽扯出來的江湖恩怨,XMPP實現推送,自定義客戶端推送

Android高效率編碼-第三方SDK詳解系列(三)——JPush推送牽扯出來的江湖恩怨,XMPP實現推送,自定義客戶端推送

編輯:關於Android編程

很久沒有更新第三方SDK這個系列了,所以更新一下這幾天工作中使用到的推送,寫這個系列真的很要命,你要去把他們的API文檔大致的翻閱一遍,而且各種功能都實現一遍,解決各種bug各種坑,不得不說,極光推送真坑,大家使用還是要慎重,我們看一下極光推送的官網

https://www.jpush.cn/common/

 

這裡寫圖片描述

 

推送比較使用,很多軟件有需要,所以在這個點拿出來多講講,我們本節課奇會講到

AndroidPn推送 JPush推送 JPush實現聊天

一.推送的原理

既然要使用推送,首先我們還是要來了解一下原理,因為我們不僅要使用JPush來實現推送,我們還得自己來實現一個推送,有因必有果,哦彌陀佛!!

推送的方式有兩種,大家使用Git的時候也耳熟能詳

push

服務端有消息的時候主動向客戶端推送消息

pull

客戶端向服務器拉取消息,沒有消息的話不做操作

但是我們一般也不會去用pull方式,看JPush這個名字就知道,用的是push,因為pull去拉的話,就像ViewGroup要遍歷一遍所有的View一樣,麻煩,所有又費流又費電量,push推送是服務端要發什麼消息就直接發過來了,所有要方便些許

而推送的方式也有很多種,我這裡列舉幾種

C2DM雲端推送

Google官方的一個輕量級服務,依賴官方的C2DM服務器,優勢在於可以直接和服務器進行通訊,但是我們基本上是無視他的,為什麼?我大天朝

MQTT協議

這個我們也可以忽略,因為這個可以說技術積累不夠吧,很不穩定,雖然很小,但是要是一個推送都不穩定,那就成了雞肋的東西了

RSMB實現推送

我們這裡用一張圖來簡單說明下

 

這裡寫圖片描述

 

這個協議我們不做太多的概括

XMPP協議

XMPP協議可謂鼎鼎大名,基本XML的協議,是一個開源的協議,采用的通信模式是C/S(客戶端/服務端),而且操作起來相對來說比較簡單,同樣的,因為基於XML實現,所以數據傳輸格式也是XML,分布式的特點,這個協議我們就藥來多唠叨幾句了

他的工作原理

客戶端連接服務端——服務端進行認證——客戶端請求操作——交互

我們等下講會說一個AndroidPn的推送就是基於XMPP協議的

第三方(JPush,BaiDu之類)

現在各大平台都有自己的推動服務了,百度,小米,極光,等等等等….

二.AndroidPn實現推送

AndroidPn大家可能用的還是相對要少一點吧

地址: https://sourceforge.net/projects/androidpn/

我們簡單的來聊聊這個框架

他是基於XMPP協議 包含完整的服務端和客戶端 基於openfire開源工程

那我們來實現以下,其實實現起來還是稍微有點復雜的,我們要進行以下的幾個步驟

安裝TomCat本地服務器(模擬服務器) 下載AndroidPn源碼部署在TomCat上 實現推送後台 集成AndroidPn客戶端代碼 通過浏覽器完成推送

我們慢工出細活,一步步來實現

1.安裝TomCat服務器

這裡我們就不重復講了,有需要的看這篇十分簡單的實現TomCat服務器的搭建

Android服務器——TomCat服務器的搭建

我們開啟服務器

 

這裡寫圖片描述

 

我們只要在浏覽器能看到

 

這裡寫圖片描述

 

就說明配置完成了

2.下載AndroidPn源碼部署在TomCat上

官網地址上面說了

地址: https://sourceforge.net/projects/androidpn/

我們直接進去可以看到

 

這裡寫圖片描述

 

我們直接點擊Download就可以下載了,他下面有一段描述

An open source project to provide push notification support for Android -- a xmpp based notification server and a client tool kit.

意思就是說:一個開源項目提供推送式通知支持Android——基於xmpp的通知服務器和客戶端工具;

我們下載好之後就直接解壓

 

這裡寫圖片描述

 

我們可以直接進入bin文件裡面啟動服務器

 

這裡寫圖片描述

 

到這裡,我們的服務器是啟動好了,我們可以直接在浏覽器裡面輸入

http://127.0.0.1:7070/

 

這裡寫圖片描述

 

哈哈,到這裡,我們基本的環境就已經部署了,這裡我說明一下,AndroidPn的代碼下載之後解壓隨便解壓在什麼地方,以為之前已經啟動了TomCat的原因,所以他會直接依賴

3.實現AndroidPn Client代碼

客戶端的實現,其實還是分了若干個步驟的,我們一點點來書寫,首先我們需要下載一個asmack.jar,用於XMPP傳輸協議的實現

asmack官網:https://github.com/Flowdalic/asmack asmack下載地址:http://asmack.freakempire.de/

這裡這麼多,我就隨便下載了一個最新的

 

這裡寫圖片描述

 

好了,我們直接新建一個項目——AndroidPn

 

這裡寫圖片描述

 

然後開始部署了,首先肯定是把jar包放在libs目錄下,接著,我們添加網絡權限

最後需要配置我們的秘鑰了,在res目錄下新建一個raw文件夾,在文件夾下新建一個android.properties文件,添加

apiKey=1234567890

xmppHost=192.168.1.100(你的本地IP)

xmppPort=5222

這些都做完了的話,我們可以直接去清單文件裡面注冊服務,我們的服務從哪裡來?看這裡

 

這裡寫圖片描述

 

這是前輩寫好的類,我們可以直接拿來用,我會提供這個Demo給大家下載的,好了,我們可以去注冊了

我們回到MainActivity裡面

package com.lgl.androidpn;

import android.support.v7.app.AppCompatActivity;

import android.os.Bundle;

import com.lgl.androidpn.client.ServiceManager;

public class MainActivity extends AppCompatActivity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

ServiceManager serviceManager = new ServiceManager(this);

//設置通知欄圖標

serviceManager.setNotificationIcon(R.mipmap.ic_launcher);

//啟動服務

serviceManager.startService();

}

}

只要我們啟動程序,這個服務就啟動了,在此之前,我們還得家點權限

現在我們可以運行一下程序,毫無疑問,我們現在的程序是空的,但是在後台可以看到活動

 

這裡寫圖片描述

 

這個時候我們就可以去實現推送了

 

這裡寫圖片描述

 

然後我們接收到了

 

這裡寫圖片描述

 

這裡也說明一下,這個AndroidPn小案例也只是告訴大家這個推送的實現原理,以及我們親手去實現了一遍推送之後得到的寶貴經驗,並不推薦使用這個,API過時了,有點蛋疼,而且2010年就已經停止更新了,不推薦使用,我們只要了解原理就可以了

三.JPush實現推送

終於到我們的主角了Jpush極光推送,說實話這個也有點坑

官方地址: https://www.jpush.cn/common/

我們根據官網的API文檔來講解

1.集成JPush推送環境

JPush我就不再多做什麼介紹了,我簡單說一下他的有點(來自網絡)

SDK采用自定義的協議保持長連接,電量,流量都相對要少 服務器的架構比較先進 高並發可擴展性的雲服務

最後加一句,還是有點坑,哈哈,不過正常使用絕對是沒有問題的

第三方SDK現在基本上已經不用一步步來了,我們直接新建一個工程——LGLJPush

 

這裡寫圖片描述

 

我們在後台新建一個應用

 

這裡寫圖片描述

 

我們可以根據他的文檔來

http://docs.jpush.io/guideline/android_guide/

首先下載SDK

http://docs.jpush.io/resources/

然後添加權限

再增加一個自定義的權限

接著我們在application中進行各種注冊了

AS還是比較方便的,這裡我們只要修改一下我們自定義的廣播和開發者的key就可以,我們新建一個廣播——JPushReceiver配置上去就可以了

現在我們可以來初始化了,JPush的初始化需要在Application中進行,所以我們還要新建一個JPushApplication

package com.lgl.lgljpush;

import android.app.Application;

import cn.jpush.android.api.JPushInterface;

/**

* 初始化JPush

* Created by LGL on 2016/5/21.

*/

public class JPushApplication extends Application{

@Override

public void onCreate() {

super.onCreate();

JPushInterface.setDebugMode(true);

JPushInterface.init(this);

}

}

接著定義一下廣播

package com.lgl.lgljpush;

import android.content.BroadcastReceiver;

import android.content.Context;

import android.content.Intent;

import android.os.Bundle;

import android.util.Log;

import cn.jpush.android.api.JPushInterface;

/**

* Jpsuh推送廣播

* Created by LGL on 2016/5/21.

*/

public class JPushReceiver extends BroadcastReceiver {

public static final String TAG = "JPushReceiver";

@Override

public void onReceive(Context context, Intent intent) {

Bundle bundle = intent.getExtras();

String action = intent.getAction();

if (JPushInterface.ACTION_REGISTRATION_ID.equals(intent.getAction())) {

String regId = bundle.getString(JPushInterface.EXTRA_REGISTRATION_ID);

Log.d(TAG, "[MyReceiver] 接收Registration Id : " + regId);

} else if (JPushInterface.ACTION_MESSAGE_RECEIVED.equals(intent.getAction())) {

Log.d(TAG, "[MyReceiver] 接收到推送下來的自定義消息: " + bundle.getString(JPushInterface.EXTRA_MESSAGE));

} else if (JPushInterface.ACTION_NOTIFICATION_RECEIVED.equals(intent.getAction())) {

Log.d(TAG, "[MyReceiver] 接收到推送下來的通知");

int notifactionId = bundle.getInt(JPushInterface.EXTRA_NOTIFICATION_ID);

Log.d(TAG, "[MyReceiver] 接收到推送下來的通知的ID: " + notifactionId);

} else if (JPushInterface.ACTION_NOTIFICATION_OPENED.equals(intent.getAction())) {

Log.d(TAG, "[MyReceiver] 用戶點擊打開了通知");

//打開自定義的Activity

} else if (JPushInterface.ACTION_RICHPUSH_CALLBACK.equals(intent.getAction())) {

Log.d(TAG, "[MyReceiver] 用戶收到到RICH PUSH CALLBACK: " + bundle.getString(JPushInterface.EXTRA_EXTRA));

//在這裡根據 JPushInterface.EXTRA_EXTRA 的內容處理代碼,比如打開新的Activity, 打開一個網頁等..

} else if (JPushInterface.ACTION_CONNECTION_CHANGE.equals(intent.getAction())) {

boolean connected = intent.getBooleanExtra(JPushInterface.EXTRA_CONNECTION_CHANGE, false);

Log.w(TAG, "[MyReceiver]" + intent.getAction() + " connected state change to " + connected);

} else {

Log.d(TAG, "[MyReceiver] Unhandled intent - " + intent.getAction());

}

}

}

這裡其實只要定義幾個就行,我照著官方的Demo就把所有的廣播都寫了一遍了。回到我們的控制台

 

這裡寫圖片描述

 

我們點擊推送

 

這裡寫圖片描述

 

OK,推送成功了,不過這裡要注意的是,我曾一度的被這個問題困擾

 

這裡寫圖片描述

 

可能也怪自己太輕視了吧,於是翻閱了一下資料,根據他的錯誤找到了問題的所在,其實我們的lib類庫是需要加載在Gradle下的,所在,我們可以在build.gradle中的android根節點下配置

sourceSets.main{

jniLibs.srcDir 'libs'

}

從而綁定我們的類庫,我們看圖

 

這裡寫圖片描述

 

OK,我們的極光推送就集成成功了

2.自定義推送

JPush給我們提供了一個比較高級的用法,就是可以在客戶端進行推送,需要我們做一些處理,具體是什麼呢,我們可以參照一下JPush官方提供的服務端文檔

http://docs.jpush.io/server/rest_api_v3_push/

文檔中提到,我們需要一個Authorization

 

這裡寫圖片描述

 

通過appKey:masterSecret的組合Base64算法得到的一個數字,這個masterSecret在我們的控制台

 

這裡寫圖片描述

 

在下面的文章中,可能涉及到很多JPush的術語,有些可能我沒有闡述到位的地方還是勞煩你多看看上面的文檔哦!

 

這裡寫圖片描述

 

推送的必填是平台和設備,JPush 當前支持 Android, iOS, Windows Phone 三個平台的推送。其關鍵字分別為:”android”, “ios”, “winphone”。

我們舉個例子

推送到所有平台:

{ "platform" : "all" }

指定特定推送平台:

{ "platform" : ["android", "ios"] }

audience

推送設備對象,表示一條推送可以被推送到哪些設備列表。確認推送設備對象,JPush 提供了多種方式,比如:別名、標簽、注冊ID、分群、廣播等。

all

如果要發廣播(全部設備),則直接填寫 “all”,我們一般也是填all

OK,我們開始第一步,用Base64算法得到我們的秘鑰,網上搜索一下Base64的在線解碼

http://www1.tc711.com/tool/BASE64.htm

開始解碼

 

這裡寫圖片描述

 

我們就可以得到秘鑰了

YzNlNDIyODdiZjQ4Y2NmYWQ4N2MwNDEyOmFkMmNiNDMxZmNmZDAwMWIwNzBjNTlhMSA=

這裡我們使用的是HttpClient的Post請求,所以你必須在Gradle的文件裡面加入

useLibrary 'org.apache.http.legacy'

看圖更加形象一點

 

這裡寫圖片描述

 

我們寫個布局

很簡單,就一個輸入框和一個按鈕,我們要做的事情也很簡單,點擊發送按鈕之後就發送消息,通過開啟一個子線程去實現,大概的代碼

package com.lgl.lgljpush;

import android.os.Bundle;

import android.support.v7.app.AppCompatActivity;

import android.text.TextUtils;

import android.util.Log;

import android.view.View;

import android.widget.Button;

import android.widget.EditText;

import android.widget.Toast;

import org.apache.http.HttpResponse;

import org.apache.http.client.ClientProtocolException;

import org.apache.http.client.HttpClient;

import org.apache.http.client.methods.HttpPost;

import org.apache.http.entity.StringEntity;

import org.apache.http.impl.client.DefaultHttpClient;

import org.json.JSONException;

import org.json.JSONObject;

import java.io.IOException;

import java.io.UnsupportedEncodingException;

public class MainActivity extends AppCompatActivity {

//發送按鈕

private Button btn_send;

//文本框

private EditText et_content;

//要發送的文本

private String text;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

btn_send = (Button) findViewById(R.id.btn_send);

et_content = (EditText) findViewById(R.id.et_content);

btn_send.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

//拿到輸入框的內容

text = et_content.getText().toString();

//判斷不能為null

if (!TextUtils.isEmpty(text)) {

new Thread(runnable).start();

} else {

Toast.makeText(MainActivity.this, "請輸入文字", Toast.LENGTH_SHORT).show();

}

}

});

}

Runnable runnable = new Runnable() {

@Override

public void run() {

try {

//Post初始化

String url = "https://api.jpush.cn/v3/push";

HttpClient httpClient = new DefaultHttpClient();

HttpPost httpPost = new HttpPost(url);

//添加頭部信息

httpPost.addHeader("Authorization", "Basic YzNlNDIyODdiZjQ4Y2NmYWQ4N2MwNDEyOjY4Zjg2MTIxMDM2YjNhODRmOWRhN2VhOA==");

//定義Json請求

httpPost.addHeader("Content-Type", "application/json");

//添加字段

JSONObject obj = new JSONObject();

obj.put("platform", "all");

obj.put("audience", "all");

JSONObject notification = new JSONObject();

JSONObject android = new JSONObject();

android.put("alert", text);

notification.put("android", android);

obj.put("notification", notification);

httpPost.setEntity(new StringEntity(obj.toString()));

HttpResponse response = httpClient.execute(httpPost);

//打印返回碼

Log.e("返回碼", response.getStatusLine().getStatusCode() + "");

} catch (JSONException e) {

e.printStackTrace();

Log.e("返回碼", "JSONException");

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

Log.e("返回碼", "UnsupportedEncodingException");

} catch (ClientProtocolException e) {

e.printStackTrace();

Log.e("返回碼", "ClientProtocolException");

} catch (IOException e) {

e.printStackTrace();

Log.e("返回碼", "IOException");

} catch (StackOverflowError e) {

Log.e("返回碼", "StackOverflowError");

}

}

};

/**

* 發送消息 Post方式發送

*

* @param date

* @return

*/

private String sendMessage(String date) {

return "";

}

}

我自問我的代碼寫的還是邏輯很清晰的,相信你一定能看懂,好了,看下運行的返回碼

 

這裡寫圖片描述

 

那就說明成功了,我們看一下運行的結果

 

這裡寫圖片描述

 

這裡我用的是模擬器,所以不能輸入中文,我們可以看到我發送的消息是ddd,然後手機就接收到了,其實,我們可以根據設備進行推送,而且可以指定推送內容,這樣,是不是我們可以根據邏輯實現一個聊天的小應用?這裡本來想寫的。篇幅太多了,留著以後有時間寫吧,感興趣的可以自己去實現以下,根據注冊ID去發送消息,JPush也給我們提供了接口

Log.e("ID", JPushInterface.getRegistrationID(this));

Nexus 5x: 140fe1da9eab772de2c

 

這裡寫圖片描述

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved