투비교육포털 X-PUSH 적용 가이드

들어가기 전에

해당 개발가이드는 X-PUSH에 대한 기본 교육을 이수 하고 실제 프로젝트를 구현 시 적용했던 내용을 위주로 정리되므로, X-PUSH에 대한 상세 설명자료는 하단 X-PUSH 2.8.x / 사용자 메뉴얼을 참고하세요.

X-PUSH 2.8.x / 사용자 매뉴얼 ♣ http://docs.tobesoft.com/xpush-user-manual-2_8

X-PUSH 설치버전 : 2.8

사전준비사항

X-PUSH 설치

X-PUSH 메시지를 사용하기 위해서는 X-PUSH제품을 서버에 설치해야 하며, 설치에 대한 내용은 별도 문서를 작성하지 않는다. (해당 설치는 제품 구입시 별도 관련부서에서 진행합니다.)

단 '투비교육포털'에서 설정한 config 부분에 대해 별도 작성

X-PUSH 설치를 위해서는 JDK 1.8 이상 설치해야 합니다.

X-PUSH 2.8.x / 사용자 매뉴얼

기본경로

http://docs.tobesoft.com/xpush-user-manual-2_8

설치경로

http://docs.tobesoft.com/xpush-user-manual-2_8#e16d545088bcf0c9

모바일 Notification 정보

X-PUSH메시지를 모바일 알림 기능을 통해 메시지가 전달되어야 하기 때문에 각 OS별 안드로이드, iOS에 대한 Notification 정보 등록 및 인증키를 준비해야 합니다.

http://docs.tobesoft.com/appstore#a1c7a33e5eaa02ba

메시지 전송방식

X-PUSH에서는 기본 메시지 전달방식이 실시간, 신뢰성을 제공합니다.
'투비교육포털' 에서는 모바일에서 메시지를 수신해야 하기 때문에 기본 신뢰성 메시지 전달방식을 선택하였으며, 관리자 화면에서 메시지 전송시 실시간 메시지 또한 가능합니다.

AppBuilder

넥사크로플랫폼을 이용하여 개발된 소스는 별도 Android studio나, iOS xcode를 사용하지 않고 배포할 수 있도록 AppBuilder를 사용하여 패킹 함. 
Build 및 packing시 체크사항을 정리하였으며 기본 packing에 대한 내용은 다루지 않는다.

프로젝트에서 사용할 X-PUSH 오브젝트 등록하기

XPush 오브젝트는 기본 오브젝트로 등록되어 있지 않습니다. Project Explorer 창에서 XPush 오브젝트를 등록한 후 사용할 수 있습니다.

xpush

메시지 레이아웃(Message Layout) 정의

메시지 구조

항목

구분

설명

Topic Key

Topic Type

TOPIC TYPE

TOPIC_ID

TOPIC ID

Field Values

CODE

메시지 코드


MSG

PUSH메시지 (전송되는 메시지 내용)


MSG_TYPE

실시간/신뢰성 구분코드


YMD_TIME

발신일시 SORT용


MSG_KEY

신뢰성 메시지 KEY (PUSH에서 들어옴)


USER_ID

사용자 ID


Chk

삭제시 필요한 Filed

메시지의 구분을 나타내는 서로 다른 고유 키 값으로 동일한 Topic Key값을 가진 수신자에게만 메시지가 전달됩니다
실제 전달하고자 하는 내용입니다.
(하나의 메시지는 여러 개의 전달 값을 만들 수 있습니다.)

프로토콜 어댑터 속성

