안드로이드 IAB .. 계속..

In-app Billing Messages

사용자가 구매를 시작하면 니 앱은 구매 메시지를 간단한 IPC 콜을 이용하여 구글 플레이의 구매 서비스(MarketBillingService) 에 보낸다. 구글 플레이 어플은 모든 빌링 요청에 동시에 응답하며, 상태 노티와 다른 정보를 제공한다. 또한 어떤 요청에는 비동기적으로 에러 메시지와 자세한 결재 정보를 보낸다. 다음은 니 어플과 구글 플레이 어플 사이의 요청-응답 메시지의 기본을 서술한다.

In-app billing request

구매 요청은 MarketBillingService 인터페이스에 노출되 있는 sendBillingRequest() 를 불러 시작. 이 인터페이스는 Android Interface Definition Language 파일(IMarketBillingService.aidl)에 정의되어 있음. 다운로드 가능. 이 메서드는 한개의 <번들> 인수를 갖고 있음. 니가 전달하는 번들은 여러개의 키-밸류를 갖고 있음. 구매 타잎, 아이템, 타잎, 어플 정보.  더 자세한 것은 문서 참조.. 가장 중요한 키는 BILLING_REQUEST 키. 이 키는 구매 타잎을 정의하게 해 줌.  구글 플레이의 빌링 서비스는 다음의 다섯가지 종류의 요청을 지원함. > CHECK_BILLING_SUPPORTED 이 요청은 구글플레이 어플이 구매를 지원하는 걸 확인. 이 것은 어플이 시작할 때 전송. 이것은 결재와 관련된 UI 를 온/오프할 때 유용. > REQUEST_PURCHASE 이 요청은 구글플레이 어플에 구매 메시지를 전달하고 구매의 기초가 됨. 사용자가 구매 의사를 표현하면 이 요청을 보냄. 구글 플레이가 그 다음 체크아웃 UI 를 보여주고 금융결재를 다룬다. > GET_PURCHASE_INFORMATION 이 요청은 구매 상태 변화의 세부를 갱신한다. 구매는 요청된 구매가 성공적으로 발행 되거나, 사용자가 체크아웃 동안 취소하면 상태를 바꾼다. 이전 구매가 환불되도 일어난다. 구글 플레이는 구매 상태가 변하면 니 어플에 노티해서 갱신할 결재 자료가 있으면 이 요청만 보내면 된다. > CONFIRM_NOTIFICATIONS 이 요청은 어플이 구매상태 변화의 상세를 받았다는 것을 수락한다. 구글플레이는 구매상태변화 노티를 니가 그것을 받았다고 확인할 때까지 니 어플에 보낸다. > RESTORE_TRANSACTIONS 이 요청은 “managed purchases” 와 “subscriptions” 의 결재 상태를 갱신한다. 이 요청을 사용자의 결재 상태를 갱신할 필요가 있을 때 – 어플이 재설치 되었을 때, 혹은 처음 인스톨 될 때 – 보낸다.

In-app billing Responses

구글 플레이 어플은 동기/비동기 방식으로 작동.  동기 응답은 다음 세가지 키와 함께하는 ‘번들’ 임.

>RESPONSE_CODE : 이 키는 요청에 대한 상태 정보와 정보를 제공한다.

> PURCHASE_INTENT : 체크아웃 활동을 런치하는 데 쓰이는 PendingIntent 를 제공.

> REQUEST_ID : 이 키는 요청 아이디를 제공. 비동기 응답에 사용 됨.

이 키 중 일부는 모든 요청에 관련된 것은 아니다.
비동기 응답은 individual broadcast intents 의 형태로 보내지며 다음을 포함한다.

> com.android.vending.billing.RESPONSE_CODE
이 응답은 구글플레이 서버 응답코드를 품으며 니가 빌링 요청을 한 이후에 보내진다. 서버 응답 코드는 빌링 요청이 성공적으로 구글 플레이에 전달됐다거나 에러가 났다는 것을 가리킨다. 이 응답은 구매 상태 변화를 보고하는데는 쓰이지 않는다. (환불 / 구매 정보 등의)

