1. 程式人生 > >SpringCloud工作筆記062---APP訊息推送_個推平臺API使用經驗

SpringCloud工作筆記062---APP訊息推送_個推平臺API使用經驗

前言       移動Push推送是移動網際網路最基礎的需求之一,用於滿足移動互聯環境下訊息到達App客戶端。以轉轉(58趕集旗下真實個人的閒置交易平臺)為例,當買家下單後,我們通過移動Push推送訊息告訴賣家,當賣家已經發貨時,我們通過移動Push訊息告訴買家,讓買賣雙方及時掌握二手商品交易的實時訂單動態。         實現推送功能的方案有許多,具體可以看《程式設計師》的一篇文章http://geek.csdn.net/news/detail/58738,這裡也詳解了IOS與Android接受推送的機制不同。 本文主要講的是利用第三方平臺來開發個推功能的API,使用的個推平臺:http://www.getui.com/          具體的使用流程,如何繫結APP在官網的官方文件裡已經詳細給出,這個都是操作問題,不涉及到後臺的開發。官方文件裡已經給出了API介紹,但是使用的需求API提供的資訊遠遠超出了API介紹的範圍。下面我將從設計的角度給出一個DEMO。 DEMO 需求:web端/APP端給指定群體使用者傳送一條通知,使用客戶端登入APP的指定使用者都能收到通知(支援多終端登入),在選單欄顯示通知,點選通知轉到APP內(透傳)顯示通知詳情(無論APP離線還是線上); 設計: 類: loginUserPojo(使用者類) NotificationPojo(通知類)--屬性見資料庫設計資訊表                    

資料庫表的設計: user_login(user_id,user_name,password....) nofitication(notification_id,title,content,createDt,creator_user_id....) user_device(user_id,client_id,device_token)(ios個推資訊通過device_id傳送,andorid通過client_id傳送)

個推API設計:

1.基本配置資訊類

public class GeXinBaseInfo {     //以下三個屬性每個APP不同     static String appId = "VAn4M36ciG9mGBEQwuDxV5";     static String appkey = "HSlKLGNZ8e6RChB3JCIop9";     static String master = "CUEIVtxSdL6wO9GfRxFoZ1";     //host是固定的作為個推的伺服器     static String host = "http://sdk.open.api.igexin.com/serviceex";     static long offExpireTime = 24 * 1000 * 3600;

    //透傳訊息設定,1為強制啟動應用,客戶端接收到訊息後就會立即啟動應用;2為等待應用啟動     static int TYPE_LAUNCH_APP = 1;     static int TYPE_WAIT_FOR_CLICK = 2; }

2.安卓端接收資訊類(點選通知後,app端根據ID資訊獲取通知詳情)

public class TransimissionContentPojo implements Serializable{

    //通知的id     private String contentId;

    //其它屬性。。。     //private ...     public String getContentId() {                return contentId;     }

