Tag Archives: API

2015년에 변경된 페이스북 메신저 API 개요

Facebook-Developers-Logo

예전부터 페이스북 API중에 Chat API가 있었습니다. 카카오톡의 게임 홍보 메시지처럼 페이스북 내에 있는 메신져 플랫폼에 메시지를 발송할 수 있는 API였는데요. 기존에 사용 빈도가 적었던것인지 사용에 특별한 제약 사항이 없는 자유롭게 사용할 수 있는 API였습니다. 심지어 Graph API를 이용해서 서버상에서 호출하는것도 가능했었습니다. 하지만 언제부터인가 기존의 Chat API가 Deprecated 되었습니다.

facebook_messenser_api_overview_01

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, 사진, 비디오, 음성메시지 등등을 활용하여 새롭고 재미있게 그들을 표현할 수 있는 방법을 찾을 수 있을 것입니다. 이 메신저 플랫폼을 사용하면 앱의 컨텐츠들은 개인 혹은 그룹 메시지들이 창의적이고 표현적인 대화가 이루어질 수 있도록 해줄것입니다. 또한 개발자들에게 성장과 재참여를 할 갖게할 기회를 제공할 것입니다.

메신저 플랫폼의 앱은 메신저를 통해 유저로 하여금 앱을 설치하도록 유도하거나 앱의 컨텐츠를 사용하여 답장을 할 수 있게 해줍니다. 만약 메시지를 받은 유저가 앱이 설치되어있지 않아서 바로 답장을 할 수 없는 상황이라면 메신저를 앱스토어로 이동시켜 바로 설치를 할 수 있도록 유도할 것입니다. 이 과정은 유저가 친구들과의 대화를 통해서 자연스럽게 새로운 앱을 추천받게 되는 과정이 될 것입니다.

facebook_messenser_api_overview_02

메신저 플랫폼을 이용하여 개발자는 앱의 사용율을 높일 수 있습니다. 만약 메시지를 받은 유저가 이미 그 앱을 설치한 상태라면 그들은 바로 메시지의 이미지에 함께 표시되는 답장(Reply) 버튼을 누를 수 있습니다. 그러면 바로 해당 앱을 실행시켜 결과를 가지고 메신저에 바로 공유할 수 있습니다.

facebook_messenser_api_overview_03

기본적인 이미지, 동영상, 텍스트를 전송하는것을 Basic 메시지라고 부르고 이렇게 설치나, 답장을 유도할 수 있는 메시지를 Optimized 메시지라고 부릅니다. 이 Optimized 메시지를 사용하기 위해서는 몇가지 제약 사항이 있습니다.

  • 컨텐츠 공유하기를 하였을 때 선택가능한 공유 선택지중에 페이스북 메신저가 가장 첫번째로 떠야 합니다. 유저 경험 차원이라는데 그냥 페이스북의 욕심이겠죠^^;
  • 페이스북이 제공하는 통계분석툴(Analytics)를 반드시 붙여야 합니다. 이것을 붙임으로써 각종 통계를 볼 수 있게 된다고 합니다. 근데 강제 하는 이유는 페이스북도 궁금해서겠지요^^?
  • 이러한 기능을 사용하기 위해서는 페이스북에 앱 심사를 거쳐야 합니다. 이때에 당신의 앱은 앱스토어에 이미 출시되어있어야 합니다.

facebook_messenser_api_overview_06

몇몇 앱의 메신저 통합된 사례는 메신저의 대화상의 새로운 탭을 통해서 바로 연결되는 홍보 기회를 가질 수 있습니다. 이 메뉴를 통해 이미 설치된 앱을 바로 실행할 수 있는 바로가기로 사용될 수 있고 새로운 유저가 시도해 볼 수 있는 기회를 얻을 수 도 있습니다.

Business on Messenger

메신저 플랫폼 이외에는 어떻게 사람들과 기업간의 커뮤니케이션을 개선시킬 수 있을까를 목적으로 만들어진 메신저 비지니스 플랫폼도 있습니다. 이 메신저 비지니스 플랫폼은 다음과 같은것을 가능케 합니다. 유저가 어떤 기업의 사이트에서 물건을 구매하는 과정에서 유저는 기업과 대화를 시작하게 됩니다. 구매가 확정되었는지 배송 상태는 어떻게 되는지 메신저를 통해 받을 수 있으며, 특정 폼 없이 자유로운 양식으로 기업에게 질문을 하고 빠른 답장을 받을 수 있습니다.

facebook_messenser_api_overview_07

facebook_messenser_api_overview_08

현재 Everlane, Zulily, Zendesk 등의 기업에서 적용하여 경험을 실시간 채팅 경험을 만들어 나가고 있습니다. 더 자세한 내용은 [이곳]을 참고하시기 바랍니다.

참고 : https://developers.facebook.com/docs/messenger/overview