> com.android.vending.billing.IN_APP_NOTIFY
이 반응은 구매가 성공했거나, 취소, 환불 되는 등의 상태 변화를 가리킴. 이 응답은 하나 이상의 노티 아이디를 포함. 각각의 노티 아이디는 특정 서버단 메시지와 대응되며 각 메시지는 하나 이상의 결재에 대한 정보를 포함. 어플이 IN_APP_NOTIFY broadcast intent 를 받은 다음 니는 GET_PURCHASE_INFORMATION 요청을 노티 아이디와 함께 보내 메시지 상세를 갱신한다.

> com.android.vending.billing.PURCHASE_STATE_CHANGED
이 응답은 하나 이상의 결재에 대한 정보를 포함. JSON 스트링으로 표현됨. 이 스트링은 사인되고, 그 서명은 어플에 암호화되지 않은 JSON 으로 보내진다. 빌링 메시지의 보안을 확실히 하기 위해, 어플은 이 스트링의 서명을 확인할 수 있다.
PURCHASE_STATE_CHANGED intent 와 한께 돌아온 JSON 스트링은 하나 이상의 빌링 결재의 상세를 어플에 제공한다. 아래는 그 예.

{ “nonce” : 134123412342134,

“orders” :  …… }

Messaging sequence

전형적인 구매 요청에 대한 메시징 절차는 그림 2에 있음.  요청 종류는 볼드체로 표기, broadcast intent는 이탤릭 표기. 그림 2에는 RESPONSE_CODE broadcase intents 는 모든 요청에 보내지므로 생략 했음.

기본 메시지 절차는 아래와 같음.

1. 어플이 구매 요청을 보낸다. product ID, 다른 인수들 명시.  (REQUEST_PURCHASE type)

2. 구글 플레이 어플이 다음의 키를 갖는 번들을 어플로 보냄 : RESPONSE_CODE, PURCHASE_INTENT, REQUEST_ID. PURCHASE_INTENT 는 PendingIntent 를 제공하는데, 이는 어플이 체크아웃 UI 를 시작하는 데 쓰인다.

3. 어플이 pending intent 를 런치하면 이는 체크아웃 UI 를 런치한다. [ 주의 : pending intent 를 activity context 로부터 런치해야함. application context 아님 ]

4. 체크아웃 절차가 끝나면 (구매가 성공되거나 취소) 구글 플레이는 어플에 노티메시지( IN_APP_NOTIFY broadcast intent) 를 보냄. 노티 메시지는 노티 ID 를 포함. 이는 결재를 참조함.

5. 어플이 GET_PURCHASE_STATE_CHANGED 요청을 보냄으로 결재 정보를 요청. 이때 결재를 위해서 노티 ID 를 명시.

6. 구글 플레이 어플이 RESPONSE_CODE key 와 REQUEST_ID 키와 함께 번들을 보낸다.

7. 구글 플레이 어플이 결재 정보를 PURCHASE_STATE_CHANGED broadcast intent 안에 넣어 어플에 보낸다.

8. 어플이 받았다는 메시지를 보낸다. (CONFIRM_NOTIFICATIONS type)

9. 구글 플레이 어플이 어플에 번들을 보낸다.

결재 정보를 받으면 (8번) 확인 메시지를 보내야 한다. 보내지 않으면 IN_APP_NOTIFY메시지를 계속 보낼 것임.  연습삼아, 아이템을 유저에게 잔달할 때까지 확인 노티를 주지 말아라. 이렇게 함으로써 어플이 죽거나 제품 전달에 실패한 경우 어플이 IN_APP_NOTIFY 메시지를 받아서 구매를 완결할 수 있다. 또한 최고의 연습으로, IN_APP_NOTIFY메시지를 다룰 수 있어야 한다.

결재를 복원하는 요청은 그림 3에 있음.

요청은 세 응답을 발생시킨다.  첫째는 번들, 다음은 RESPONSE … 이것은 상태정보, 에러정보를 포함. RESPONSE_CODE 메시지.

RESTORE_TRANSACTIONS 요청 타잎은 (구매 요청시 보내진 결재 정보와 같은 종류의) PURCHASE_STATE_CHANGED broadcast intent 를 촉발.

Handling IN_APP_NOTIFY messages

