웹마스터 팁
XE 로만든 앱 + 푸쉬기능 구현하기 (안드로이드)
2013.10.16 16:55
앱..이랄건없고 모바일웹을 제작했습니다.
http://ddbang.terainvest.co.kr/?m=1
주소를 공개해도되나 모르겠지만 그냥 살펴보시라고 넣어둡니다.
디자인/개발 단독작업이라 엉성한부분이좀 있습니다. 스크립트작업이나 디자인을 조금더 보완해야하긴합니다만..
무튼 되긴했습니다.
해당 모바일웹을 안드로이드 웹뷰 앱으로 제작했습니다.
말그대로 그냥 껍데기만있는 앱이지요.
껍데기만있고, 앱을실행하면 내부에선 웹브라우저가 동작하는 형태입니다.
굳이 앱을 만든 이유는.. 아무래도 푸쉬때문이겠죠 ^^
푸쉬서버는 parse.com에서 제공하는 월 100만건 무료 api를 이용합니다.
푸쉬내용은 XE알림센터를 이용해 알림센터가 전달하는 모든 내용을 푸쉬로 전달합니다.
이 팁은 저처럼 앱을 제작하시는분이 있을까봐 적어둡니다.
일단 빈 모듈을 하나 생성하시는게 작업에 유리합니다. 저는 app_module 이라는 모듈을 생성했습니다.
app_module.class.php 를 이용해 member 테이블에 obid 라는 필드를 추가하고, 단말기의 정보를 저장해줄 함수를 로그인 트리거로 걸어줍니다.
obid는 단말기의 고유번호이고, 트리거로 추가한 함수 두개중 하나는 고유번호를 세션에 저장해주는것 하나는 로그인할때 저장된세션에 있는 고유번호를 회원정보에 반영해 주는 부분 입니다.
require_once(_XE_PATH_.'modules/member/member.class.php'); class app_module extends member { /** * @brief install the module **/ function moduleInstall() { return new Object(); } /** * @brief chgeck module method **/ function checkUpdate() { $oDB = &DB::getInstance(); $oModuleModel = &getModel('module'); if(!$oDB->isColumnExists("member", "obid")) return true; if(!$oModuleModel->getTrigger('member.doLogin', 'app_module', 'controller', 'triggerAfterLogin', 'after')) return true; if(!$oModuleModel->getTrigger('moduleHandler.proc', 'app_module', 'controller', 'triggerModuleHandlerProc', 'after')) return true; return false; } /** * @brief update module **/ function moduleUpdate() { $oDB = &DB::getInstance(); if(!$oDB->isColumnExists("member", "obid")) $oDB->addColumn("member", "obid", "varchar","128"); $oModuleModel = &getModel('module'); $oModuleController = &getController('module'); if(!$oModuleModel->getTrigger('member.doLogin', 'app_module', 'controller', 'triggerAfterLogin', 'after')) $oModuleController->insertTrigger('member.doLogin', 'app_module', 'controller', 'triggerAfterLogin', 'after'); if(!$oModuleModel->getTrigger('moduleHandler.proc', 'app_module', 'controller', 'triggerModuleHandlerProc', 'after')) $oModuleController->insertTrigger('moduleHandler.proc', 'app_module', 'controller', 'triggerModuleHandlerProc', 'after'); return new Object(0, 'success_updated'); } function moduleUninstall() { return new Object(); } /** * @brief re-generate the cache files **/ function recompileCache() { } }
이제 controller 부분의 두개함수를 작성 해주어야겠죠?
/** * @brief Get ObjectID, Save Session */ function triggerModuleHandlerInit(){ if(Context::get('obid')){ $_SESSION["obid"] = Context::get('obid'); } } /** * @brief A trigger to add Object ID for Member */ function triggerAfterLogin(&$obj) { $member_srl = $obj->member_srl; if(!$member_srl) return new Object(); if(!$_SESSION["obid"]) return new Object(); $query = "update xe_member set `obid` = '".$_SESSION["obid"]."' where `member_srl` = ".$member_srl; $sql = mysql_query($query); if($sql){ unset($_SESSION["obid"]); return new Object(); }else{ return new Object(-1,"단말기 정보를 가져오는데에 실패했습니다."); } }
이제 푸쉬를 실제로 전송할 Model 클래스에 다음함수를 추가해줍니다.
function getPushMessage($v,$obid){ switch($v->type) { case 'D': $type = "글"; break; case 'C': $type = "댓글"; break; // 메시지. 쪽지 case 'E': $type = "쪽지"; break; } switch($v->target_type) { case 'C': $str = sprintf('%s님이 회원님의 %s에 "%s" 댓글을 남겼습니다.', $target_nick_name, $type, $v->target_summary); break; case 'M': $str = sprintf('%s님이 "%s" %s에서 회원님을 언급하였습니다.', $target_nick_name, $v->target_summary, $type); break; // 메시지. 쪽지 case 'E': $str = sprintf($lang->app_ncenter_message_string, $v->target_summary); break; } //푸쉬전송 $url = 'https://api.parse.com/1/push'; $appId = <!-- 수정하세요 parse.com appId -->; $restKey = <!-- 수정하세요 parse.com RESTKEY -->; $target_device = $obid; // using object Id of target Installation. $push_payload = json_encode(array( "where" => array( "objectId" => $target_device, ), "data" => array( "alert" => $str, "url" => getUrl('','act','procNcenterRedirect', 'notify', $v->notify, 'url', $v->target_url) ) )); $rest = curl_init(); curl_setopt($rest,CURLOPT_URL,$url); curl_setopt($rest, CURLOPT_RETURNTRANSFER, 1); curl_setopt($rest, CURLOPT_SSL_VERIFYPEER, 0); curl_setopt($rest,CURLOPT_PORT,443); curl_setopt($rest,CURLOPT_POST,1); curl_setopt($rest,CURLOPT_POSTFIELDS,$push_payload); curl_setopt($rest,CURLOPT_HTTPHEADER, array("X-Parse-Application-Id: " . $appId, "X-Parse-REST-API-Key: " . $restKey, "Content-Type: application/json")); curl_exec($rest); }
위함수는 CURL을 이용하여 parse.com에 푸쉬메세지를 전달합니다.
중요한부분 몇가지를 짚고넘어가자면,
curl_setopt($rest, CURLOPT_RETURNTRANSFER, 1);
이부분을 통해 결과값을 페이지에 뿌리지않고 변수에 저장해줍니다. 페이지에 뿌리게되면 트리거부분에서 에러가납니다.
(display handler와의 충돌~)
curl_setopt($rest, CURLOPT_SSL_VERIFYPEER, 0);
이부분은 CURL작업할때 많이들 빠뜨리시는 부분인데, https:// 로 데이터를 전송할땐 반드시 포함되어야합니다.
그리고, 메세지를 생성하는 과정에서 기존 알림센터와 살짝 다른부분이 있습니다.
우선 언어팩을 사용하실분은 global $lang; 을통해 사용하시면되고, 알림센터의 언어팩을 그대로사용할경우 푸쉬메세지에 태그가 그대로 노출되므로 ( <strong> ... ) 새 언어팩을 만드셔서 사용하시면 되겠습니다.
이제, 알림센터의 controller 파일을 조금 수정해줍니다.
else if($logged_info) { // 익명 노티가 아닐 때 로그인 세션의 회원정보 넣기 $args->target_member_srl = $logged_info->member_srl; $args->target_nick_name = $logged_info->nick_name; $args->target_user_id = $logged_info->user_id; $args->target_email_address = $logged_info->email_address; //푸쉬알림 추가 $oMemberModel = &getModel('member'); $push_sender_info = $oMemberModel->getMemberInfoByMemberSrl($args->member_srl); if($push_sender_info->obid){ $oAppModuleModel = &getModel('app_module'); $oAppModuleModel->getPushMessage($args,$push_sender_info->obid); } }
모듈을 업로드하고, 업데이트를하면 준비가 완료된겁니다.
이제 앱에서 첫페이지를 로드할때 get방식으로 obid 변수를 전달합니다.
단말기의 고유 object id를 담아 전달하면됩니다.
저의경우 다음과같은 형태로 전달했습니다.
http://ddbang.terainvest.co.kr/?m=1&obid=OBJECTID
그럼, 최초 페이지가 로딩될때 object ID를 세션에 저장하고 로그인이 될때 회원정보에 반영을 하게되지요.
그리고 회원정보에 obid가 반영되어 있는경우 알림센터에서 app_module 에 있는 model클래스의 함수를통해 푸쉬데이터를 생성하고, 전송합니다.
앱에서 들어온 푸쉬데이터의 data->url 을 통해 해당웹페이지를 로드해주면 되겠습니다. ^^
아래는 인증샷..
사실.. 이걸어떻게해야하나 하며 웹뷰앱 만드신분과 머리를 맞대고 고민을 많이했습니다만
이렇게 공개해보니 별거아니네요...
흠이 좀 있다면,,, model 클래스의 푸쉬전송함수를 푸쉬데이터 생성만하고 controller에서 처리하려했는데
...귀찮... ^^* 이해하시죠?
MVC패턴에 살짝 어긋나긴했지만 무튼 .. 도움되시길바랍니더 ~(__)~
ㅜㅠ 6시간만에 성공 했어요!!
모두 감사드립니다!!