정의한 Message Layout 정의 파일의 위치와 이름을 X-PUSH 프로토콜 어댑터 속성으로 설정합니다.
넥사크로 스튜디오 프로토콜 설정에서 다음과 같은 방법으로 등록합니다.
소스참고
EduHub\mobile\Mobile_main_content.xfdl
//XPush Message 송/수신을 위한 Layout세팅            
this.fn_setXPuxh = function()
{	
	var objGUser = nexacro.getApplication().gdsUserInfo; 
	
	if(this.fn_IsMobileRuntime())
	{	
		this.XPush.set_layouturl("%USERAPP%XPushUrl/XPush_Message_Layout.xml");
	} else      
	{            
		this.XPush.set_layouturl("XPushUrl::XPush_Message_Layout.xml");
	}   

... 중략...

서비스 방식

로그인 사용자를 대상으로 합니다.

로그인 방법에는 크게 사용자(인터넷) 로그인과, 영업추가(성명,이메일)을 통한 방법 중 사용자(인터넷) 로
로그인을 한 경우에 해당 됩니다.

AppBuilder 사용

가능한 기본기능을 사용하여 Android Studio나, xcode를 사용하지 않고 개발 하였습니다.

메시지 유형

출결처리

입실과 퇴실 QR체크 또는 비대면 체크 시 메시지 전달됩니다.

QR체크를 통한 입/퇴실을 하는 경우 관리자 화면(QR Reader) 화면에서 메시지를 전송함

비대면 체크를 통한 입/퇴실을 하는 경우 비대면 화면에서 메시지를 전송합니다.

공지사항

관리자에 의한 메시지 전달 방식으로 전체 공지사항과 각 교육 회차별 신청자를 대상으로 메시지를 전달합니다.

교육회차별 대상은 참가자 개인이 아닌 교육 회차를 기준으로 전달됩니다.

메시지 전달방식

X-PUSH메시지 전달방식 중 실시간,신뢰성 전달방식 중 신뢰성을 기본으로 전달되며, 필요에 따라 실시간 전달이 가능합니다.

X-PUSH를 이용하여 메시지를 전송하기 위해서는 기본 신뢰성 메시지 방식으로 개발하였습니다.

사용자 화면 및 주요 소스

main_flow

메인화면

'투비교육포털' 메인화면 (로그인 전)

X-PUSH에 관련된 소스는 Mobile_main_content.xfdl 소스에 포함되어 있습니다.

소스참고
EduHub\mobile\Mobile_main_content.xfdl

KakaoTalk_20210312_143813765

X-PUSH를 수신하기 위해서는 로그인 과정을 진행해야 합니다.

주요 소스

this.fn_setXPushIpList : X-PUSH 접속 IP정보

this.fn_setXPushIpList = function()
{ 
  if(this.fn_UserLoginXPushCheck())   
  {
    var args = "UserID='" + nexacro.getApplication().GV_PUB_USER_ID + "'";
    var objgdsUserInfo = nexacro.getApplication().gdsUserInfo;
    if(objgdsUserInfo.getRowCount() > 0)
    {    
      var args = "UserID='" + objgdsUserInfo.getColumn(objgdsUserInfo.rowposition,"UserID") + "'";
    }  

    this.gfn_transCOMMClear();     
    this.gfn_addTransInfo("","output",args,"001,frmXPushMessage,6");	
    this.gfn_addTransInfo("","output2",args,"001,frmLogin,5");	
    //해당 서비스에서 DB에 저장되어 있는 XPUSH 서버 접속 정보를 가져온다. 	 	
}

해당 X-PUSH 접속 정보는 외부에 노출할 수 없어 생략하였습니다.

this.fn_setXPuxhDisconnect : X-PUSH 연결종료

//XPush Message 송/수신을 위한 Layout세팅         
this.fn_setXPuxhDisconnect = function()
{
  this.XPush.disconnect(); 
}

this.fn_setXPux : XPush Message 송/수신을 위한 Layout세팅

//XPush Message 송/수신을 위한 Layout세팅            
this.fn_setXPuxh = function()
{	
  var objGUser = nexacro.getApplication().gdsUserInfo; 
  if(this.fn_IsMobileRuntime())
  {	
    this.XPush.set_layouturl("%USERAPP%XPushUrl/XPush_Message_Layout.xml");
  } else      
  {            
    this.XPush.set_layouturl("XPushUrl::XPush_Message_Layout.xml");
  }     
 
  if(objGUser.getRowCount() > 0)      
  {   	  
    if(objGUser.getColumn(objGUser.rowposition,"LoginGubun") == "U")
    {			
      this.XPush.set_projectid("EduHub");	 //ProjectName
      this.XPush.set_protocolversion(3);   //Protocal

      /*    
      * connection 성공, 실패는 event 에서 발생 
      */ 
      this.XPush.set_iplist(this.ds_IpList.getColumn(this.ds_IpList.rowposition,"XPUSH_IPLIST"));  
      this.XPush.connect(objGUser.getColumn(objGUser.rowposition,"UserID"), "..."); //비번은 의미없음
      this.XPush.set_userid(objGUser.getColumn(objGUser.rowposition,"UserID"));
    }	
  }    
}

this.fn_setregisterTopic : 사용자 TOPIC 등록

this.fn_setregisterTopic = function()  
{    
  if(this.fn_UserLoginXPushCheck())
  {
    var objDs = nexacro.getApplication().gdsUserTopicList;
    for(var i=0;i<objDs.getRowCount(); i ++)
    {
      var ret = this.XPush.registerTopic(objDs.getColumn(i,"TOPIC_TYPE"),  
                   objDs.getColumn(i,"TOPIC_ID"));//개인별 신청교육내용 
    } 
		
    if(this.fn_IsMobileRuntime())
    { 		 
      //trace("deviceID : [" +  system.notificationtoken + "]");  
        this.XPush.registerDevice();
    }	              
		
    this.fn_setsubscribe();   
  } 	
}

this.fn_setunregisterTopic : 사용자가 push메시지 미수신으로 설정을 바꾸는 경우

//사용자가 push메시지 미수신으로 설정을 바꾸는 경우
this.fn_setunregisterTopic = function() 
{    
  var objDs = nexacro.getApplication().gdsUserTopicList;
  for(var i=0;i<objDs.getRowCount(); i ++)
  {
    var ret = this.XPush.unregisterTopic(objDs.getColumn(i,"TOPIC_TYPE"),  
                 objDs.getColumn(i,"TOPIC_ID"));//개인별 신청교육내용 
  } 
}

로그인 사용자가 알림 수신여부를 미수신으로 변경하는 경우 DB 세팅 후 XPUSH에 등록된 Topic정보를 삭제해야 합니다.

this.fn_setsubscribe : 로그인 사용자 TOPIC정보 등록

this.fn_setsubscribe = function()  
{	    
  var objgdsXPushMessage = nexacro.getApplication().gdsXPushMessage;
  var objDs = nexacro.getApplication().gdsUserTopicList;

// 로그인 처리 필요   
  if(this.fn_UserLoginXPushCheck())  
  {
    /* XPUSH 세팅정보 추가 2021-01-27  start */    
    for(var i=0;i<objDs.getRowCount(); i ++)
    {                      
       //this.XPush.subscribe(objDs.getColumn(i,"TOPIC_TYPE"), objDs.getColumn(i,"TOPIC_ID"), 
       this, objgdsXPushMessage, "insert", "fn_push_callback")
           this.XPush.subscribe(objDs.getColumn(i,"TOPIC_TYPE"),
           objDs.getColumn(i,"TOPIC_ID"), this, this.ds_XPushMessageTemp, "insert",
           "fn_push_callback")
    }     
  
    /* XPUSH 세팅정보 추가 2021-01-27  end */    
    this.fn_requestMessageCount();  
   }     
}

this.fn_requestMessageCount : 미수신 메시지 개수 조회

this.fn_requestMessageCount = function()  
{
  var objDs = nexacro.getApplication().gdsUserTopicList;
  for(var i=0;i<objDs.getRowCount(); i++) 
  {     
    this.XPush.requestMessageCount(objDs.getColumn(i,"TOPIC_TYPE"), objDs.getColumn(i,"TOPIC_ID"));
  }   
}

this.fn_pushDisplay : 수신된 알림정보 표시

this.fn_pushDisplay = function()  
{ 
  var objgdsXPushMessage = nexacro.getApplication().gdsXPushMessage; 
  this.stNotice.set_visible(true);
  this.stNotice.set_usedecorate(true);
	
  if(objgdsXPushMessage.getRowCount() > 0)
  {
    if(this.stNotice.text != "알림 <fc v='#d23c3a'><b v='true'>"
        + objgdsXPushMessage.getRowCount() + "건</b></fc>이 있습니다.")
    {		
      this.stNotice.set_left(150);
      this.stNotice.set_width(200);     		
      this.stNotice.set_text("알림 <fc v='#d23c3a'><b v='true'>" +
        objgdsXPushMessage.getRowCount() + "건</b></fc>이 있습니다."); 
        this.stNotice.set_cssclass("sta_WF_MainNotice");
     }	
  } else { 
    if(this.fn_UserLoginXPushCheck())  
    {		
      if(this.stNotice.text != "알림이 없습니다.")
			{				
			
		... 중략 ...      


		this.stNotice.set_cssclass("sta_WF_MainNoticeD");
	}  
	
  //메시지 화면이 오픈되어 있는 경우 새롭게 갱신해 준다. 
  if(nexacro.getApplication().mainframe.ChildFrame.form.divMain.form.divBody.form["fn_createXpushMessage"])
	{  
nexacro.getApplication().mainframe.ChildFrame.form.divMain.form.divBody.form.fn_delete("noSave");
	}
 
}

수신된 알림 정보를 메인화면에 표현합니다.

만약 현재 오픈된 화면이 알림 화면인 경우 해당 화면의 메시지 정보를 다시 그려 줄 수 있도록 Mobile_frmXPushMessage.xfdl 화면의 fn_delete("noSave"); 함수를 호출합니다.

this.fn_push_callback : XPUSH 알림 정보를 받기 위한 callback 함수

해당 함수는 this.fn_setsubscribe의 this.XPush.subscribe callback (fn_push_callback)에 정의되어 있습니다.
this.fn_push_callback = function(Row, ChangeColumn, AllColumns, Type, ActionType, MessageId) 
{  
  if(ActionType == "RELI") 
  {
    /* 수신확인 메시지 전송 */
    this.XPush.sendResponse(MessageId);
    this.ds_XPushMessageTemp.set_enableevent(false);
		
    this.ds_XPushMessageTemp.setColumn(Row,"MSG_KEY",MessageId);
    this.ds_XPushMessageTemp.setColumn(Row,"USER_ID",this.XPush.userid);
    this.ds_XPushMessageTemp.set_enableevent(true);   			
  } 
  
  var objgdsXPushMessage = nexacro.getApplication().gdsXPushMessage;	
  var nDupliRowCnt = objgdsXPushMessage.getCaseCount("MSG_KEY == '"+ MessageId +"'");

  if (nDupliRowCnt ==  0) {		       
    var toRow = objgdsXPushMessage.addRow();  
    objgdsXPushMessage.copyRow(toRow,this.ds_XPushMessageTemp, Row); 
    this.fn_pushDisplay();         
  }	    
}

this.XPush_onerror : XPUSH 오류처리 (오류메시지 발생시에 별도 처리로직 생략 backgroud에서 동작)

this.XPush_onerror = function(obj:nexacro.XPush,e:nexacro.XPushErrorEventInfo)
{
	if(e.message != null) {
	}   
};

e.statuscode 정보는 아래 내용을 참고하세요

// ------------------------------------

// -100 - Push 서버가 “Byec”를 보냈거나 서버와의 규약에 따라 종료되었습니다. (e.action이 -1임)

// -101 - 타임아웃 처리되었습니다.

// -200 - Command Auth Error. 현재 선택된 IP에 대해인증에 오류가 발생하였습니다.

// -201 - iplist 속성에 등록되어 있는 Push 서버로의 접속이 모두 실패했습니다.

// -202 - 데이터 전송 채널 인증(authentication)에 오류가 발생하였습니다.

// -300 - 서버로의 접속에 실패했습니다.

// -301 - 패킷 전송(send/recv) 오류가 발생하였습니다.

// -302 - 이미 PUSH서버에 접속되어 있습니다.

// -401 - X-PUSH 서버와 접속해제(disconnect) 요청을 실패했습니다.

// -501 - X-PUSH 서버로부터 메시지 수신중단(suspend) 요청을 실패했습니다.

// -601 - X-PUSH 서버로부터 메시지 수신 재시작(resume) 요청을 실패했습니다.

// -701 - X-PUSH 서버로 topic 등록/등록해제 요청을 실패했습니다.

// -801 - 메시지 포맷 버전 정보가 일치하지 않습니다.

// -901 - 신뢰성 메시지에 대한 수신응답 전송에 실패했습니다.

// -902 - 미수신 메시지 요청을 실패했습니다.

// -1001 - X-PUSH 서버로 모바일 DeviceToken 정보 등록요청을 실패했습니다.

// -1002 - X-PUSH 서버로 유저 topic 정보 등록요청(reqisterUser)이 실패했습니다.

// -1003 - X-PUSH 서버로 유저 topic 정보 등록해제(unregisterUser)요청이 실패했습니다.

// -1004 - 미수신 메시지 정보요청을 실패했습니다.

// -1072 - 디바이스 등록(RGST)시 중복된 경우 발생. registerDevice 기등록 정상오류

// -1092 - registerTopic 기등록 정상오류

this.XPush_onkeepalive

this.XPush_onkeepalive = function(obj:nexacro.XPush,e:nexacro.XPushKeepAliveEventInfo)
{
//	trace("KEEP");     	  
};

this.XPush_onsuccess : XPUSH 메시지 수신 성공처리

this.XPush_onsuccess = function(obj:nexacro.XPush,e:nexacro.XPushEventInfo)
{
  if(e.message != null) { 
  }
  if( e.action == 0 ) {
    this.fn_setregisterTopic();   
  } 
 
  if( e.action == 10) {
    if(e.message.returnvalue != undefined || e.message.returnvalue != null) { 
      var returnvalue = e.message.returnvalue;
      for(var i = 0; i < returnvalue.length; i++) {
        if(returnvalue[i].count > 0)
	{   
	  this.XPush.requestMessage(returnvalue[i].topictype, returnvalue[i].topicid);	
	}
      }  
    }
  }     
};

e.action = 10 // trace("requestMessageCount() success") 즉

미수신된 건수를 수신한 경우 XPUSH에 수신상태를 업데이트 하기 위해 requestMessage를 호출해 주어야 합니다.

Mobile_main 소스

소스참고
EduHub\mobile\Mobile_main.xfdl

재로그인 (XPUSH 알림수신 여부를 변경하는 경우 사용

this.fn_reLogin = function()  
{
  this.divMain.set_visible(false);      
  this.divBody.bringToFront();	
  
  this.divMain.set_visible(false);  
  this.divMenu.set_visible(false);  	
  nexacro.getApplication().gdsUserInfo.clearData();	
  nexacro.getApplication().gdsUserEduList.clearData();	
  nexacro.getApplication().gdsUserEduListSelect.clearData();	

  this.fn_xPush_reset();
  this.divBody.form.fn_setUserName();      
  this.fn_Login();
};

this.fn_xPush_reset : 이전에 수신된 XPUSH관련 정보를 모두 reset한다.

this.fn_xPush_reset = function()

{
  nexacro.getApplication().gdsUserState.clearData();	
  nexacro.getApplication().gdsUserTopicList.clearData();	
  nexacro.getApplication().gdsXPushMessage.clearData();	
  this.divBody.form.fn_setXPuxhDisconnect();   
  this.divBody.form.fn_pushDisplay();  
}

this.fn_goMain : 선택한 메뉴화면으로 이동(이동시 알림 정보를 갱신해 준다.)

/**
 * @description 해당 메뉴 화면으로 이동
*/
this.fn_goMain = function()
{  
  ... 중략 ...
  //메시시 화면이 오픈되어 있는 경우 새롭게 갱신해 준다. 
  //푸시 메시지 창을 닫을때 건수를 재 갱신해 주기 위한 용도 
  if(nexacro.getApplication().mainframe.ChildFrame.form.divBody.form["fn_pushDisplay"])
  {        
    nexacro.getApplication().mainframe.ChildFrame.form.divBody.form.fn_pushDisplay();
  }
}

로그인

'투비교육포털'의 로그인 방법은 크게 회원(인터넷신청), 비회원(영업대표신청)으로 나누어 진다. 
이때 XPUSH메시지를 받기 위해서는 회원(인터넷신청)으로 로그인 하는 사용자를 대상으로 서비스가 제공 된다.
소스참고
EduHub\mobile\Mobile_Login.xfdl

KakaoTalk_20210312_143347168

주요 소스

this.fn_goMain = function()
{
  var objGUserInfo = nexacro.getApplication().gdsUserInfo;
  if(this.tabTitle.tabindex == 0)
  {	
    if(objGUserInfo.getColumn(objGUserInfo.rowposition,"LoginGubun") == "U")
	{  
      if(nexacro.getApplication().gdsUserState.getRowCount() > 0)
	  {
        if(nexacro.getApplication().gdsUserState.getColumn(
               nexacro.getApplication().gdsUserState.rowposition,
              "MESSAGE_STATE") != "N")
		{     
		  /* XPUSH 세팅정보 추가 2021-01-27  start */  
		  this.parent.parent.parent.parent.divBody.form.fn_setXPushIpList();
		  /* XPUSH 세팅정보 추가 2021-01-27  end */  
		}	    
 	  }  else {     
	  /* XPUSH 세팅정보 추가 2021-01-27  start */  
	  this.parent.parent.parent.parent.divBody.form.fn_setXPushIpList();
	  /* XPUSH 세팅정보 추가 2021-01-27  end */  
    }  
   }     
 }
... 중략 ...
EduHub\mobile\Mobile_main_content.xfdl 에 있는 fn_setXPushIpList(); 함수를 호출

알림 (메인화면)

소스참고
EduHub\mobile\Mobile_main_content.xfdl

KakaoTalk_20210310_161851021_02

메시지가 수신되면 메인화면에 1 알림 건수가 표현된다.

알림 수신여부 설정

2 알림 수신여부는 상단 설정 아이콘을 통해 변경할 수 있다.

소스참고
EduHub\mobile\Mobile_frmSetup.xfdl

KakaoTalk_20210310_164207462

사용자에 의한 알림설정 값에 따라 해당 정보는 DB에 저장이 되며,
XPUSH 서버에 사용자 정보로 등록된 Topic정보를 삭제한다.

삭제처리의 경우 실제 DB에서 삭제가 아닌 Flag정보가 변경된다.

참고 : T_TOPIC 테이블의 ACTIVE 값을 N으로 변경

사용 : Y, 미사용 : N

알림 설정이 변경되면 XPUSH에 등록된 TOPIC정보를 재 설정해 주어야 하므로

로그아웃 후 다시 로그인 과정을 거쳐야 알림 설정 정보가 반영됩니다.

주요 소스

this.chk_Setup_onchanged = function(obj:nexacro.CheckBox,e:nexacro.CheckBoxChangedEventInfo)
{	
    if(objGds.getRowCount() > 0)
    {	
        this.fn_save();
    }		 
};


this.fnCallback = function(svcID, errorCode, errorMsg)
{
  switch(svcID)
  {   
		...중략 ...
    case "save":	  
	  if(this.chk_Setup.value == false)
	  {
        this.parent.parent.parent.parent.divBody.form.fn_setunregisterTopic();	 
	  }
...

변경된 설정값을 DB TABLE에 반영합니다.

이때 알림설정을 False로 한 경우에는 XPUSH의 설정정보도 변경해야 합니다.

즉 this.fnCallback함수

this.parent.parent.parent.parent.divBody.form.fn_setunregisterTopic();

를 호출하여 XPUSH등록된 Topic정보를 갱신합니다.

//메인화면 
//Mobile::Mobile_main_content.xfdl에 작성된 함수호출
this.parent.parent.parent.parent.divBody.form.fn_setunregisterTopic();
소스참고
EduHub\mobile\Mobile_main_content.xfdl
//사용자가 push메시지 미수신으로 설정을 바꾸는 경우
this.fn_setunregisterTopic = function() 
{    
	var objDs = nexacro.getApplication().gdsUserTopicList;
	for(var i=0;i<objDs.getRowCount(); i ++)
	{
		var ret = this.XPush.unregisterTopic(objDs.getColumn(i,"TOPIC_TYPE"),  objDs.getColumn(i,"TOPIC_ID"));//개인별 신청교육내용 
	} 
}

수신여부에 대한 상태값은 TABLE : T_USER_STATE에 관리됩니다.

알림

메인화면의 1 을 선택하게 되면 알림 화면으로 이동한다.

XPUSH에서 보내주는 Data를 받는 Dataset과, 실제 사용자에게 보여주는 메시지 관리용 Dataset을 분리하여 구현하였습니다.

소스참고
EduHub\mobile\Mobile_frmXPushMessage.xfdl

KakaoTalk_20210310_161851021_01

주요 소스

this.Mobile_frmMsgList_onload

알림 폼이 load되는 시점에 Global에 정의된 nexacro.getApplication().gdsXPushMessage Dataset에 건수가 있으면 해당 건수 만큼 수신된 메시지를 표현합니다.
this.Mobile_frmMsgList_onload = function(obj:nexacro.Form,e:nexacro.LoadEventInfo)
{
	if(this.fn_UserXPushSetCheck())
	{		
		this.objXPushMessage = nexacro.getApplication().gdsXPushMessage; 
		this.objXPushMessage.set_keystring("S:-YMD_TIME");
		this.fn_createXpushMessage();

this.fn_createXpushMessage

수신된 메시지를 Div와 Static 컴포넌트를 이용하여 동적으로 생성합니다.
this.fn_createXpushMessage = function()
{
	if(this.objXPushMessage.rowcount == 0){
		this.st_nodata.set_visible(true);
		this.st_msgCnt.set_visible(false); 
		this.btnDelete.set_visible(false);
		return;
	} else {

		this.st_nodata.set_visible(false);
		this.st_msgCnt.set_visible(true);
		this.btnDelete.set_visible(true);	
		this.st_msgCnt.set_text("<fc v='#D23C3A'> "+ this.objXPushMessage.rowcount +"</fc>건")
		var objDiv, objStDt, objSt, objStTitle, objChk;
		
		var objDivMsgMain = new Div("div_msgMain", 0, 94, null, 100, 0);
		this.addChild("div_msgMain", objDivMsgMain);
		objDivMsgMain.show();
		objDivMsgMain.set_visible(false);

		for(var i=0; i<this.objXPushMessage.rowcount; i++)
		{
			//div 생성 div_0, div_1, div_2....
			if(i == 0){
				objDiv = new Div("div_"+i, 30, 0, null, 200, 30);
			}
			else{  
				objDiv = new Div("div_"+i, 30, "div_"+(i-1)+":20", null, 200, 30);
			}
			objDivMsgMain.addChild("div_"+i, objDiv);
			objDiv.set_cssclass("div_WF_NoticeBg");
			objDiv.show();

			//div 안에 제목 static 생성 st_title0. st_title1, st_title2...
			objStTitle = new Static("st_title"+i, 20, 20, 160, 25);
			objDiv.addChild("st_title"+i, objStTitle);
			var sMsgType = this.objXPushMessage.getColumn(i, "TOPIC_TYPE"); 
			var sMsgTitle = (sMsgType == "9999" ? "교육관련메시지" : (sMsgType == "1000" ? "전체공지" : (sMsgType == "2000" ? "일반" : "미지정")))
			var sCssClass = (sMsgType == "9999" ? "sta_WF_NoticeEducation" : (sMsgType == "1000" ? "sta_WF_NoticeEmergency" : "sta_WF_NoticeNormal"))
			objStTitle.set_text(sMsgTitle + ""); 
			objStTitle.set_cssclass(sCssClass);
			objStTitle.show(); 
			
			//div 안에 일자 static 생성 st_dt0. st_dt1, st_dt2...
			objStDt = new Static("st_dt"+i, null, 20, 152, 25, 54);
			objDiv.addChild("st_dt"+i, objStDt);
			objStDt.set_cssclass("sta_WF_NoticeDate");
			
			//날짜 포맷 적용 위해 Calendar 에 set하여 포맷 get 
			this.cal_temp.set_value(this.objXPushMessage.getColumn(i, "YMD_TIME"));
			objStDt.set_text(this.cal_temp.text);
			objStDt.show(); 

			//div 안에 삭제용 checkbox 생성 chk_del0. chk_del1, chk_del2...
			//단 전체공지는 삭제할 수 없다.
			
			objChk = new CheckBox("chk_del"+i, null, 20, 25, 25, 19);
			objDiv.addChild("chk_del"+i, objChk);
			objChk.set_cssclass("chk_WF_NotiSelect");
			objChk.addEventHandler("onchanged", this.fn_chkCnanged, this);
			objChk.show(); 
			objChk.set_visible(false);		

			//div 안에 메세지 static 생성 st_msg0. st_msg1, st_msg2...
			objSt = new Static("st_msg"+i, 20, 55, null, 100, 18);
			objDiv.addChild("st_msg"+i, objSt);
			objSt.set_cssclass("sta_WF_NoticeMsg");
			objSt.set_usedecorate(true);
			objSt.set_text(this.objXPushMessage.getColumn(i, "MSG"));
			objSt.show(); 

		}	
	
		//div, static 사이즈 조정
		this.fn_setSize();	
	}
}

this.fn_setSize

this.fn_setSize = function()
{
  var nCnt = this.objXPushMessage.rowcount;
  var nH ;	
  for(var i=0; i<nCnt; i++)
  {
    var objDiv = this.div_msgMain.form.components["div_"+i];
    var objSt  = objDiv.form.components["st_msg"+i];		
    objSt.set_fittocontents("height");
    objDiv.set_height(objSt.getOffsetBottom()+20);
    if(i == (nCnt-1))	nH = objDiv.getOffsetBottom()+20;
  }	
  //마지막 div의 bottom값으로 div_msgMain height 변경
  this.div_msgMain.set_height(nH);
  this.div_msgMain.set_visible(true);
  this.resetScroll();	
}

KakaoTalk_20210310_161851021

this.btnDelete_onclick

수신된 메시지는 로그인 사용자에 의해 삭제기능을 제공하며, 전체 또는 단일 건으로 삭제할 수 있습니다.
this.btnDelete_onclick = function(obj:nexacro.Button,e:nexacro.ClickEventInfo)
{
  if(this.objXPushMessage.rowcount == 0) return;
  if(this.st_delCnt.visible){
    this.fn_delete("Save");  
    this.st_delCnt.set_text("0");
    this.st_delCnt.set_visible(false);
    this.btnCancel.set_visible(false);
    this.btnSelectAll.set_visible(false);
  } else {
    for(var i=0; i<this.objXPushMessage.rowcount; i++)
    {
      var objDiv = this.div_msgMain.form.components["div_"+i];
      var objChk =  objDiv.form.components["chk_del"+i];		
      objChk.set_visible(true);
    }	
    this.btnCancel.set_visible(true);
    this.btnSelectAll.set_visible(true);
  }
};

this.fn_delete

this.fn_delete = function(arg)

{
  var objDivMsgMain = this.removeChild("div_msgMain");  
  if((objDivMsgMain != undefined) && (this.isValidObject(objDivMsgMain)))  
  {  		
    objDivMsgMain.destroy(); 
    objDivMsgMain = null;				 	
  }
  
  if(arg == "noSave")
  { 
    this.fn_createXpushMessage();
  } else {
    this.fn_save();	
  }
}

알림 메시지는 로그인 사용자가 직접 삭제할 수 있습니다.

이때 삭제된 메시지는 DB에서 삭제되지 않으며 별도 FLAG를 관리하여 사용자 화면에서만 사라지며, 삭제되는 시점은 XPUSH의 cronTab기능에 의해 만료된 메시지가 삭제됩니다.

관리자 화면 및 주요 소스

main_flow

푸시메시지 관리

소스참고
EduHub\mobile\Mobile_frmXPushMessageManager.xfdl

xpush_manager

메시지 전송시 자주 발송하는 메시지를 DB에 저장하여 관리합니다.

TOPIC TYPE별 메시지 유형을 관리합니다.

푸시메시지발송

소스참고
EduHub\mobile\Mobile_frmXPushProvider.xfdl

푸시메시지발송

전송 가능한 메시지 길이는 Android와 iOS가 다르게 전달이 되므로, 전송 메시지는 최대 4줄을 넘기 않아야 하며. 만약 4줄이 넘는 경우 Notification에는 잘려서 표현되며, 전체 메시지는 알림 메시지 화면에서 확인이 가능합니다.

XPUSH 메시지 전송을 위한 Provider 소스

넥사크로플랫폼 X-API를 이용하여 UI호면에서 보내준 데이타를 이용해 XPUSH서버로 메시지를 전송하도록 구현합니다.

XPUSH 설치모듈 중 xpush-2.8.2\api\xpush-2.8.2_API.jar 모듈을 제공하며, 해당 모듈을 이용하여 XPUSH쪾으로 메시지를 전송합니다.

소스참고
WAS/jsp경로/XPush_Provider.jsp 소스 위치는 WAS의 환경에 따라 달라질 수 있습니다.
<%@ page import = "org.apache.commons.logging.*" %>
<%@ page import = "com.nexacro17.xapi.data.*" %>
<%@ page import = "com.nexacro17.xapi.tx.*" %>  
<%@ page import = "java.net.UnknownHostException.*" %>
<%@ page import = "com.nexacro.xpush.api.PushMessageProvider" %>
<%@ page import = "com.nexacro.xpush.api.PushResponse" %>
<%@ page import = "com.nexacro.xpush.fw.io.ConnectionClosedException" %>
<%@ page import = "com.nexacro.xpush.fw.service.provider.LoginFailException" %>
<%@ page import = "com.nexacro.xpush.fw.service.provider.PushMessage" %>
<%@ page import = "com.nexacro.xpush.message.Constants" %>
<%@ page import = "java.util.*" %>
<%@ page import = "java.sql.*" %>
<%@ page import = "java.io.*" %><%@ page contentType = "text/xml; charset=UTF-8" %><%! 
// Dataset value
public String  dsGet(DataSet ds, int rowno, String colid) throws Exception
{
    String value;
    value = ds.getString(rowno, colid);
    if( value == null )
        return "";
    else 
        return value;
} 

/**
* lpad 함수
*
* @param str   대상문자열, len 길이, addStr 대체문자
* @return      문자열
*/

public static String lpad(String str, int len, String addStr) {
    String result = str;
    int templen   = len - result.length();

    for (int i = 0; i < templen; i++){
          result = addStr + result;
    }    
    return result;
}

%><%
int nErrorCode = 0;
String strErrorMsg = "START";

HttpPlatformRequest pReq = new HttpPlatformRequest(request);
pReq.receiveData();
PlatformData in_pData = pReq.getData();

VariableList in_varList = in_pData.getVariableList();
String pushType = in_varList.getString("argPUSH_TYPE");
String pushMSG = in_varList.getString("argPUSH_MSG");

if(pushType == null)   
{
	pushType = "PUSH";
}

DataSet ds = in_pData.getDataSet("in_Provider");

try {    
   
	String host = "XPUSH설치된 서버 IP";
	int port = 10082;
	String id = "ID";
	String password = "PWD"; 

	int push_count = 1;

	for(int i = 0; i < ds.getRowCount(); i ++) {

		PushMessageProvider pushMessageProvider = new PushMessageProvider();
		try {
			 
			pushMessageProvider.setUseProject(true);
			
			pushMessageProvider.connect(host, port, id, password);
			PushMessage pushMessage = new PushMessage();

			pushMessage.setProjectID(dsGet(ds,i,"PROJECT_ID"));  //PROJECT ID 
			pushMessage.setAvailablePeriod(30);//일 단위 설정 
			pushMessage.setEmergencyMessage(true);
            //긴급여부 무조건 true 안드로이드 FCM 용  
			   
			if(pushType.equals("RELI"))    
			{	
				pushMessage.setActionType(Constants.ACTION_RELI_STRING);
			} else {
			
				pushMessage.setActionType(Constants.ACTION_PUSH_STRING);
			}
			pushMessage.setCharsetName("utf-8");
			pushMessage.setTopic(dsGet(ds,i,"TOPIC_TYPE"), dsGet(ds,i,"TOPIC_ID")); 
            //TOPIC TYPE과 ID 
			//메시지는 3개를 보내주는데  데이타 구분을 취해 TOPIC TYPE과 CODE, MSG로 전달 
			pushMessage.addData(dsGet(ds,i,"TOPIC_TYPE"));
			//숫자로 넘오느는 데이타를 3자리 문자로 변환하여 저장 
			pushMessage.addData(lpad(dsGet(ds,i,"CODE"),3,"0"));
			pushMessage.addData(dsGet(ds,i,"MSG"));  

			if(pushType.equals("RELI"))   
			{	
				pushMessage.addData("RELI");  
			} else {			   
				pushMessage.addData("PUSH");  
			}			
			
			Calendar today = Calendar.getInstance();
			int year = today.get(Calendar.YEAR);
			int month = today.get(Calendar.MONTH);
			int date = today.get(Calendar.DATE); 
			int hour = today.get(Calendar.HOUR_OF_DAY);
			int minute = today.get(Calendar.MINUTE);
			int second = today.get(Calendar.SECOND);

			StringBuffer sb = new StringBuffer();  //최신의 메시지를 sort하기 위해 메시지 시간을 전달 
			sb.append(year);
			sb.append(String.format("%02d",month+1));
			sb.append(String.format("%02d",date)); 
			sb.append(String.format("%02d",hour));
			sb.append(String.format("%02d",minute));
			sb.append(String.format("%02d",second));
			
			
			pushMessage.addData(sb.toString());  
			
			pushMessage.addData("KEY");  //Message Key
			pushMessage.addData("");  //사용자 ID
			pushMessage.addData("0");  //Chk 삭제 처리를 위한 선택컬럼 
			  
			
			PushResponse pushresponse = pushMessageProvider.sendPushMessage(pushMessage);
			System.out.println("response : " + pushresponse.isSucceed());
			pushMessageProvider.close();

			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

//		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
//			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (LoginFailException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ConnectionClosedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
    nErrorCode  = 0;
    strErrorMsg = "SUCC";
            
} catch (Throwable th) {
    nErrorCode  = -1;
    strErrorMsg = th.getMessage();
}

// PlatformData 
PlatformData out_pData = new PlatformData();

VariableList out_varList = out_pData.getVariableList();
out_varList.add("ErrorCode", nErrorCode);
out_varList.add("ErrorMsg" , strErrorMsg);


HttpPlatformResponse pRes = new HttpPlatformResponse(response, PlatformType.CONTENT_TYPE_XML, "UTF-8");
pRes.setData(out_pData);
pRes.sendData();
%>

XPUSH 상세 설정 '투비교육포털'

DB정보

신뢰성 데이타 전송을 위해서는 DB정보가 필요하며 MSSQL DB를 사용합니다.
DB TABLE의 경우 제품 설치시 사용한 포멧을 기준으로 사용하였으며, T_USER_MESSAGE TABLE에 대해
추가 컬럼을 만듭니다.

TABLE정보

XPUSH 기본 TABLE정보 변경

T_USER_MESSAGE TABLE 수정에 따른 TABLE Layout
T_USER_MESSAGE

구분

구분


id

기본


PROJECT_ID


USER_ID


MESSAGE_ID


MESSAGE_STATUS


CHECK_DATE


READ_STATE

추가

신뢰성 메시지 사용자 삭제여부

READ_DATE

신뢰성 메시지 사용자 삭제일자

READ_STATE, READ_DATE 컬럼은 로그인 사용자가 메시지를 확인 후 삭제를 하게 되면 실제 DB에서 삭제가 되지 않으며 삭제 Flag를 관리합니다. 이를 관리하기 위한 컬럼추가 정보입니다.

XPUSH 기능 구현을 위해 추가 생성 TABLE (XPUSH서버 설정과 무관)

EDU_XPUSH_MESSAGE

Column

Type

Desc

PROJECT_ID

varchar(32)

PROJECT ID

TOPIC_TYPE

varchar(32)

TOPIC TYPE

SEQ

int

table key

TITLE

varchar(500)

제목

XPUSH_MSG

varchar(4000)

기본 메시지

SEQ_ORD

int

순서

해당 TABLE은 관리자 화면에서 XPUSH메시지 전송시 기본 포멧을 등록해 놓고 필요시 불러서 사용하기 위한 기본 메시지 포멧정보를 관리합니다.
T_USER_STATE

Column

Type

Desc

USER_ID

varchar(50)

USER ID

MESSAGE_STATE

varchar(1)

수신여부 상태

CHECK_DATE

varchar(14)

수신여부 변경일시

해당 TABLE은 사용자가 XPUSH메시지 수신여부 변경시 '수신여부 상태'를 관리합니다.

xpush_config.xml

위치
XPUSH 서버경로/config/xpush_config.xml

DB정보

투비교육포털은 MSSQL DB를 사용하였습니다.

<service name="DbcpService" code="com.nexacro.xpush.service.dbConPool.DBCPService">
  <!-- mssql -->
  <attribute name="username">DB로그인 정보</attribute>
  <attribute name="password">DB로그인 정보</attribute>
  <attribute name="connectUri">jdbc:sqlserver://DB정보;databaseName=DB명</attribute>
  <attribute name="jdbcClassName">
        com.microsoft.sqlserver.jdbc.SQLServerDriver</attribute>
  <attribute name="validationQuery">select 1</attribute>

중략
...

username, password, connectUrl정보는 고객사 DB설정에 맞추어 변경해 사용해야 한다.

정기적인으로 DB 비밀번호가 변경되는 경우라면 반듯이 해당 설정 정보를 변경해 주어야 하며,

변경 후에는 XPUSH를 재기동 해야 합니다.

CronTabScheduleService

<service name="CronTabScheduleService"  code="com.nexacro.xpush.service.schedule.CronTabScheduleService">
<attribute name="taskCollector">
	<object code="com.nexacro.xpush.service.schedule.ScheduleTaskCollector">
    <!-- 매월 1일 0시 0분 메시지 삭제  -->
    <!-- 
		<invoke name="add">
			<argument type="java.lang.String">0 0 1 * *</argument> 
			<argument type="it.sauronsoftware.cron4j.Task">
				<object code="com.nexacro.xpush.service.schedule.DeleteMessageTask">
					<attribute name="dbcpService">
            <service-ref>#DbcpService</service-ref>
          </attribute>
        </object>             	 			
			</argument>
		</invoke> 
		-->

CronTab Schedule에서 삭제하는 기능 중 매월1일 0시 0분에 메시지 삭제하는 부분은 사용하지 않토록 주석처리 하였습니다.

APNS Multi Project & Multi App

Android, iOS에 필요한 인증서 발급 절차는 별도 문서 참조

iOS

<service name="IOS_PRO#1" code="com.nexacro.xpush.service.notification.InfoApnsWithProjectIDService" instance="singleton" management="false">
	<attribute name="ProjectID">EduHub</attribute>
	<attribute name="AppInfo" type ="java.util.HashMap">
    <!--  아래 내용은 인증서를 사전에 발급받아야 한다. -->
CFBundleURLName=F:\Project\EduHub_XPUSH\EduHubXpush_iOS_cert\EduHubXpush.p12,KeystorePassword,PKCS12,true,
  </attribute> 
</service>
형식

설정

예시

CFBundleURLName

com.tobesoft.EduHubXPush

KeystorePath

F:\Project\EduHub_XPUSH\EduHubXpush_iOS_cert\EduHubXpush.p12

KeystorePassword

iOS Store 비밀번호 (오픈불가)

KeystoreType

PKCS12

production

true

ProjectID : EduHub (프로젝트 ID)를 기술

KeystorePassword : 해당 내용은 고유비번으로 오픈 불가능 합니다.

<service name="ApnsNotifierService" code="com.nexacro.xpush.service.notification.ApnsNotifierService" instance="singleton" management="false">
	<attribute name="ApnsInfo">
		#IOS_PRO#1
  </attribute>
  ... 중략 ...

위에서 정의한 iOS servicd name을 기술해 준다.

Android

<service name="ANDROID_PRO#1" code="com.nexacro.xpush.service.notification.InfoFcmWithProjectIDService" instance="singleton" management="false">
	<attribute name="ProjectID">EduHub</attribute> 
	<attribute name="Apikey">FCM cloudMessage serverkey</attribute>
	<attribute name="SendID">FCM발신자ID</attribute>
</service>
형식

설정

예시

Apikey

FCM cloudMessage serverkey

SendID

FCM 발신자 ID

ProjectID : EduHub (프로젝트 ID)를 기입합니다.

<service name="GcmNotifierService" code="com.nexacro.xpush.service.notification.GcmNotifierService" instance="singleton" management="false">
	<attribute name="FcmInfo">
		#ANDROID_PRO#1
        </attribute>
        <attribute name="NotificationAttributeCommonServiceName">#NotificationAttributeCommonService</attribute>
... 중략 ...

위에서 정의한 Android servicd name을 기술해 줍니다.

notification.properties

위치
XPUSH 서버경로/notification.properties
title = 투비교육포털
body  = 새로운 메세지가 도착했습니다.\r\n사용자 계정으로 로그인 후 확인 가능합니다.

해당 내용은 모바일 환경에서 '투비교육포털' 어플이 종료되어 있는 경우

메시지 수신시 보여주는 내용 (이미지 참고)

KakaoTalk_20210310_165927799

메시지는 동일한 형태로 제공되며, 메시지 내용의 일부를 보여주는 기능만 사용합니다.

모바일 알림 메시지 변환(Notification Formatter) 개발

모바일 알림 문자 메시지 표현은 기본포멧을 사용할 수 있으며, 
Notification Formatter 를 별도로 개발하여 사용하게 되면 문제 메시지를 실제 전송하는 메시지로 표현이 가능합니다.

http://docs.tobesoft.com/xpush-user-manual-2_8#320a354e85d5c193

해당 기능을 사용할 때는 XPUSH 서버경로/notification.properties에서 정의된

notification.properties 설정값은 사용되지 않습니다.

주요 소스

XPush_notificaton

XPush_Notification.java (투비교육포털 메시지 변환소스)

import java.io.UnsupportedEncodingException;

import com.nexacro.xpush.fw.service.provider.MobileNotification;
import com.nexacro.xpush.fw.service.provider.PushMessage;
import com.nexacro.xpush.service.notification.NotificationFormatter;
import com.nexacro.xpush.service.notification.type.NotificationPayload;

import jp.ossc.nimbus.core.ServiceManagerFactory;
import jp.ossc.nimbus.service.log.Logger;

public class XPush_Notification extends NotificationFormatter {
	private final Logger logger = ServiceManagerFactory.getLogger();
	  
	public NotificationPayload format(PushMessage pushMessage, NotificationPayload payload) {
		String title = "투비교육포털";
		String body = "새로운 메세지가 왔습니다.";
		
		String action = pushMessage.getActionType();
		payload.setCommand(action); 
		
		String topicType = pushMessage.getTopicType();
		String topicId = pushMessage.getTopicId();
		payload.addParam(NotificationPayload.TOPIC_TYPE, topicType);
		payload.addParam(NotificationPayload.TOPIC_ID, topicId);
		 
		/*
		 * 추가 아규먼트
		 */
		//payload.addParam("0000000001", "111");

		/*
		 * 메시지 변경
		 */
		String bodyMsg = null;

        try {  
        	bodyMsg = new String(pushMessage.getValueBytesList().get(2), "UTF-8");
            
        } catch (UnsupportedEncodingException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        body = bodyMsg;
            
        payload.addParam("title", title);
		payload.setMessage(body);
		
		if (payload.isTooBig()) {
			NotificationPayload summarized = summarize(payload);
			return summarized;
		}
		  
		return payload;
	}

	@Override
	public NotificationPayload format(MobileNotification arg0, NotificationPayload arg1) {
		// TODO Auto-generated method stub
		return null;
	}
}

수신된 알림화면

KakaoTalk_20210317_152010520

참고사항

해당 기능을 구현하지 않으면 default 알림메시지 형태로 수신합니다.

KakaoTalk_20210310_165927799

개발 시 참고사항 (FAQ)

실시간 메시지의 경우 사용자가 확인하지 않으면 해당 메시지는 어떻게 되는가?

실시간 메시지의 경우 '투비교육포털' 실행 및 로그인 상태에서 수신이 가능하며, 확인하지 않은 메시지는
해당 어플을 종료하게 되면 사라집니다.

실시간은 DB에 저장되지 않는다.

신뢰성 메시지 유효 기간은 어떻게 되는가?

신뢰성 메시지의 경우 기본 DB에 1개월간 저장이 되며, 이후 자동 삭제되도록 처리 하였으며, DB에 저장하는 기간은 설정하는 일정에 따라 달라질 수 있습니다.
소스참고
WAS/jsp경로/XPush_Provider.jsp 소스에 설정값을 정의합니다.
pushMessage.setAvailablePeriod(30);//일 단위 설정

신뢰성 메시지인 경우에도 유효기간 동안 메시지를 확인하지 않으면 해당 데이타는 DB에서 삭제됩니다.

'투비교육포털' 의 경우 사용자가 직접 수신된 메시지를 삭제할 수 있습니다.

이때 삭제는 DB에서 삭제처리는 되지 않으며 Flag값을 조정함으로서 사용자 화면에 보여지지 않습니다.

이중화 지원되는가?

XPUSH 제품은 서버 확장 및 이중화 기능을 지원됩니다. 
해당 내용은 서버 아키텍쳐 설계 영역입니다. 

XPUSH는 기본 독립서버 운영을 권장하나, '투비교육포털'에서는 기존 Application과 같은 서버에 
설치되었습니다.

WAS에서 특정 TOPIC에서 Publish 할 수 있는가?

기본사항을 가능합니다.

브라우저에서 PUSH서버에 SubScribe 하는 방법

프로그램 구현방법에 따라 달라지며, 프로그램작성시 가능합니다.

Web서버와 WAS가 분리되어 있는 경우 브라우저는 Web에만 접근가능

Client에서 XPUSH가 설치되어 있는 서버를 직접 바라볼 수 있어야 합니다. 
따라서 방화벽을 오픈해 주거나 프록시 서버에서 접근 가능하도록 설정해 주어야 합니다.

xeni는 war로 되어 있는데 어떻게 설치해야 하나? 독립적인 Web App?

XPUSH설치는 단독으로 실행해 주는 것을 권장합니다.

즉 XPUSH용 별도 서버 구성

push서버 설치시 was와 다른 계정으로 설치하는 이유?

별도의 이유는 없으며, 통상 관리차원에서 서버 담당자가 하나로 관리할 수도 있고, 제품별로 별도 계정을 만들어 사용할 수 있습니다.

Client에서 XPUSH서버거 여러대 인 경우 몇번 서버로 연결되는지 연결순서를 알 수 있는가?

예) 123.333.123.1,  123.333.123.2,  123.333.123.3, 
3개의 서버가 있다고 가장하는 경우 연결순서는?

제품에서는 별도 로드발란싱를 지원하지 않으며 random으로 호출 됨

Client에서는 L4 주소를 바라보고 L4에서 분배하도록 설계해야 함

메시지 전송 후 삭제되는 시점

XPUSH에 등록된 메시지 즉 (Provider)에서 전송한 메시지는 유효기간이 어떻게 되는지 알고 싶습니다.

메세지를 보낼때 pushMessageNOTI.setAvailablePeriod(5) 에 세팅된 일자가 되면

XPUSH에서 메시지가 삭제 됩니다.

신뢰성 메시지를 보냈다고 하더라도, EXPIRATION_DATE 가 되면 수신할 수 없으며,

만약 삭제 기능을 사용하지 않고자 한다면 pushMessageNOTI.setAvailablePeriod(5) 사용하지 않거나

xpush_config에서 삭제 부분을 주석처리하거나 삭제하면 됩니다.

XPUSH 신뢰성 메시지 전송을 위해 생성하는 TABLE 명은 변경할 수 있나요? 그리고 컬럼을 추가하여 사용이 가능한지 알고 싶습니다.

제품 설치시 생성하는 TABLE 명은 수정이 불가능합니다. 
단 TABLE 생성시 컬럼 추가는 가능하며, 이때 디폴트 값 null이 허용 되어야 합니다.

XPUSH로 전달되는 메시지 길이는 제한이 있는가?

Topic Type : 4byte
Topic Id : 최대 256byte
Field Values : 구분자를 포함하여 최대 4,000byte

참고 모바일 알림 메시지 Notification의 길이는 XPUSH에서 보내주는 길이를 모두 표현하지 않으며,

Android의 경우 최대 8줄, iOS의 경우 4줄이 표현되며 나머지는 자동으로 짤립니다.

APN(Apple Push Notification Service) API 변경

Updated APNs provider API deadline

October 9, 2020
The HTTP/2-based Apple Push Notification service (APNs) provider API lets you take advantage of great features, such as authentication with a JSON Web Token, improved error messaging, and per-notification feedback. If you send push notifications with the legacy binary protocol, we strongly recommend upgrading to the APNs provider API.
To give you additional time to prepare, the deadline to upgrade to the APNs provider API has been extended to March 31, 2021. APNs will no longer support the legacy binary protocol after this date.

참고사항

현재 PUSH 서버가 사용하는 프로토콜은 legacy binary protocol 입니다.

legacy binary protocol 프로콜이 3월 31 일 종료됨


이전에 설치된 XPUSH는 변경된 jar모듈로 변경이 필요합니다.


3월 이후 부터는 변경된 모듈을 적용 후 사용 가능합니다.

2.8.3 모듈부터 적용

Apple 푸시 알림 서비스 서버 인증서 업데이트

apple-1

기존 X-PUSH는 HTTP/2 Protocol를 사용하고 있지 않습니다.

그러나, 이번 긴급 패치되는 X-PUSH는 HTTP/2 Protocol 사용함으로

3/29이전까지는 필히 루트 인증서 업데이트를 해야 합니다.


해당 업데이트를 해야 만 알림을 받을 수 있습니다.

https://developer.apple.com/kr/news/?id=7gx0a2lp