보통, 앱은 REQUEST_PURCHASE 메시지에 대한 응답으로  IN_APP_NOTIFY broadcast intent 를 구글 플레이로부터 받는다.  IN_APP_NOTIFY broadcast intent는 어플에게 요청한 구매 상태가 변경되었다는 것을 알려준다. 그 구매의 상세를 갱신하기 위해서, 어플은 GET_PURCHASE_INFORMATION 요청을 보낸다. 구글 플레이는 PURCHASE_STATE_CHANGED b. i. 로 응답하고 이는 구매상태변화의 상세를 답고 있다. 어플은 CONFIRM_NOTIFICATIONS 메시지를 보내서 구글 플레이에게 구매상태변경 정보를 받았다는 것을 알려준다.

몇몇 특별한 경우, 영수증을 컨펌 해도 여러개의 IN_APP_NOTIFY 메시지를 받거나, 구매를 시작하지도 않았는데, IN_APP_NOTIFY 를 받을 수 있다. 어플은 이 두가지 경우를 다룰 수 있어야 한다.

Handling multiple IN_APP_NOTIFY messages

구글 플레이가 주어진 PURCHASE_STATE_CHANGED 메시지에 대하여 CONFIRM_NOTIFICATIONS 메시지를 받으면 보통은 IN_APP_NOTIFY intent 를 보내는 것을 멈춘다. 하지만, 가끔 구글 플레이가 이것을 반복할 수 있다. 이것은 기기가 네트워크 연결이 끊겼을 때 일어날 수 있다. 이 경우 CONFIRM_NOTIFICATIONS 메시지를 받지 못했을 수 있고, 니가 결재 메시지를 받았다는 것을 알 때까지 계속 보낼 수 있다.
그러므로, 다음에 오는 그 메시지가 직전 거래의 결과라는 것을 알수 있어야 한다. 이것은 orderID를 확인함으로써 가능하다.

Handling refunds and other unsolicited IN_APP_NOTIFY messages

REQUEST_PURCHASE 메시지를 보내지 않아도 IN_APP_NOTIFY 를 받는 경우는 두가지가 있다. 그림 5 참조.

첫번째 경우는, 유저가 두 기기에 어플을 설치하고 한 기기에서 구매를 했을 경우. 이 때, 구글 플레이는 IN_APP_NOTIFY 메시지를 두번째 기기에 보내서 구매 상태가 변했다는 것을 알려준다. 니 어플은 이 메시지를 일반 구매와 동일하게 해석해서  PURCHASE_STATE_CHANGED b. i. 메시지를 받아 어느 아이템을 구매했는지 알수 있어야 한다.  이것은 구매 종류가 “managed per user account” 일 경우에만 해당한다는 것을 의미한다.

두번째 경우, 구글 플레이가 구글 지갑으로부터 환불 노티를 받는 경우 IN_APP_NOTIFY 를 받을 수 있다. 이 경우, 구글 플레이는 어플에 IN_APP_NOTIFY 메시지를 준다. 어플은 이 메시지를 해석하여 궁극적으로 PURCHASE_STATE_CHANGED 메시지를 받도록 한다. 환불 정보는 JSON 스트링에 있다. 또한, purchaseState 필드가 2로 세팅된다.

Security Controls

어플로 보내지는 결재 정보의 안전을 위해 구글 플레이는 PURCHASE_STATE_CHANGED b. i. 가 담고 있는 JSON 스트링에 사인한다. 구글 플레이는  이 서명을 만들기 위한 당신의 퍼블리셔 계정과 연결된 private key를 이용한다.  이와 쌍을 이루는 public key 부분은 계정의 프로파일 페이지에 있다. 이는 구글 플레이 라이센싱과 함께 사용되는 동일한 키이다.

구글 플레이가 빌링 응답에 사인하면, 서명된 JSON 스트링과 서명을 포함한다. 어플이 이 서명된 응답을 받으면 RSA 키 쌍의 public key 를 이용하여 서명을 확인할 수 있다. 서명 확인을 함으로써 조작되거나, 위조된? 응답을 탐지할 수 있다. 이 서명 확인 단계는 어플에서 할 수 있다; 하지만, 서버가 있다면 서버에서 하는 것을 권한다.

