예전부터 페이스북 API중에 Chat API가 있었습니다. 카카오톡의 게임 홍보 메시지처럼 페이스북 내에 있는 메신져 플랫폼에 메시지를 발송할 수 있는 API였는데요. 기존에 사용 빈도가 적었던것인지 사용에 특별한 제약 사항이 없는 자유롭게 사용할 수 있는 API였습니다. 심지어 Graph API를 이용해서 서버상에서 호출하는것도 가능했었습니다. 하지만 언제부터인가 기존의 Chat API가 Deprecated 되었습니다.
2014년 4월 30일에 기존의 XMPP기반의 채팅 API가 Deprecate 될것임을 공지하였었고 2015년 4월 30일에 더이상 이 API들을 사용할 수 없게 되었습니다. 기존에 제공되었던 API를 사용하여 활용할 수 있는 기능은 다음과 같았습니다.
addUserToGroup : 특정 유저를 그룹 채팅에 추가합니다.
changeArchivedStatus : 채팅을 보관 상태로 변경. 채팅 목록에서 즉시 사라지며 보관함에 들어갑니다.
deleteMessage : 이미 발송된 메시지를 삭제합니다.
deleteThread : 채팅을 삭제합니다.
getCurrentUserID : 현재 로그인되어있는 유저의 페이스북 ID를 가져옵니다.
getFriendsList : 친구의 페이스북 계정 정보를 가져옵니다. 이름, 성별, 프로필사진, 생일여부등을 알 수 있습니다.
getOnlineUsers : 친구들의 온라인 상태 정보를 가져옵니다. 오프라인, 유휴상태, 온라인, 모바일사용중으로 분류됩니다.
getThreadHistory : 현재 채팅의 히소토리를 가져옵니다.
getThreadList : 채팅 목록을 가져옵니다.
getUserID : 페이스북상의 이름으로 ID를 가져옵니다.
getUserInfo : 페이스북 ID로 계정의 정보를 가져옵니다.
markAsRead : 특정 채팅의 내용을 모두 읽은것으로 지정합니다.
removeUserFromGroup : 그룹에서 유저를 제거합니다.
searchForThread : 채팅방의 이름을 검색합니다.
sendMessage : 메시지를 발송합니다. 텍스트, 스티커ID, 파일/이미지, URL을 포함할 수 있습니다.
sendTypingIndicator : “유저가 글을 작성중입니다”라는 상태 메시지를 상대측에 보여줍니다.
setTitle : 그룹 채팅의 방 이름을 설정합니다.
그리고 2015년 3월 25일에 새로운 메신저 플랫폼이 발표되었습니다. 결과적으로 기존의 XMPP 버전의 API들과는 차원이 다르게 기능이 축소되었습니다. 아마도 친구들의 정보라던지 온라인 상태를 가져다 쓸 수 있다는 점을 문제로 생각한게 아닐까 생각됩니다. 페이스북 자체의 새로운 메신저 플랫폼에 대해서 밀어붙이던 시기이기도 했고요. 아무래도 기존에는 메신저 기능을 페이스북의 +@ 기능정도로 생각하다가 좀 더 적극적인 방향으로 생각해보기로 하면서 방향을 폐쇄적으로 변경한것인지도 모르겠습니다. 다음은 페이스북의 메신져 플랫폼에 대한 소개글을 번역한 내용입니다.
Messenger Platform
메신저 플랫폼은 개발자들이 개발중인 앱에 메신저를 통합하는 과정을 좀 더 쉽게 해줍니다. 그렇게 함으로 써 메신저를 사용하는 6억이 넘는 사용자들이 GIF, 사진, 비디오, 음성메시지 등등을 활용하여 새롭고 재미있게 그들을 표현할 수 있는 방법을 찾을 수 있을 것입니다. 이 메신저 플랫폼을 사용하면 앱의 컨텐츠들은 개인 혹은 그룹 메시지들이 창의적이고 표현적인 대화가 이루어질 수 있도록 해줄것입니다. 또한 개발자들에게 성장과 재참여를 할 갖게할 기회를 제공할 것입니다.
메신저 플랫폼의 앱은 메신저를 통해 유저로 하여금 앱을 설치하도록 유도하거나 앱의 컨텐츠를 사용하여 답장을 할 수 있게 해줍니다. 만약 메시지를 받은 유저가 앱이 설치되어있지 않아서 바로 답장을 할 수 없는 상황이라면 메신저를 앱스토어로 이동시켜 바로 설치를 할 수 있도록 유도할 것입니다. 이 과정은 유저가 친구들과의 대화를 통해서 자연스럽게 새로운 앱을 추천받게 되는 과정이 될 것입니다.
메신저 플랫폼을 이용하여 개발자는 앱의 사용율을 높일 수 있습니다. 만약 메시지를 받은 유저가 이미 그 앱을 설치한 상태라면 그들은 바로 메시지의 이미지에 함께 표시되는 답장(Reply) 버튼을 누를 수 있습니다. 그러면 바로 해당 앱을 실행시켜 결과를 가지고 메신저에 바로 공유할 수 있습니다.
기본적인 이미지, 동영상, 텍스트를 전송하는것을 Basic 메시지라고 부르고 이렇게 설치나, 답장을 유도할 수 있는 메시지를 Optimized 메시지라고 부릅니다. 이 Optimized 메시지를 사용하기 위해서는 몇가지 제약 사항이 있습니다.
컨텐츠 공유하기를 하였을 때 선택가능한 공유 선택지중에 페이스북 메신저가 가장 첫번째로 떠야 합니다. 유저 경험 차원이라는데 그냥 페이스북의 욕심이겠죠^^;
페이스북이 제공하는 통계분석툴(Analytics)를 반드시 붙여야 합니다. 이것을 붙임으로써 각종 통계를 볼 수 있게 된다고 합니다. 근데 강제 하는 이유는 페이스북도 궁금해서겠지요^^?
이러한 기능을 사용하기 위해서는 페이스북에 앱 심사를 거쳐야 합니다. 이때에 당신의 앱은 앱스토어에 이미 출시되어있어야 합니다.
몇몇 앱의 메신저 통합된 사례는 메신저의 대화상의 새로운 탭을 통해서 바로 연결되는 홍보 기회를 가질 수 있습니다. 이 메뉴를 통해 이미 설치된 앱을 바로 실행할 수 있는 바로가기로 사용될 수 있고 새로운 유저가 시도해 볼 수 있는 기회를 얻을 수 도 있습니다.
Business on Messenger
메신저 플랫폼 이외에는 어떻게 사람들과 기업간의 커뮤니케이션을 개선시킬 수 있을까를 목적으로 만들어진 메신저 비지니스 플랫폼도 있습니다. 이 메신저 비지니스 플랫폼은 다음과 같은것을 가능케 합니다. 유저가 어떤 기업의 사이트에서 물건을 구매하는 과정에서 유저는 기업과 대화를 시작하게 됩니다. 구매가 확정되었는지 배송 상태는 어떻게 되는지 메신저를 통해 받을 수 있으며, 특정 폼 없이 자유로운 양식으로 기업에게 질문을 하고 빠른 답장을 받을 수 있습니다.
현재 Everlane, Zulily, Zendesk 등의 기업에서 적용하여 경험을 실시간 채팅 경험을 만들어 나가고 있습니다. 더 자세한 내용은 [이곳]을 참고하시기 바랍니다.
참고 : https://developers.facebook.com/docs/messenger/overview
// lib/display/feed.php has to be declared here for scope issues. // This keeps display/feed.php cleaner and easier to understand. include_once $_SERVER[‘PHP_ROOT’].’/lib/display/feed.php’; include_once $_SERVER[‘PHP_ROOT’].’/lib/monetization_box.php’;
// todo: password confirmation redirects here (from html/reset.php), // do we want a confirmation message?
param_get_slashed(array( ‘feeduser’ => $PARAM_INT, //debug: gets feed for user here ‘err’ => $PARAM_STRING, // returning from a failed entry on an orientation form ‘error’ => $PARAM_STRING, // an error can also be here because the profile photo upload code is crazy ‘ret’ => $PARAM_INT, ‘success’ => $PARAM_INT, // successful profile picture upload ‘jn’ => $PARAM_INT, // joined a network for orientation ‘np’ => $PARAM_INT, // network pending (for work/address network) ‘me’ => $PARAM_STRING, // mobile error ‘mr’ => $PARAM_EXISTS, // force mobile reg view ‘mobile’ => $PARAM_EXISTS, // mobile confirmation code sent ‘jif’ => $PARAM_EXISTS, // just imported friends ‘ied’ => $PARAM_STRING, // import email domain ‘o’ => $PARAM_EXISTS, // first time orientation, passed on confirm ‘verified’ => $PARAM_EXISTS)); // verified mobile phone
param_post(array( ‘leave_orientation’ => $PARAM_EXISTS, ‘show_orientation’ => $PARAM_INT, // show an orientation step ‘hide_orientation’ => $PARAM_INT)); // skip an orientation step
// upcoming events events_check_future_events($user); // make sure big tunas haven’t moved around $upcoming_events = events_get_imminent_for_user($user);
// this is all stuff that can be fetched together! $upcoming_events_short = array(); obj_multiget_short(array_keys($upcoming_events), true, $upcoming_events_short); $new_pokes = 0; //only get the next N pokes for display //where N is set in the dbget to avoid caching issues $poke_stats = get_num_pokes($user); get_next_pokes($user, true, $new_pokes); $poke_count = $poke_stats[‘unseen’];
$targeted_data = array(); home_get_cache_targeted_data($user, true, $targeted_data); $announcement_data = array(); home_get_cache_announcement_data($user, true, $announcement_data); $orientation = 0; orientation_get_status($user, true, $orientation); $short_profile = array(); profile_get_short($user, true, $short_profile); // pure priming stuff privacy_get_network_settings($user, true); $presence = array(); mobile_get_presence_data($user, true, $presence); feedback_get_event_weights($user, true); // Determine if we want to display the feed intro message $intro_settings = 0; user_get_hide_intro_bitmask($user, true, $intro_settings); $user_friend_finder = true; contact_importer_get_used_friend_finder($user, true, $used_friend_finder); $all_requests = requests_get_cache_data($user); // FIXME?: is it sub-optimal to call this both in requests_get_cache_data and here? $friends_status = statusupdates_get_recent($user, null, 3); memcache_dispatch(); // populate cache data
// Merman’s Admin profile always links to the Merman’s home if (user_has_obj_attached($user)) { redirect(‘mhome.php’, ‘www’); }
if (is_array($upcoming_events)) { foreach ($upcoming_events as $event_id => $data) { $upcoming_events[$event_id][‘name’] = txt_set($upcoming_events_short[$event_id][‘name’]); } }
// new pokes (no more messages here, they are in the top nav!) if (!user_is_guest($user)) { tpl_set(‘poke_count’ , $poke_count); tpl_set(‘pokes’ , $new_pokes); }
// get announcement computations tpl_set(‘targeted_data’ , $targeted_data); tpl_set(‘announcement_data’ , $announcement_data);
// user info tpl_set(‘first_name’ , user_get_first_name(txt_set($short_profile[‘id’]))); tpl_set(‘user’ , $user);
// decide if there are now any requests to show $show_requests = false; foreach ($all_requests as $request_category) { if ($request_category) { $show_requests = true; break; } } tpl_set(‘all_requests’, $show_requests ? $all_requests : null);
// set next step if we can if (!$orientation) { user_set_next_step($user, $short_profile); }
// note: don’t make this an else with the above statement, because then no news feed stories will be fetched if they’re exiting orientation if ($orientation) { extract(orientation_get_const());
$stories = orientation_get_stories($user, $orientation); switch ($get_err) { case $ORIENTATION_ERR_COLLEGE: $temp = array(); // the affil_retval_msg needs some parameters won’t be used $stories[$ORIENTATION_NETWORK][‘failed_college’]=affil_retval_msg($get_ret, $temp, $temp); break; case $ORIENTATION_ERR_CORP: $temp = array(); // We special case the network not recognized error here, because affil_retval_msg is retarded. $stories[$ORIENTATION_NETWORK][‘failed_corp’] = ($get_ret == 70) ? ‘The email you entered did not match any of our supported networks. ‘ . ‘Click here to see our supported list. ‘ . ‘Go here to suggest your network for the future.’ : affil_retval_msg($get_ret, $temp, $temp); break; }
// Mobile web API params if ($get_mobile) { $stories[$ORIENTATION_ORDER[$ORIENTATION_MOBILE]][‘sent_code’] = true; $stories[$ORIENTATION_ORDER[$ORIENTATION_MOBILE]][‘view’] = ‘confirm’; } if ($get_verified) { $stories[$ORIENTATION_ORDER[$ORIENTATION_MOBILE]][‘verified’] = true; } if ($get_me) { $stories[$ORIENTATION_ORDER[$ORIENTATION_MOBILE]][‘error’] = $get_me; } if ($get_mr) { $stories[$ORIENTATION_ORDER[$ORIENTATION_MOBILE]][‘view’] = ‘register’; }
if (orientation_eligible_exit($orientation)) { tpl_set(‘orientation_show_exit’, true); } tpl_set(‘orientation_stories’, $stories);
//if in orientation, we hide all feed intros (all 1’s in bitmask) $intro_settings = -1;
} tpl_set(‘orientation’, $orientation);
// Rooster Stories if (!$orientation && ((get_site_variable(‘ROOSTER_ENABLED’) == 2) || (get_site_variable(‘ROOSTER_DEV_ENABLED’) == 2))) { $rooster_story_count = get_site_variable(‘ROOSTER_STORY_COUNT’); if (!isset($rooster_story_count)) { // Set default if something is wrong with the sitevar $rooster_story_count = 2; } $rooster_stories = rooster_get_stories($user, $rooster_story_count, $log_omissions = true); if (!empty($rooster_stories) && !empty($rooster_stories[‘stories’])) { // Do page-view level logging here foreach($rooster_stories[‘stories’] as $story) { rooster_log_action($user, $story, ROOSTER_LOG_ACTION_VIEW); } tpl_set(‘rooster_stories’, $rooster_stories); } }
// set the variables for the home announcement code $hide_announcement_tpl = ($intro_settings | $HIDE_INTRO_BITMASK) & $HIDE_ANNOUNCEMENT_BIT; // if on qa/dev site, special rules $HIDE_INTRO_ON_DEV = get_site_variable(‘HIDE_INTRO_ON_DEV’); if ((IS_QA_SITE || IS_DEV_SITE) && !$HIDE_INTRO_ON_DEV) { $hide_announcement_tpl = 0; }
// page length using feed stories if ($orientation) { $ads_page_length_data = max($ads_page_length_data, count($stories) * 5); } tpl_set(‘ads_page_length_data’, $ads_page_length_data);
$feed_stories = null; if (!$orientation) { // if they’re not in orientation they get other cool stuff // ad_insert: the ad type to try to insert for the user // (0 if we don’t want to try an insert) $ad_insert = get_site_variable(‘FEED_ADS_ENABLE_INSERTS’);