這幾天一直在做Android 消息推送接入前的準備工作
特此在這裏將自己在加載第三方推送時出現的問題以及詳細的接入步驟進行記錄,已免後者踩坑
爲什麼選擇友盟推送?
在剛開始準備接入消息推送時 首先我先想到的是極光推送,在大概看了一遍他們的接入流程並且根據他們的文檔做了一個demo後,因爲是第一次接入推送,所以不太清楚在app離線情況下是如何接收到推送的流程,在積極和他們的業務人員溝通後也沒有得到一個我想要的回答 可能是因爲自身原因(但是服務挺好的 會把你拉到一個相關的羣聊裏面 你可以和他們技術進行溝通 )。。。最後沒選擇激光推送的原因是他們的收費標準不清晰和兩個業務員溝通得到的答覆都不太一樣 。然後在學長的推薦下查看了友盟推送。對於友盟的第一印象就是感覺他們的文檔寫的很通俗易懂,並且非常棒的一點是還提供了視頻教學,雖然視頻長度很短,但是該表達的都表現出來了,還是很讚的。當然了,最後也是最重要的一點就是他們的推送是分爲免費版和Pro版的,免費版的完全夠日常的使用。
接入前的準備:
- 友盟官方接入文檔概述
這裏推薦大家使用最新版的SDK (Push SDK 6.1.0及之後才支持AndroidQ) - 友盟推送產品後臺管理
- 友盟推送官方demo
- 新手引導 如果你還沒接觸過友盟推送,建議先看一下推送集成的流程
打開官方示例
當我們從官網下載好推送的demo,因爲是一個完整的項目直接編譯即可。
編譯完成後先不着急運行,我們首先需要在友盟推送產品後臺管理新建一個新應用
這裏測試階段你可以先填入當前demo的詳細包名,點擊確認添加後就會進入到配置嚮導界面
這裏你就可以拿到應用唯一的AppKey,Uming Message Secret,App Master Secret 這三個值很重要後期我們需要使用他們。
初始化SDK
進入我們的Android demo的MyApplication中,在UMConfigure.init()方法中分別填入我們的應用申請的Appkey和Umeng Message Secret對應信息
UMConfigure.init(this, "your appkey", "Umeng", UMConfigure.DEVICE_TYPE_PHONE, "umeng message secret");
然後運行一下我們的項目,拿到你設備專屬的device_token
然後這時,進入我們的友盟推送後臺管理,點擊測試模式->創建測試任務
在創建測試任務最後一步點擊完成
這時等待幾秒鐘後你的app就會接收到消息通知,(請先確保當前demo在前臺)
歐克,到這一步我們就算接入成功我們的測試demo了,當然了這隻算是剛剛開始,點擊該通知就會自動跳轉到我們的app中去,當然這裏可以自定義我們收到通知後點擊通知會跳轉到的特定頁面或者指定url等等,這裏可以在後續動作進行設置,當然你也可以傳遞參數,我們再來新建一個測試任務測試一下吧
這裏我們設置當用戶接收到通知點擊通知時跳轉到我們指定的頁面中,並且傳遞了參數,注意這裏的指定頁面必須要填寫全路徑。
這時你是不是想,這就結束了,原來接入推送這麼簡單啊 !
那你就錯了哦,當前我們接入的是在線推送哦,這裏先清除你的當前demo的任務,使app處於離線狀態下,我們在來新建一個測試任務,點擊發送你會發現接收不到該通知
離線推送
廠商推送
廠商推送指的就是手機硬件廠商提供的系統級別的推送服務。因爲她是系統服務,隨手機開機後她就一直存在着,有效地保證了推送通道的高可用性。在網絡暢通和推送消息內容合法的情況下,通過廠商通道推送消息給該型號手機,不論應用是否存活,都保證消息推送到位。
友盟廠商通道接入
廠商通道接入詳細文檔
直接跟着文檔一步步走就行了,裏面有詳細的接入步驟,效果圖以及鏈接
點此鏈接即可獲得神功!
這裏需要注意的是:廠商推送賬號必須註冊爲企業認證賬號
發送離線推送
其實這裏和在線推送略有差別
當我們集成好廠商通道後並完善我們的應用信息後,在這裏點擊勾選廠商通道,填入要打開的指定頁面(必填)點擊發送,當我們的app在離線狀態下也可以接收到消息推送咯(這裏上傳的是我集成demo)。
app內接收到的參數:
第一個坑
這裏我在離線推送有問題的時候和友盟的人工客服溝通,他非常堅定地告訴我離線推送消息後續行爲只能設置爲打開應用並且不可以傳參,當時我就懵了,我跟他說不能傳參我咋判斷跳轉到指定頁面的業務邏輯處理呢,他也沒給我具體的說法最後好像不了了之了
第二個坑
在我使用離線推送去推消息時,我測試了兩種情況,分別時app運行在前臺和清空後臺任務兩種情況,當我設置後續行爲爲打開應用推離線消息時,app離線狀態下點擊通知會跳轉到指定界面(這裏指的是勾選廠商推送後填寫跳轉的指定界面,不是行爲動作跳轉指定界面),但是當app在前臺時點擊通知不會跳轉到指定界面,因爲這裏我們的後續行爲設置的就是打開應用,我又和他們客服進行溝通,期間分別時和兩個客服進行了溝通,但是兩個給我的答覆居然還都不一樣,並且說沒辦法,然後還說讓我推送時推送兩個,一個在線的一個離線的 ,我感覺他就是在瞎扯,我說他們技術在實現功能時肯定有考慮這一點,然後我強烈要求和他們技術進行溝通,最後也沒和他們技術進行溝通,不過最後也是找到了解決方法,就是在發送離線通知時,想行爲動作也設置爲跳轉到指定頁面,這樣發送離線消息,不管是app離線還是在線都可以接收到信息,並且點擊通知還可以跳轉到指定界面,最後也是瞭解到,當app離線時走的時廠商通道,在線時走的時友盟通道,所以爲了實現不管app在不在線直接設定兩種都爲跳轉到指定頁面的話都會執行這個結果。
這裏忍不住吐槽友盟了,每個客服說的內容都相差太大,與實際不符,並且我們在接入時遇到的都是技術方面的問題,但是還不能和技術有一個很好的溝通,這點沒有極光做的好,不過文檔還是非常詳細的。
這就是詳細的接入步驟了,這裏貼出我的跳轉指定頁面的activity
public class SecondActivity extends UmengNotifyClickActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
init();
}
private void init() {
Bundle bun = getIntent().getExtras();
if (bun != null) {
Set<String> keySet = bun.keySet();
for (String key : keySet) {
String value = bun.getString(key);
Log.i("testww", "#"+value);
//Toast.makeText(this,"@"+value,Toast.LENGTH_SHORT).show();
}
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
}
@Override
public void onMessage(Intent intent) {
super.onMessage(intent);
Log.i("unlineintent", "onMessage-------->");
String body = intent.getStringExtra(AgooConstants.MESSAGE_BODY);
Log.i("unlineintent", body);
}
}
服務端代碼調用
這裏有兩種方式在後臺調用,分別時調用API的方式和服務端調用
服務端下載地址
這裏推薦使用JAVA sdk的方式進行下載,因爲其它兩個都太老了
當然你也可以選擇直接調用API, 詳情請戳->
這裏我也下載了服務端代碼,並且進行了稍微的修改,在Demo.java文件中新增了列播功能
//列播
public void sendAndroidListcast() throws Exception {
AndroidListcast listcast = new AndroidListcast(appkey,appMasterSecret);
// TODO Set your device token
listcast.setDeviceToken( "Aif9eEilatT-3JOYQJDm1HXmVh_S-2QLuoRH4let4tQd,");
listcast.setTicker( "通知欄提示文字");
listcast.setTitle( "通知標題");
listcast.setText( "通知文字描述");
//點擊"通知"的後續行爲,默認爲打開app。
//unicast.goAppAfterOpen();
listcast.goActivityAfterOpen("com.example.wow.SecondActivity");
listcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
// TODO Set 'production_mode' to 'false' if it's a test device.
// For how to register a test device, please see the developer doc.
//正式模式 默認爲true
listcast.setProductionMode();
// Set customized fields
listcast.setExtraField("test", "helloworld");
listcast.setExtraField("state", "ok");
//廠商指定跳轉的activity
listcast.setChannelActivity("com.example.wow.SecondActivity");
//填寫小米channel_id 選填給推送進行分類別
//unicast.setChannelProperties("abc");
//unicast.setChannelProperties("2882303761519015348");
client.send(listcast);
}
完整的Demo.java代碼
package push;
import org.json.JSONArray;
import org.json.JSONObject;
import push.android.AndroidBroadcast;
import push.android.AndroidCustomizedcast;
import push.android.AndroidFilecast;
import push.android.AndroidGroupcast;
import push.android.AndroidListcast;
import push.android.AndroidUnicast;
import push.ios.IOSBroadcast;
import push.ios.IOSCustomizedcast;
import push.ios.IOSFilecast;
import push.ios.IOSGroupcast;
import push.ios.IOSUnicast;
public class Demo {
private String appkey = null;
private String appMasterSecret = null;
private String timestamp = null;
private PushClient client = new PushClient();
public Demo(String key, String secret) {
try {
appkey = key;
appMasterSecret = secret;
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
//廣播:5次/分鐘(發送量10次/天)
public void sendAndroidBroadcast() throws Exception {
AndroidBroadcast broadcast = new AndroidBroadcast(appkey,appMasterSecret);
broadcast.setTicker( "通知欄提示文字");
broadcast.setTitle( "我是廣播");
broadcast.setText( "是否全員接收");
//broadcast.goAppAfterOpen();
broadcast.goActivityAfterOpen("com.example.wow.SecondActivity");
broadcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
// TODO Set 'production_mode' to 'false' if it's a test device.
// For how to register a test device, please see the developer doc.
broadcast.setProductionMode();
// Set customized fields
broadcast.setExtraField("test", "helloworld");
//廠商通道相關參數
broadcast.setChannelActivity("com.example.wow.SecondActivity");
//broadcast.setChannelProperties("abc");
client.send(broadcast);
}
//單播
public void sendAndroidUnicast() throws Exception {
AndroidUnicast unicast = new AndroidUnicast(appkey,appMasterSecret);
// TODO Set your device token
unicast.setDeviceToken( "Aif9eEilatT-3JOYQJDm1HXmVh_S-2QLuoRH4let4tQd");
unicast.setTicker( "通知欄提示文字");
unicast.setTitle( "通知標題");
unicast.setText( "通知文字描述");
//點擊"通知"的後續行爲,默認爲打開app。
//unicast.goAppAfterOpen();
unicast.goActivityAfterOpen("com.example.wow.SecondActivity");
unicast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
// TODO Set 'production_mode' to 'false' if it's a test device.
// For how to register a test device, please see the developer doc.
//正式模式 默認爲true
unicast.setProductionMode();
// Set customized fields
unicast.setExtraField("test", "helloworld");
unicast.setExtraField("state", "ok");
//廠商指定跳轉的activity
unicast.setChannelActivity("com.example.wow.SecondActivity");
//填寫小米channel_id 選填給推送進行分類別
//unicast.setChannelProperties("abc");
//unicast.setChannelProperties("2882303761519015348");
client.send(unicast);
}
//列播
public void sendAndroidListcast() throws Exception {
AndroidListcast listcast = new AndroidListcast(appkey,appMasterSecret);
// TODO Set your device token
listcast.setDeviceToken( "Aif9eEilatT-3JOYQJDm1HXmVh_S-2QLuoRH4let4tQd,");
listcast.setTicker( "通知欄提示文字");
listcast.setTitle( "通知標題");
listcast.setText( "通知文字描述");
//點擊"通知"的後續行爲,默認爲打開app。
//unicast.goAppAfterOpen();
listcast.goActivityAfterOpen("com.example.wow.SecondActivity");
listcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
// TODO Set 'production_mode' to 'false' if it's a test device.
// For how to register a test device, please see the developer doc.
//正式模式 默認爲true
listcast.setProductionMode();
// Set customized fields
listcast.setExtraField("test", "helloworld");
listcast.setExtraField("state", "ok");
//廠商指定跳轉的activity
listcast.setChannelActivity("com.example.wow.SecondActivity");
//填寫小米channel_id 選填給推送進行分類別
//unicast.setChannelProperties("abc");
//unicast.setChannelProperties("2882303761519015348");
client.send(listcast);
}
//組播 用戶篩選條件,如用戶標籤、渠道等 不推薦使用
public void sendAndroidGroupcast() throws Exception {
AndroidGroupcast groupcast = new AndroidGroupcast(appkey,appMasterSecret);
/* TODO
* Construct the filter condition:
* "where":
* {
* "and":
* [
* {"tag":"test"},
* {"tag":"Test"}
* ]
* }
*/
JSONObject filterJson = new JSONObject();
JSONObject whereJson = new JSONObject();
JSONArray tagArray = new JSONArray();
JSONObject testTag = new JSONObject();
JSONObject TestTag = new JSONObject();
testTag.put("tag", "test");
TestTag.put("tag", "Test");
tagArray.put(testTag);
tagArray.put(TestTag);
whereJson.put("and", tagArray);
filterJson.put("where", whereJson);
groupcast.setFilter(filterJson);
groupcast.setTicker( "Android groupcast ticker");
groupcast.setTitle( "中文的title");
groupcast.setText( "Android groupcast text");
groupcast.goAppAfterOpen();
groupcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
groupcast.setChannelActivity("your channel activity");
// TODO Set 'production_mode' to 'false' if it's a test device.
// For how to register a test device, please see the developer doc.
groupcast.setProductionMode();
//廠商通道相關參數
groupcast.setChannelActivity("your channel activity");
groupcast.setChannelProperties("abc");
client.send(groupcast);
}
public void sendAndroidCustomizedcast() throws Exception {
AndroidCustomizedcast customizedcast = new AndroidCustomizedcast(appkey,appMasterSecret);
// TODO Set your alias here, and use comma to split them if there are multiple alias.
// And if you have many alias, you can also upload a file containing these alias, then
// use file_id to send customized notification.
customizedcast.setAlias("alias", "alias_type");
customizedcast.setTicker( "Android customizedcast ticker");
customizedcast.setTitle( "中文的title");
customizedcast.setText( "Android customizedcast text");
customizedcast.goAppAfterOpen();
customizedcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
// TODO Set 'production_mode' to 'false' if it's a test device.
// For how to register a test device, please see the developer doc.
customizedcast.setProductionMode();
//廠商通道相關參數
customizedcast.setChannelActivity("your channel activity");
customizedcast.setChannelProperties("abc");
client.send(customizedcast);
}
public void sendAndroidCustomizedcastFile() throws Exception {
AndroidCustomizedcast customizedcast = new AndroidCustomizedcast(appkey,appMasterSecret);
// TODO Set your alias here, and use comma to split them if there are multiple alias.
// And if you have many alias, you can also upload a file containing these alias, then
// use file_id to send customized notification.
String fileId = client.uploadContents(appkey,appMasterSecret,"aa"+"\n"+"bb"+"\n"+"alias");
customizedcast.setFileId(fileId, "alias_type");
customizedcast.setTicker( "Android customizedcast ticker");
customizedcast.setTitle( "中文的title");
customizedcast.setText( "Android customizedcast text");
customizedcast.goAppAfterOpen();
customizedcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
// TODO Set 'production_mode' to 'false' if it's a test device.
// For how to register a test device, please see the developer doc.
customizedcast.setProductionMode();
//廠商通道相關參數
customizedcast.setChannelActivity("your channel activity");
customizedcast.setChannelProperties("abc");
client.send(customizedcast);
}
public void sendAndroidFilecast() throws Exception {
AndroidFilecast filecast = new AndroidFilecast(appkey,appMasterSecret);
// TODO upload your device tokens, and use '\n' to split them if there are multiple tokens
String fileId = client.uploadContents(appkey,appMasterSecret,"aa"+"\n"+"bb");
filecast.setFileId( fileId);
filecast.setTicker( "Android filecast ticker");
filecast.setTitle( "中文的title");
filecast.setText( "Android filecast text");
filecast.goAppAfterOpen();
filecast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
//廠商通道相關參數
filecast.setChannelActivity("your channel activity");
filecast.setChannelProperties("abc");
client.send(filecast);
}
public void sendIOSBroadcast() throws Exception {
IOSBroadcast broadcast = new IOSBroadcast(appkey,appMasterSecret);
//alert值設置爲字符串
//broadcast.setAlert("IOS 廣播測試");
//alert的值設置爲字典
broadcast.setAlert("今日天氣" , "" , "今日可能下雨🌂");
broadcast.setBadge( 0);
broadcast.setSound( "default");
// TODO set 'production_mode' to 'true' if your app is under production mode
broadcast.setTestMode();
// Set customized fields
broadcast.setCustomizedField("test", "helloworld");
client.send(broadcast);
}
public void sendIOSUnicast() throws Exception {
IOSUnicast unicast = new IOSUnicast(appkey,appMasterSecret);
// TODO Set your device token
unicast.setDeviceToken( "your device_token");
//alert值設置爲字符串
//unicast.setAlert("IOS 單播測試");
//alert的值設置爲字典
unicast.setAlert("今日天氣" , "" , "今日可能下雨🌂");
unicast.setBadge( 0);
unicast.setSound( "default");
// TODO set 'production_mode' to 'true' if your app is under production mode
unicast.setTestMode();
// Set customized fields
unicast.setCustomizedField("test", "helloworld");
client.send(unicast);
}
public void sendIOSGroupcast() throws Exception {
IOSGroupcast groupcast = new IOSGroupcast(appkey,appMasterSecret);
/* TODO
* Construct the filter condition:
* "where":
* {
* "and":
* [
* {"tag":"iostest"}
* ]
* }
*/
JSONObject filterJson = new JSONObject();
JSONObject whereJson = new JSONObject();
JSONArray tagArray = new JSONArray();
JSONObject testTag = new JSONObject();
testTag.put("tag", "iostest");
tagArray.put(testTag);
whereJson.put("and", tagArray);
filterJson.put("where", whereJson);
System.out.println(filterJson.toString());
// Set filter condition into rootJson
groupcast.setFilter(filterJson);
//groupcast.setAlert("IOS 組播測試");
//alert的值設置爲字典
groupcast.setAlert("今日天氣" , "subtitle" , "今日可能下雨🌂");
groupcast.setBadge( 0);
groupcast.setSound( "default");
// TODO set 'production_mode' to 'true' if your app is under production mode
groupcast.setTestMode();
client.send(groupcast);
}
public void sendIOSCustomizedcast() throws Exception {
IOSCustomizedcast customizedcast = new IOSCustomizedcast(appkey,appMasterSecret);
// TODO Set your alias and alias_type here, and use comma to split them if there are multiple alias.
// And if you have many alias, you can also upload a file containing these alias, then
// use file_id to send customized notification.
customizedcast.setAlias("alias", "alias_type");
//customizedcast.setAlert("IOS 個性化測試");
//alert的值設置爲字典
customizedcast.setAlert("今日天氣" , "" , "今日可能下雨🌂");
customizedcast.setBadge( 0);
customizedcast.setSound( "default");
// TODO set 'production_mode' to 'true' if your app is under production mode
customizedcast.setTestMode();
client.send(customizedcast);
}
public void sendIOSFilecast() throws Exception {
IOSFilecast filecast = new IOSFilecast(appkey,appMasterSecret);
// TODO upload your device tokens, and use '\n' to split them if there are multiple tokens
String fileId = client.uploadContents(appkey,appMasterSecret,"aa"+"\n"+"bb");
filecast.setFileId( fileId);
//filecast.setAlert("IOS 文件播測試");
//alert的值設置爲字典
filecast.setAlert("今日天氣" , "" , "今日可能下雨🌂");
filecast.setBadge( 0);
filecast.setSound( "default");
// TODO set 'production_mode' to 'true' if your app is under production mode
filecast.setTestMode();
client.send(filecast);
}
public static void main(String[] args) {
// TODO set your appkey and master secret here
Demo demo = new Demo("your appkey", "master secret");
try {
//單播 處理一個設備的消息推送 推薦
//demo.sendAndroidUnicast();
//列播 處理2個以上500個以下的消息推送
demo.sendAndroidListcast();
//廣播 5次/分鐘(發送量10次/天) 向所有安裝該app的用戶發送推送 推薦
//demo.sendAndroidBroadcast();
//demo.sendAndroidCustomizedcastFile();
//組播 不推薦使用
//demo.sendAndroidGroupcast();
//不推薦
//* demo.sendAndroidCustomizedcast();
//* demo.sendAndroidFilecast();
//demo.sendIOSUnicast();
/* TODO these methods are all available, just fill in some fields and do the test
* demo.sendAndroidCustomizedcastFile();
* demo.sendAndroidBroadcast();
* demo.sendAndroidGroupcast();
* demo.sendAndroidCustomizedcast();
* demo.sendAndroidFilecast();
*
* demo.sendIOSBroadcast();
* demo.sendIOSUnicast();
* demo.sendIOSGroupcast();
* demo.sendIOSCustomizedcast();
* demo.sendIOSFilecast();
*/
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
看註釋
以及還有新增的列播類
package push.android;
import push.AndroidNotification;
public class AndroidListcast extends AndroidNotification {
public AndroidListcast(String appkey,String appMasterSecret) throws Exception {
setAppMasterSecret(appMasterSecret);
setPredefinedKeyValue("appkey", appkey);
this.setPredefinedKeyValue("type", "listcast");
}
public void setDeviceToken(String tokens) throws Exception {
setPredefinedKeyValue("device_tokens", tokens);
}
}
最最最重要的事
歐克,到這裏友盟推送的集成就算完成咯,這段關係只能到這了,如果非要說點什麼的話,那就是愛過~