IAB 은 또한 nonces (한번 쓰는 난수) 를 사용하여 구글플레이로부터 오는 구매 정보의 안전성을 확인하는 것을 돕는다. 어플은 넌스를 발생하고 GET_PURCHASE_INFORMATION 요청과 RESTORE_TRANSACTIONS 요청과 함께 보내야 한다. 구글 플레이가 요청을 받으면 ‘넌스’를 JSON 에 추가한다. 그러면, JSON 스트링이 사인되고 어플로 되돌아온다. 어플이 JSON 을 받으면 ‘넌스’를 확인할 필요가 있다.

In-app Billing Requirements and Limitations

> IAB는 구글 플레이를 통해 퍼블리쉬된 어플에만 이식할 수 있다.

> 구글 지갑 계정이 있어야 한다.

> 안드로이드 마켓 어플 2.3.4 이상. ….

> 안드로이드 1.6 이상.

> 디지털 콘텐츠에만 해당. 실제 제품, 서비스 등은 불가.

> 구글 플레이에서는 콘텐츠 전달은 하지 않음.

> 네트워크 필요.

안드로이드 IAB ..

In-app Billing Overview

In app Billing Service 에서 구글 서버에 요청, 확인 하는 과정 대리함. 금융 거래 데이터를 다룰 필요가 없다.

Product and Purchase Types

먼저 제품을 등록해야 함. 제품 종류, 구입 종류, SKU, 가격, 설명 등

Product Types

두가지 상이한 제품이 있지만, 구입 과정은 동일한 통신모델, 데이터구조, UI 를 갖는다.

In-app products

한번만 구매하는 제품. 기능 언락. 구매하면 반품 윈도우가 없다.  환불 받으려면 개발자에게 직접 연락해야 함.
“managed per user account” 또는 “unmanaged” 를 통해 판매 가능.
항상 ‘하나의’ 앱과 명시적으로 연관되어야 함. 즉, 한 앱은 다른 앱을 위해 발행된 ‘인앱 제품’ 을 구매할 수 없다.
In app products 는 모든 버전의 In-app Billing 에서 지원한다.

Subscriptions

일정 주기로 판매되는 아이템.  유저가 이것을 구입하면 구글 플레이와 그 결재 프로세서가 자동적으로 결재를 한다. 한번 구매하면 구글 플레이는 계정을 승인 요청이나 다른 경고 없이 무한히 계속한다. 사용자는 언제고 구매를 취소할 수 있다.
“managed per user account” 구매 방식에 의해서만 판매 가능. 이것도 리펀드 윈도우 없음. 개발자 직접 연락.  자세한 사항은 더 참조할 것.

Purchase Types

두가지 구매 방식. “유저 계정” 에 따른 것과, “비관리” 되는 것.

Managed per user account : 계정별 관리

한번만 구매하는 제품. 구매 되면 구글 플레이는 영수증을 ‘누가’ 구매 했는지 영원히 보관한다. 이것을 통해 나중에 구글에 쿼리하여 구매한 아이템을 복원 할 수 있다.  이미 구매한 아이템을 구매하려고하면 구글 플레이가 재구매를 박고 “Item already purchased” 에러를 보낸다.
게임 레벨, 기능 등을 팔 때 유용하다. 이 아이템은 일시적인 것이 아니고 앱을 재 설치할 때 복원되어야 한다.

Unmanaged : 비관리 형식

구글 플레이에 저장되지 않는 아이템들. 나중에 쿼리할 수 없다. 개발자가 결재 정보를 관리할 책임이 있다. 구글 플레이가 재구매를 막지 않기때문에 여러번 구매할 수 있으므로 몇 번 구매 가능한 지에 대해서 개발자가 관리해야 한다.
소비성 제품 판매에 적절하고 여러번 구매될 수 있다.

In-app Billing Architecture

기기에 설치된 구글 플레이 앱에 노출된 API 를 이용하여 당신의 앱은  In-app Billing 서비스에 접속한다. 구글 플레이 앱은 비동기 메시지 루프를 통해 구매 요청을 전달하고 앱과 구글 플레이 서버 사이에서 신호를 받는다.
실제로, 당신의 앱은 구글 플레이 서버와 직접 통신하지 않는다. 대신, 니 앱은 구글 플레이 어플에 IPC 로 요청하고 구글 플레이 어플로부터 비동기 브로드캐스트 인텐츠의 형식으로 응답을 받는다.  asynchronous broadcast intents.
니 앱은 어떠한 네트워크 커넥션도 하지 않으며 특별한 안드로이드 플랫폼의 API 를 이용하지도 않는다.