Android In-App Billing 서버사이드 보안 완벽 정리

google_developers_logo

이번에는 안드로이드 어플리케이션의 앱내 구매(In-App Billing)를 사용한 상품 구매시에 해킹 여부를 서버에서 검증하는 방법에 대해 정리해보겠습니다. 기존에 인터넷 상에 최종 사용자(End User) 기준의 구글 API 사용 방법에 대한 레퍼런스는 많은편인것 같으니 좀 더 사용이 용이한 서비스 계정(Service Account)를 이용한 결제 검증을 하는 방법에 대해 알아보겠습니다. 이 문서는 [Android In-App Billing 보안 완벽 정리]를 먼저 읽으신 다음에 읽으시길 권장드립니다.

여기서 사용하려는 방식은 구글 사용자의 계정 로그인 후 엑세스/리프레시 토큰을 관리 유지하면서 API를 사용하지 않고 구글이 제공하는 여러 인증 방식중에 하나인 서비스 계정으로 API를 바로 사용하는 방법입니다. 이를 위해서는 먼서 서비스 계정을 만들 필요가 있습니다. 해당 부분은 [Server to Server 어플리케이션을 위한 Google OAuth 2.0]에 정리해 두었으니 이 내용을 참고하셔서 서비스 계정을 우선 준비하시기 바랍니다. 이후의 내용은 이 서비스 계정이 준비된 상태라고 판단하고 진행을 하겠습니다.

서비스 계정 발급을 통해 준비가 되어야 하는 것은 크게 두가지 입니다.

  • 유니크한 구글이 발급한 이메일 주소
  • 구글이 생성한 P12 방식 비밀키 파일

구글 개발자 센터에서 서비스 계정 연결하기

준비에 문제가 없다면 구글 개발자 콘솔에 접속하여 현재 설정 상태가 구글 API를 호출하기에 문제가 없는지 점검을 해보겠습니다. 우선 설정 – API 액세스에 들어가 봅니다.

google_validation_iab_01

오른쪽에 나오는 정보중에 마지막으로 서비스 계정이라는 항목이 있습니다. 여기에 미리 추가했던 서비스 계정이 보여지게 됩니다. 엑세스 권한 부여 버튼을 눌러 해당 서비스 계정으로 안드로이드 관련 API를 호출 할 수 있도록 해 줍니다. 이미 권한이 부여되었다면 권한 보기 버튼이 있을 것입니다.

google_validation_iab_03

여기서 중요한것은 구매내역 및 영수증 검증을 하기 위해서는 재무 보고서 보기 권한이 필요하다는 부분입니다. 역할을 금융으로 선택해 주면 해당 권한이 자동으로 선택됩니다. 즉 영수증 검증을 위해서는 금융 역할을 갖는 서비스 계정이 필요합니다.

google_validation_iab_04

정상적으로 권한 설정이 된것을 확인할 수 있습니다. 이것으로 Google 쪽에서 필요한 작업은 모두 끝났습니다. 이과정은 하나의 안드로이드 개발자 당 한번만 수행하면 됩니다. 앱을 추가할때마다 하실 필요는 없습니다. 이제 코드를 보도록 하겠습니다.

구글 클라이언트 라이브러리를 이용하여 API 호출하기

복잡하게 토큰을 관리하며 HTTP/REST API를 사용할것 없이 구글이 제공하는 클라이언트 라이브러리를 사용하도록 합시다. [이곳]에서 자신의 언어에 맞는 라이브러리를 찾으실 수 있습니다. 여기서는 Java로 진행하도록 하겠습니다. Java 기준 필요한 라이브러리는 두가지입니다. google-api-client 와 google-api-services-androidpublisher 입니다. 저의 경우에는 gradle을 사용하여 예제 프로젝트를 만들어보았습니다. 다음과 같이 dependencies를 추가 해 주면 됩니다.

dependencies {
    compile 'com.google.api-client:google-api-client:1.21.0'
    compile 'com.google.apis:google-api-services-androidpublisher:v2-rev22-1.21.0'
}

이제 다음과 같은 방법으로 GoogleCredential을 생성해주도록 합시다. 여기서는 기존에 서비스 계정 발급을 통해 받은 이메일주소와 P12 비밀키 파일을 잘 지정해 주셔야 합니다.

String emailAddress = "my-new-service-account@api-project-000000.iam.gserviceaccount.com";

JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
GoogleCredential credential = new GoogleCredential.Builder()
     .setTransport(httpTransport)
     .setJsonFactory(JSON_FACTORY)
     .setServiceAccountId(emailAddress)
     .setServiceAccountPrivateKeyFromP12File(new File("src/GooglePlayAndroidDeveloperPrivateKey.p12"))
     .setServiceAccountScopes(Collections.singleton("https://www.googleapis.com/auth/androidpublisher"))
     .build();