    public void setContentId(String contentId) {                this.contentId = contentId;     } }

3.建立通知資訊的工廠類public class NotiTemplateFactory {      //andorid     public static NotificationTemplate produceNotiFromNoti(NotificationPojo notificationPojo){         NotificationTemplate template = getBaseTemplate();         template.setTitle("移動校園");         template.setText(notificationPojo.getTitle());         template.setTransmissionType(1);         TransimissionContentPojo pojo = new TransimissionContentPojo();         pojo.setContentId(notificationPojo.getNotificationId());         template.setTransmissionContent(new Gson().toJson(pojo));         return template;     }     //ios     public static APNPayload.DictionaryAlertMsg getDictionaryAlertMsg(String title, NotificationPojo nPojo){             APNPayload.DictionaryAlertMsg alertMsg = new APNPayload.DictionaryAlertMsg();             alertMsg.setBody(title);             alertMsg.setTitle("移動校園");             alertMsg.setTitleLocKey("ccccc");             alertMsg.setActionLocKey("移動校園");             return alertMsg;         } } 4.個推傳送資訊工具類

public class GeXinMPushUtil {     private static GeXinMPushUtil instance;

    private static ExecutorService executorService;

    private List<Target> convertToTargets(List<String> cidList) {         List<Target> targetList = new ArrayList<>();         for (String cid : cidList) {             Target target = new Target();             target.setAppId(GeXinBaseInfo.appId);             target.setClientId(cid); //          target.setAlias(cid);             targetList.add(target);         }         return targetList;     }

    protected IGtPush push;

    public GeXinMPushUtil() {         push = new IGtPush(GeXinBaseInfo.host, GeXinBaseInfo.appkey, GeXinBaseInfo.master);         executorService = Executors.newCachedThreadPool();     }

    public static GeXinMPushUtil getInstance() {         if (instance == null) {             instance = new GeXinMPushUtil();         }         return instance;     }         //andorid有通知     public void push(final NotificationTemplate notificationTemplate, final List<String> cidList) {

        executorService.submit(new Runnable() {             @Override             public void run() {                 ListMessage message = new ListMessage();                 message.setData(notificationTemplate);                 message.setOffline(true);                 message.setOfflineExpireTime(GeXinBaseInfo.offExpireTime);                 String taskId = push.getContentId(message);                 IPushResult ret = push.pushMessageToList(taskId, convertToTargets(cidList));                 System.out.println(ret.getResponse().toString());             }         });     }          //andorid透傳,無通知     public void push(final TransmissionTemplate transmissionTemplate, final List<String> cidList) {

        executorService.submit(new Runnable() {             @Override             public void run() {                 ListMessage message = new ListMessage();                 message.setData(transmissionTemplate);                 message.setOffline(false);                 message.setOfflineExpireTime(GeXinBaseInfo.offExpireTime);                 String taskId = push.getContentId(message);                 IPushResult ret = push.pushMessageToList(taskId, convertToTargets(cidList));                 System.out.println(ret.getResponse().toString());

            }         });     }     

   //將使用者ID與client_id繫結記錄在個推服務上     public boolean bind(String alias, String cid){         IAliasResult bindSCid = push.bindAlias(GeXinBaseInfo.appId, alias, cid);         return bindSCid.getResult();     }     

    //解綁     public boolean unBind(String alias, String cid){         IAliasResult unBindSCid = push.unBindAlias(GeXinBaseInfo.appId, alias, cid);         return unBindSCid.getResult();     }          //ios推送     public void pushAPN(final APNPayload.DictionaryAlertMsg alertMsg             , final List<String> deviceTokens, String content){                 IGtPush push = new IGtPush(GeXinBaseInfo.host,                         GeXinBaseInfo.appkey, GeXinBaseInfo.master);

                APNTemplate t = new APNTemplate();

                APNPayload apnpayload = new APNPayload();                 apnpayload.setSound("");

                apnpayload.setAlertMsg(alertMsg);               //傳送的附加資訊,用於解析                 apnpayload.addCustomMsg("info",content);                 t.setAPNInfo(apnpayload);                 ListMessage message = new ListMessage();                 message.setData(t);                 IPushResult ret = push.pushAPNMessageToList(GeXinBaseInfo.appId, contentId, deviceTokens);                 System.out.println(ret.getResponse());     } }

邏輯設計: 使用者登入andorid攜帶client_id,iOS端攜帶device_token,檢查user_device中是否有記錄user_id與 client_id或user_id與device_token的組合,如果沒有插入組合,並且繫結這組資訊

public UserInfoJson login(HttpServletRequest request,                               HttpServletResponse response) {         String userName = request.getParameter("userName");         String password = request.getParameter("passWord");         String clientId = request.getParameter("clientId");         String deviceId = request.getParameter("deviceToken");         LoginUserPojo user = loginUserService.findByUserCode(userName);         if (user == null) {             return new UserInfoJson();         } else {             UserInfoJson userJson = getUserJson(user);             //繫結使用者與硬體             if (clientId != null && !clientId.trim().equals("")) {                 userJson.setClientId(clientId);                 int count = loginUserService.selectDeviceByClientId(user.getUserId(), clientId);                 if (count == 0) {                     GeXinMPushUtil.getInstance().bind(user.getUserId(), clientId);                     loginUserService.insertDeviceByClientId(user.getUserId(), clientId);                 }             }             if (deviceId != null && !deviceId.trim().equals("")) {                 userJson.setDeviceId(deviceId);                 int count = loginUserService.selectDeviceByDeviceId(user.getUserId(), deviceId);                 if (count == 0) {                     loginUserService.insertDeviceByDeviceId(user.getUserId(), deviceId);                 }             }             String encPassword = new SimpleHash("md5", password, new SimpleByteSourceFix(user.getSalt()), 2).toHex();             if (!encPassword.equals(user.getPassword())) {                 return new UserInfoJson();             } else {                 userJson.setToken(encPassword);                 return userJson;             }         }     }

登出登入:

public boolean loginOut(HttpServletRequest request,                               HttpServletResponse response) {         String userId = request.getParameter("userId");         String clientId = request.getParameter("clientId");         String deviceId = request.getParameter("deviceToken");         boolean result = false;        //取消繫結 if (clientId != null && !clientId.trim().equals(""))             loginUserService.deleteDeviceByClientId(userId, deviceId);             result = GeXinMPushUtil.getInstance().unBind(userId, clientId);         if (deviceId != null) {             try {                 loginUserService.deleteDeviceByDeviceId(userId, deviceId);                 result = true;             } catch (Exception e){                 result = false;                 e.printStackTrace();             }         }

        return result;     }

在傳送通知的方法中,加入推送的程式碼:

..............前面的程式碼使用者獲取NotificationPojo nPojo(通知內容),     List<String> sendUsers(傳送的使用者ID)     List<String> listAlias = new ArrayList<>();                 if (sendUsers != null && !sendUsers.isEmpty()) {                     for (LoginUserPojo userPojo : sendUsers) {                         // TODO: 16/1/26 getui these users                         listAlias.add(userPojo.getUserId());                     }                 }                 List<String> deviceTokens = new ArrayList<>();                 List<String> clientIds = new ArrayList<>();                 if (listAlias != null && !listAlias.isEmpty() && listAlias.size() != 0) {                     deviceTokens = loginUserService.selectDeviceTokens(listAlias);                     clientIds = loginUserService.selectClientIds(listAlias);                 }                 TransimissionContentPojo pojo = new TransimissionContentPojo(TransimissionContentPojo.TYPE_NOTI);                 pojo.setContentId(notificationPojo.getNotificationId());                 NotificationTemplate template = NotiTemplateFactory.produceNotiFromNoti(notificationPojo);                 if (clientIds.size() != 0 && !clientIds.isEmpty())                     GeXinMPushUtil.getInstance().push(template, clientIds);                 APNPayload.DictionaryAlertMsg alertMsg = NotiTemplateFactory.getDictionaryAlertMsg(notificationPojo.getTitle()                         ,notificationPojo);                 if (deviceTokens.size() != 0 && !deviceTokens.isEmpty())                     GeXinMPushUtil.getInstance().pushAPN(alertMsg, deviceTokens,new Gson().toJson(pojo));

.................這樣就可以將推送資訊傳送出去了

其中 selectDeviceTokens(List<String>  alias)的mybatis程式碼如下:

(使用MyBatis的sql如下      <select id="selectDeviceTokens" resultType="java.lang.String">         select device_id         from user_device         where device_id is not null and user_id in         <foreach collection="userIds" item="userId" index="index"                  open="(" close=")" separator=",">             #{userId}         </foreach>     </select>)

對於附加資訊,contentId的傳送,app的獲取,安卓端的獲取凡事:msg.content-------此內容為new Gson().toJson(pojo)的Json字串,可以解析獲取contentId的內容,然後更具contentId獲取Notification的詳情(傳送一次請求,sql查詢) 而IOS的處理比較複雜,msg.payload.info-----此內容為new Gson().toJson(pojo)的Json字串,因為IOS服務端傳送的是ListMessage,這是對應msg,listMessage設定了payLoad,payLoad設定了info(apnpayload.addCustomMsg("info",content);),因此提取額外資訊是msg.payload.info,info這個字端是在伺服器端設定的,當然也可以是其它名稱。 ---------------------  作者:VICHOU_FA  來源:CSDN  原文:https://blog.csdn.net/vichou_fa/article/details/50802222  版權宣告:本文為博主原創文章,轉載請附上博文連結!