어떤 경우 사설 원격 서버를 사용해서 사진이나 미디어를 전달할 수 도 있다. 또한, 거래 내역을 저장하거나 추가적인 보안 작업을 할 수도 있다. 앱에서 보안관련 처리를 할 수 있지만 서버에서 하는 것이 더 안전하다.

전형적인 in-app billing 구현은 3가지 요소에 달려있다.

>> A Service (BillingService) : 어플로부터 구매 메시지를 처리, 구매 요청을 구글 플레이 서비스에 보냄.

>> A BroadcastReceiver (BillingReceiver) : 구글 플레이 어플로부터 모든 비동기 구매 응답을 받음.

>> A security component (Security) : 보안 관련 작업. signature verification, nonce generation.

추가 가능한 다른 두 요소.

>> A response Handler : 구매 노티, 에러, 상태 메시지 등.
>> An observer : 니 어플에 콜백을 보내는 일 담당.

이 외에 어플에서는 사용자 구매를 저장할 방법을 제공해야 하고, 구매 관련 유아이가 있어야 함. 체크아웃 UI 는 불필요. 사용자가 구매를 시작할 때, 구글 플레이 어플은 UI 를 제공한다. 유저가 체크아웃을 완료하면 어플이 재개 됨.

OpenGL, iOS 의 대가.. Jeff Lamarche. SceneKit ..

바로가기는 여기   외국사람인데, kr ??  암튼..

씬 킷은 현재까지는 맥앱에만 해당되는 기술인데 되게 좋더라..

개념적으로 뭘 하느냐.

OpenGL 위에, 앱킷 같은 상위 레벨 아래에 위치함. 씬킷 뷰는 완전히 ‘레이어-감지’ 하여 코어 애니메이션으로 애니메이션 가능하다.
뷰 자체가 아니마 가능할 뿐더러, 뷰의 상수를 아니마 할 수 있음.

씬 킷은 주로 ‘scene graph management’ 라이브러리로 알려진 것이다. 이놈은 하나 이상의 3차원객체와 광원, 카메라를 매니지한다. 이 아이템들이 합쳐져서 스크린에 보여진다. 씬킷은 마야, 모도, 블레더 등으로부터 콜라다 형식으로 데이터를 받을 수 있다. 컬라다는 3차원 객체 외에 광원, 카메라, 애니매이션 정보까지 포함한다.

씬킷은 앱킷과 잘 어우러져 NSView 에 이미 있는 힛 테스트를 통해 터치, 마우스 클릭 등의 프로젝션 등을 다룰 수 있다.

씬킷에서 모든 렌더링이 편하게 가능하며 필요할 때는 렌더 딜리깃을 통해 직접 제어가능하다. 편하게 구현 가능하면서 세세한 조정도 가능하다는 얘기.
이것을 보면 얼마나 이 프레임 워크에 공이 들어갔는지 알 수 있다.

결론적으로 씬킷은 어려운 걸 쉽제 해준다. 하지만, 아직 문서도 완전하지 않고….

셋업

Xcode 4.4 or 4.5 ..  산사자 필요…

ARC 를 켜라.

쿼츠코어 추가.

씬뷰 추가

파일 추가..  닙파일… 씬뷰 객체를 윈도우에 드래그..  레이아웃 할 필요 없다…  블라블라.. HTFSceneView 로 명명해라.

헤더에  씬킷.h 추가..  이제 컴파일 가능.

씬 배경 색 지정

간단한 씬 만들기

씬을 코드로 만들어보자.  씬킷에 대한 기본 툴과 용어를 익힐 것이다.

기본은 카메라, 광원, 객체이다. 이것 없이는 별볼일 없다.

빈 SCNScene 객체 생성. 이 객체를 갖으면 씬에 아이템을 추가하기 위해서 “노드”라 불리는 객체를 생성한다. SCNNode 클래스로 대표되는 노드는 다른 종류의 객체를 붙들어 매기 위해 만들어졌다. 위계가 있어 자식, 부모 관계 로 붙일 수 있다.

