一堕担、APP 推送概述:
App推送消息是我們常見的一種app消息提醒方式。
我們的實現(xiàn)需要第三方的支持,實現(xiàn)方式是后臺通過接口將Push請求發(fā)送至第三方讽营,第三方實現(xiàn)在App所在設(shè)備上的推送。
二泡徙、APP推送后臺處理邏輯:
在與推送平臺交互時橱鹏,后臺需要向第三方發(fā)送兩部分信息,推送目標(biāo)終端標(biāo)示+推送內(nèi)容
1堪藐、推送目標(biāo)終端標(biāo)示:
APP推送需要定位目標(biāo)終端莉兰,也就是說要給那臺設(shè)備進行推送,
簡單的情況下礁竞,單設(shè)備推送糖荒,我們需要拿到一個終端ID的概念,用于定位目標(biāo)設(shè)備模捂,
注:不同渠道中使用的單設(shè)備ID方式也不盡相同寂嘉,以下用TokenID來表示這個終端ID的概念。
而實際推送渠道中往往還有自定義的功能枫绅,比如通過打標(biāo)簽的方式將TokenID進行劃分泉孩,達到批量差異化的效果。
2并淋、推送內(nèi)容:
即指通過API接口參數(shù)的定義終端上收到的Push消息的內(nèi)容和格式寓搬。
其中IOS的推送消息在展示上區(qū)別于安卓的一點是沒有title,title的部分只能是默認的APP名稱县耽,而安卓的部分雖然默認值也是APP名稱句喷,但是也支持自定義title。
三兔毙、后端實現(xiàn):
通過上述的處理邏輯可得知唾琼,后端首先需要登記客戶端的TokenId,然后保持TokenID的有效性更新澎剥,然后在需要發(fā)送APP推送時拿到用戶的有效TokenID锡溯,
然后使用TokenID和已有的內(nèi)容信息通過API與三方Push服務(wù)交互,完成推送哑姚。
即后端的實現(xiàn)分為兩部分:
1祭饭、TokenID的登記
2、App Push API的調(diào)用
注:以下示例中有兩個元素為本項目的特殊情況:
其中product_id是因為當(dāng)前項目中客戶端同時有多個版本叙量,不同版本需要推送獨立處理倡蝙,但在同一張表內(nèi)統(tǒng)一記登記;
而login_id跟member_id同時存在是因為當(dāng)前系統(tǒng)中存在共享賬戶的情況绞佩,一般賬號賬戶一對一的情況login_id和member_id是綁定的寺鸥,不需要同時重復(fù)登記猪钮。
1、TokenID的登記:
- 以下是現(xiàn)項目使用的TokenID登記表結(jié)構(gòu):
<pre>
/==============================================================/
/* Table: sys_app_push_token */
/==============================================================/
create table sys_app_push_token
(
record_id int(11) not null auto_increment,
login_id int(11),
member_id int(11),
push_token varchar(200),
visit_device int(4) comment '3:Android;4:IOS',
product_id varchar(20) default '0' comment '',
push_channel int(4) default 1 comment '1:IOS信鴿,2:華為,3:小米,4:極光',
nstatus int(4) not null default 0 comment '狀態(tài):0:申請中胆建;1:生效躬贡;2:失效;3:刪除眼坏;4:歷史記錄',
create_userid int(11) not null default 0,
create_time varchar(20) character set utf8 not null default "",
edit_userid int(11) not null default 0,
edit_time varchar(20) character set utf8 not null default "",
this_remark text,
description text,
create_ordernum varchar(30) character set utf8 comment '記錄創(chuàng)建時的流水號',
last_ordernum varchar(30) character set utf8 comment '記錄最后一次編輯時的流水號',
primary key (record_id)
)
ENGINE=InnoDB
DEFAULT CHARACTERSET=utf8
COLLATE=utf8_general_ci
auto_increment=10000
row_format=COMPACT;
alter table sys_app_push_token comment 'app推送token表';
/==============================================================/
/* Index: Index_1 */
/==============================================================/
create index Index_1 on sys_app_push_token
(
record_id
);
</pre>
- 以下是APP上傳TokenID接口上傳參數(shù)列表:
注:其中拂玻,推送渠道絕對在做Push時使用哪家API,參數(shù)的判定交由客戶端進行處理宰译,后端直接登記判定結(jié)果檐蚜。
- 以下是TokenID登記接口處理方法
<pre>
@Transactional(readOnly=false)
publicbooleanuploadMemberPushTokenEnt(TrainVansContext trainVansContext) {
try{
//check already data
trainVansContext.getTrainVansRequest().put("login_id", TrainVansUtils.getMV(trainVansContext.getTrainVansRequest(),"login_login_id"));
// get All memberRelation
trainVansContext.getTrainVansRequest().put("relation_type", TrainVansUtils.getMV(trainVansContext.getTrainVansRequest(),"visit_role"));
List> memberRelationList = SpringContextHandler.getBean(MemberService.class).getRelateMemberListByLoginId(trainVansContext);
for(Map memberRelateMap : memberRelationList){
//
trainVansContext.getTrainVansRequest().put("member_id", TrainVansUtils.getMV(memberRelateMap,"member_id"));
Map tokenMap = SpringContextHandler.getBean(AppPushService.class).getPushTokenMapByLoginMap(trainVansContext.getTrainVansRequest());
//disable already data
if(tokenMap !=null){
if(!TrainVansUtils.getMV(tokenMap,"push_token").equals(TrainVansUtils.getMV(trainVansContext.getTrainVansRequest(),"push_token"))){
//
trainVansContext.getTrainVansRequest().put("record_id", TrainVansUtils.getMV(tokenMap,"record_id"));
if(!SpringContextHandler.getBean(AppPushService.class).updateDiabledThePushToken(trainVansContext)){
thrownewRuntimeException("TranVans_Operate_Exception");
}
//insert new data
if(!SpringContextHandler.getBean(AppPushService.class).insertPushTokenRecord(trainVansContext)){
thrownewRuntimeException("TranVans_Operate_Exception");
}
}
}else{
//insert new data
if(!SpringContextHandler.getBean(AppPushService.class).insertPushTokenRecord(trainVansContext)){
thrownewRuntimeException("TranVans_Operate_Exception");
}
}
}
returntrue;
}catch(Exception e) {
TrainVansUtils.setRetInfo(trainVansContext,"10005001","Register TokenID Error");
e.printStackTrace();
thrownewRuntimeException("TranVans_Operate_Exception");
}
}
</pre>
注:方法外部有一個關(guān)于對應(yīng)本賬號的對賬戶列表的遍歷,遍歷中的處理部分為TokenID的登記處理操作沿侈。
2闯第、APP Push API 的調(diào)用
推送渠道:
APP推送不僅僅要求在APP打開狀態(tài)時或者后臺運行時進行消息推送,更多的場景是在移動終端關(guān)閉APP的場景下進行消息推送缀拭,
渠道的優(yōu)劣無非在于兩個維度咳短,送達率和送達效率。
其中安卓推送的渠道較為雜亂蛛淋,其中華為和小米提供的PUSH服務(wù)對于自平臺的移動終端支持的較為完善咙好,而沒有廠商提供PUSH服務(wù)的終端只能通過
第三方服務(wù)來進行對接。
對于現(xiàn)有的這些渠道進行如下總結(jié):
1褐荷、IOS:信鴿推送勾效,這個推送在我門公司中經(jīng)歷了三個項目,推送效果穩(wěn)定叛甫。API接入也方便层宫,是IOS端的不二選擇。
2其监、Android-華為:華為自平臺萌腿。
3、Android-小米:小米自平臺抖苦。
4毁菱、Android-其他:目前使用的是“極光推送”。在理想狀態(tài)下送達率和送達效率表現(xiàn)很好睛约,但并不如以上三家渠道穩(wěn)定鼎俘。
在進行調(diào)用時可根據(jù)之前定義的push_channel分發(fā)給各自的渠道哲身,各渠道的具體對接請各自查看官網(wǎng)辩涝,API都很完善。