이제 특정 구글 앱내 구매를 처리하기 위해서 다음과 같은 간단한 코드만으로 API를 호출하고 결과를 확인할 수 있습니다.

String packageName = "pe.kr.theeye.trivialdrive";
String productId = "gas";
String purchaseToken = "njnbhmfid...AuSkyASqY";

AndroidPublisher publisher = new AndroidPublisher.Builder(httpTransport, JSON_FACTORY, credential)
	.setApplicationName(packageName)
	.build();

AndroidPublisher.Purchases.Products.Get get = publisher.purchases().products().get(packageName, productId, purchaseToken);
ProductPurchase productPurchase = get.execute();
System.out.println(productPurchase.toPrettyString());

// 인앱 상품의 소비 상태. 0 아직 소비 안됨(Yet to be consumed) / 1 소비됨(Consumed)
Integer consumptionState = productPurchase.getConsumptionState();

// 개발자가 지정한 임의 문자열 정보
String developerPayload = productPurchase.getDeveloperPayload();

// 구매 상태. 0 구매완료 / 1 취소됨
Integer purchaseState = productPurchase.getPurchaseState();

// 상품이 구매된 시각. 타임스탬프 형태
Long purchaseTimeMillis = productPurchase.getPurchaseTimeMillis();

받을 수 있는 결과의 예시는 다음과 같습니다. 정상적인 상품이라면 HTTP 200 OK가 떨어지며 다음과 같이 정상적인 상품의 정보와 consumptionState가 1이고 purchaseState가 0이게 됩니다.  consumptionState가 0이라면 개발자의 실수라던가 구매 과정에서 앱이 크래시되거나 다양한 이유가 있겠지만 어쨌든 결제 과정에서 오류가 발생했다고 보시면 될 것 같습니다.

{
  "consumptionState" : 1,	// 0 아직 컨슘 안됨, 1 컨슘됨
  "developerPayload" : "",
  "kind" : "androidpublisher#productPurchase",
  "purchaseState" : 0,	// 0 구매완료, 1 취소
  "purchaseTimeMillis" : "1454502702978"
}

purchaseState의 경우 결제 완료 상태의 경우 0으로 오게 되며 개발자가 환불을 해주거나 유저가 임의로 환불을 한 상태라면 1로 바뀌게 됩니다. 이게 즉시 바뀌지는 않고 몇분정도 딜레이가 있는것 같습니다.

만약에 위변조된 구매 토큰을 가지고 검증 요청을 하였다면 다음과 같은 오류 메시지를 받게 됩니다. HTTP 400번대의 오류코드가 떨어지게 됩니다. 인증관련 오류는 401이 존재하지 않는 구매 영수증의 경우 404가 떨어집니다.

{
  "code" : 404,
  "errors" : [ {
    "domain" : "global",
    "location" : "token",
    "locationType" : "parameter",
    "message" : "The purchase token was not found.",
    "reason" : "purchaseTokenNotFound"
  } ],
  "message" : "The purchase token was not found."
}

이런 오류의 경우 get.execute() 호출 할 때에 GoogleJsonResponseException 예외가 발생하니 관련하여 적절한 처리를 해주시면 됩니다.

참고 사항

Google Purchase API 버전별 차이점 (v1.1 / v2)

기존에 v1.1은 권한과 상관없이 아무앱의 결제 정보를 영수증값과 패키지명 등을 이용하여 조회가 가능했다고 들었지만 실제로 테스트 해본 결과 다른 앱의 정보를 조회하는것은 불가능했습니다. v1.1 및 v2 모두 다음과 같이 권한 오류가 발생하였습니다.

{
  "error": {
    "errors": [
      {
        "domain": "androidpublisher",
        "reason": "permissionDenied",
        "message": "The current user has insufficient permissions to perform the requested operation."
      }
    ],
    "code": 401,
    "message": "The current user has insufficient permissions to perform the requested operation."
  }
}

purchaseState의 값을 조회하면 현재 구매 완료된 상태인지 취소된 상태인지 여부를 확인할 수 있습니다. 하지만 v1.1에서는 무조건 0으로 나오는 등 정상적으로 값을 조회할 수 없었습니다. 결제 취소 여부를 조회할 필요가 있으시다면 필히 v2로 구현을 하시기를 추천드립니다.

쿼터 제약 사항

구글플레이 개발자 API를 사용하는 어플리케이션들은 초기 사용 할당량으로 하루에 (하나의 어플리케이션 당) 20만건을 부여받습니다. 이 정도의 수량이면 대부분의 일반적인 어플리케이션들에는 충분한 양이지만 만약에 더 높은 제한 조건이 필요할 경우 구글 개발자 콘솔의 “Request more” 링크를 사용해 주시기 바랍니다.

참고 :

https://stackoverflow.com/questions/11115381/unable-to-get-the-subscription-information-from-google-play-android-developer-ap
https://developers.google.com/android-publisher/api-ref/purchases/products