모든 씬은 ‘루트 노드’ 가 있고 rootNode 로 불리며 씬의 톱 위상의 객체를 붙인다. 노드를 만들고 거기에 카메라, 3차원객체 등을 붙고 그 노드를 루트노드 혹은 그 자식에 붙여서 씬에 객체를 추가한다. 꽤 직관적이지 않은가?

한번 붙이면 리무브 할 때까지 남아있는다.  awakeFromNib 에 코드를 붙이자.

씬 만들기

// Create an empty scene
SCNScene *scene = [SCNScene scene];
self.scene = scene;

카메라 추가.

// Create a camera
SCNCamera *camera = [SCNCamera camera];
camera.xFov = 45; // Degrees, not radians
camera.yFov = 45;
SCNNode *cameraNode = [SCNNode node];
cameraNode.camera = camera;
cameraNode.position = SCNVector3Make(0, 0, 30);
[scene.rootNode addChildNode:cameraNode];

카메라에 라디언 대신 ‘도’ 로 표시. 카메라 클래스를 보면 오픈쥐엘 뷰포트와 유사하다는 것을 알 것이다. 우연이 아니고. 씬킷의 ‘카메라’는 GL 뷰포트 … 이 다가 아니다. ?? 카메라가 {0, 0, 30} 에 있으면 카메라의 위치에 따라 렌더하기 전에 씬의 모든 노드는 Z 방향으로 -30 물러날 것이다. 카메라는 회전가능. 씬은 카메라의 시점으로 렌더 된다.

이제 객체. 빌트인 객체를 제공. 실린더, 큐브, 공, 콘, 평면, 튜브, 토러스, 피라미드, 텍스트.. SCNGeometry 에서 상속.  생성한 후 속성 부여, 노드에 할당, 노드를 씬에 추가.. 예제.

// Create a torus
SCNTorus *torus = [SCNTorus torusWithRingRadius:8 pipeRadius:3];
SCNNode *torusNode = [SCNNode nodeWithGeometry:torus];
CATransform3D rot = CATransform3DMakeRotation(MCP_DEGREES_TO_RADIANS(45), 1, 0, 0);
torusNode.transform = rot;
[scene.rootNode addChildNode:torusNode];

Transform3D .. 매트릭스.. GLKMatrix4 와 유사. 위치, 스케일, 회전 등에 대한 정보를 담는다.

다음은 조명. 지금 상태에서 프로그램을 돌리면, 토러스가 그려지지만 완전한 평면 흰색일 것임.

OpenGL from the ground.. 를 상기한다면 3디 그래픽의 기본은 디퓨즈, 앰비언트, 스펙큘러 .. 설명..

스펙큘러 : 밝은 점.. 스팟.. 직광..
앰비언트 광원 : 분명한 소스가 없는 광원.. 여러곳에서 반사된 광원. 세이드 부분.. 어두운 곳..
디퓨즈 : 밝은 부분 ?? 아마도..

씬킷의 라이팅은 더 진보된 것. 씬킷에서 스펙큘러 하이라잇은 광원 세팅보다는 재료 로 부터 온다. 나중에 살펴보자. 하지만 디퓨즈와 앰비언트는 씬에 빛을 추가함으로 얻을수 있다.

씬킷에서 광원은 여러가지 타잎. 앰비언트. 직광.

앰비언트 추가해보자. 일반적으로 하나의 앰비언트 광원. 더 드라마틱한 경우 없을 수도 있음.  앰비언트의 위치와 변위는 상관없음.

// Create ambient light
SCNLight *ambientLight = [SCNLight light];
SCNNode *ambientLightNode = [SCNNode node];
ambientLight.type = SCNLightTypeAmbient;
ambientLight.color = [NSColor colorWithDeviceWhite:0.1 alpha:1.0];
ambientLightNode.light = ambientLight;
[scene.rootNode addChildNode:ambientLightNode];

// Create a diffuse light
SCNLight *diffuseLight = [SCNLight light];
SCNNode *diffuseLightNode = [SCNNode node];
diffuseLight.type = SCNLightTypeOmni;
diffuseLightNode.light = diffuseLight;
diffuseLightNode.position = SCNVector3Make(-30, 30, 50);
[scene.rootNode addChildNode:diffuseLightNode];

 

// Create a torus