주의 사항
Hive SDK v1.11.0 update
- Engagement 수행 로직이 변경됨
- 게임 내부에서 Engagement사용 준비가 완료된 경우 (게임 로그인 이후, 게임 메인 페이지 진입 등) SetReady API를 호출하여 Engagement기능을 동작을 활성화시켜야 함
Engagement_SetReady 참고
유저 인게이지먼트 기능 중 쿠폰딥링크를 통해 게임이 실행이 되면
C2SModuleSocial_Initialize, C2SModuleSocial_Show API에 세팅한 serverId 값으로 Hive 아이템에 재화 지급 요청하게 되는데, C2SModulePromotion_Show의 addtionalInfo의 server 값 또한 Hive 아이템에서 서버 구분을 위해 세팅되는 값으로 두 API의 서버 구분자 값은 동일하여야 한다.
위 서버 구분자는 Hive 아이템에 아이템 등록 요청 시 개발TF에서 등록 요청한 서버 구분자 값이다.
참고 API – C2SModuleSocial_Initialize
참고 API – C2SModulePromotion_Show
참고 API – C2SModuleSocial_Show
Hive SDK v1.12.0 update
- serverId 설정 방법 변경
1.12.0이후 serverId 값은 C2SModuleSocial_Initialize, C2SModuleSocial_SetGameInfo API를 통해 세팅한다.
참고 API – C2SModuleSocial_Show // C2SModuleSocial_SetGameInfo로 링크 변경
제한 사항
– Hive SDK v1.10.0 이상 적용 필요
– 쿠폰 딥링크 보상을 위해 Hive Item에 적용 필요
용어 정리
유저 인게이지먼트 (UE) | 프로젝트 명으로 유저 인게이지먼트 혹은 줄여서 UE 라고도 하며, 정식 영문 명은 User Engagement 이다. 유저 인게이지에 대한 자세한 내용은 유저 인게이지먼트란?에서 확인할 수 있다. |
---|---|
딥링크 URL | 모바일에서의 딥링크는 웹 상에서 링크를 타고 앱 상에 있는 특정 페이지로 바로 넘어가도록 만드는 것을 의미한다. 혹은 앱에서 다른 앱을 연결시켜주는 의미도 포함된다. 딥링크 URL은 위와 같이 이동할 수 있는 주소를 의미하며, 유저 인게이지에서는 목적에 따라 게임 내 주소를 딥링크 URL로 만들고, 유저가 접근 할 수 있는 랜딩 URL을 제공한다. |
랜딩 URL | 영문으로는 Landing URL 이라고 하며, 사용자가 사이트에 접속했을 때 처음 만나게 되는 웹 페이지의 주소를 의미한다. 링크를 눌러 처음으로 도달하는 곳 이기 때문에 목적에 따라 페이지를 구성할 수 있다. |
쿠폰 딥링크 | 기존 Hive 원> GMS > 쿠폰발행관리 에서 발급하던 대량 쿠폰 번호를 게임 주소와 쿠폰번호를 포함한 URL로 만들어 게임 내 에서 바로 보상을 받을 수 있는 링크이다. 사전등록이벤트, 그 외 보상 지급 시 메세지에 쿠폰 딥링크 URL을 넣어 전송하면 유저가 쉽게 보상을 받을 수 있다. |
인게임 딥링크 | 게임 내에서 링크를 클릭하여(ex: 배너, 공지 글 등), 게임 내 특정 위치로(ex: 던전, 친구목록 등) 갈 수 있는 링크이다. 새소식 공지 글, 배너 등에 인게임 딥링크 URL을 연결해 주면, 게임 내 이벤트 영역으로 쉽게 이동할 수 있다. |
기타 이벤트 딥링크 | 자체적으로 만든 이벤트 페이지(ex: 사전등록페이지 등) 링크를 딥링크 URL로 변경하여 다양한 마케팅 영역에서 사용할 수 있도록 한다. |
Scheme URL | 어플리케이션 외부에서 어플리케이션에 접근할 수 있도록 정해진 URL 구조의 스키마이다. {scheme}://{host}/{path}?{parameters} 구조로 이루어져 있으며, {scheme} 값을 기준으로 실행할 앱을 결정한다. |
인텐트 | 정식 영문 명칭은 Intent 이며 안드로이드 시스템에서만 사용하는 개념이다. 하나의 앱을 구성하는 여러 액티비티간 데이터를 주고 받고 대상에게 무엇을 하려는 지에 대한 의도를 전달하는 목적으로 사용되는 객체로 메시지 시스템에서 사용된다. |
유저 인게이지먼트(UE)란?
Hive SDK v1.10.0 부터 들어간 신규 서비스로 딥링크 기능을 말한다.
모바일 메시지(SMS), 푸시 알림(Push Notification)으로 전송된 메시지 내의 URL클릭 시, 게임을 실행시키고
게임 내 특정 위치에 바로 도달 할 수 있다.
또한 쿠폰 값을 딥링크에 넣어 유저가 클릭하면 바로 게임을 실행 하고 우편함 등에서 보상을 획득할 수 있다.
이처럼 다양한 마케팅 이슈에 대응할 수 있도록 구성된 서비스로, 백오피스(Hive ONE) 에서 쿠폰 받기,
게임 접속 유도, 기타 이벤트 용도의 URL을 생성하여 이용할 수 있다.
서비스 특징
유저 인게이지에서 제공하는 서비스 내용은 다음과 같다.
1) 딥링크 생성하기
딥링크 생성은 백오피스(Hive ONE) 에서 생성할 수 있다.
딥링크 생성은 사용 목적에 따라 쿠폰 딥링크, 인게임 딥링크, 기타 이벤트 딥링크로 나뉜다.
쿠폰 딥링크는 쿠폰 값을 가진 링크로 클릭 시, 게임으로 진입하여 바로 보상을 받을 수 있으며,
인게임 딥링크는 게임 내에서 클릭한 링크가 게임 내 특정 위치로 이동할 수 있게 한다.
기타 이벤트는 다양한 마케팅 목적을 수용할 수 있도록 일반 URL을 딥링크 URL로 변환하여
사용 할 수 있다.
2) 생성한 딥링크 수정 및 삭제 관리
백오피스(Hive ONE) 에서 생성한 딥링크 정보를 수정하거나 삭제 할 수 있다. 이벤트 내용, APP ID 변경,
서비스 상태(활성화 또는 비활성화) 등 을 변경할 수 있다. 정보 수정 시 처음에 생성했던 랜딩 URL주소가
변경될 수 있다.
3) 게임 설치 유무 및 유저의 단말 환경에 따른 대응
쿠폰 딥링크, 인게임 딥링크의 경우, 해당 게임의 설치 유무에 따라 유저 플로우가 변경 된다. 설치가 된
경우에는 바로 게임 실행하여 보상 받기나, 게임 내 특정 위치로 이동할 수 있으며, 설치가 안 된 경우에는
마켓으로 연결시켜 다운로드 후 게임으로 진입할 수 있도록 유도한다.
Android 버전 중, 인텐트(intent)가 불가한 단말이나 샤오미 폰의 경우, 단말 특성상 동일한 플로우
진행이 어려워 별도의 처리가 되어 있다.
4) 쿠폰에서 에러 발생 시 처리
쿠폰 딥링크 클릭 시, 없는 쿠폰 번호 이거나, 기간 만료된 쿠폰 번호 등과 같이 쿠폰 번호에 문제가 있어
연결이 안 되는 경우는, 게임 진입 전 메시지로 유저에게 상황을 알려주고 대처할 수 있도록 처리한다.
5) 랜딩 URL을 PC 웹에서 접속 시 처리
쿠폰 딥링크, 인게임 딥링크의 랜딩URL은 모바일 에서만 접속 가능하다. 랜딩 URL을 PC 웹에서 접속
시, 모바일 접속 유도 메시지가 뜨며 해당 게임의 게임 소개 페이지 링크와 QA코드로 바로 다운로드 할
수 있도록 연결해 준다.
기타 이벤트 딥링크의 경우는 모바일과 PC웹 모두 동일하게 페이지가 뜬다.
유저 인게이지먼트 적용 시 준비사항
1) Hive SDK v1.10.0 이상 적용 필수
유저 인게이지먼트 서비스는 Hive SDK v1.10.0 이상 버전 적용시 사용 가능하다.
2) Scheme URL 등록 필수
유저 인게이지먼트 기능을 사용하기 위해서는 각 게임 클라이언트에 해당 게임에 접근하기 위한 Scheme이
등록되어 있어야 한다. 각 게임에 접근할 때 사용할 Scheme은 APP ID와 동일한 값으로 이용해야 하는
것이 원칙이며, 이를 따르지 않을 경우 유저 인게이지먼트 모듈에서 제공하는 기능이 작동하지 않을 수 있다.
Scheme을 등록하는 방법은 [5. API 연동 가이드]를 참고.
3) 자동 분기되는 게임 다운로드 URL 필요
백오피스에서 딥링크를 생성하려면, OS별로 자동으로 분기할 수 있는 게임 다운로드 URL을 미리 발급
해야 한다.
(컴투스 : QA 서비스 지원팀에서 발급 / 컴투스홀딩스: 마케팅팀에서 발급)
개발 개요
스키마 통합
기존에는 게임 개발팀에서 별도로 구현하고 있던 쿠폰 딥링크 기능을 Hive SDK v1.10.0에서 처리할 수 있도록 개발되었다.
이에따라 기존에 모듈별로 달랐던 URL스키마 구조를 동일한 규격으로 맞추어 작업의 효율성을 높였으며 동일한 스키마 구조를 통해 딥링크 모듈간 연동, 푸시 기능 수행시 연동 프로세스를 확장할 수 있으며, 클라이언트 개발 시 통일성을 유지 할 수 있다.
이에 따라 유저 인게이지먼트 서비스에 사용되는 모듈의 URL 스키마에 대한 표준을 제시하며, 스키마 통합 대상은 딥링크(Deep Link), 푸시(Push Notification), 인터워크(Interwork) 다.
URL 스키마 통합을 위한 기본 사항은 다음과 같다.
- URL 스키마 발급을 위한 별도 키 등의 추가 정보는 세팅하지 않는다.
- 게임에서 사용하는 스키마는 게임에서 직접 사용할 수 있도록 파싱하여 제공한다.
- 3가지 서비스(딥링크, 푸시, 인터워크)에서 사용하는 URL 스키마는 동일한 형식으로 사용할 수 있도록 정의한다.
- URL 스키마는 서비스 필드 영역과 공통 필드 영역으로 나타내며 서비스 필드를 통해 해당 서비스를 파악할 수 있다.
스키마 표준안
URL 스키마 구조는 서비스를 나타내는 서비스 필드와 데이터 및 액션을 나타내는 공통 필드로 구성된다.
서비스 필드 {scheme}://{host}/
- scheme 값 종류:
- 딥링크 > 게임 appid 사용
- 인터워크 > interwork:// 사용
- 푸시 > push:// 사용
- host 값 종류:
- 게임 내 주소인 경우 > game
- Hive 플랫폼 내 주소인 경우 > hive
- 공통 필드 {path}?{parameters}
- path > 해당 서비스에서 행동을 위한 액션 필드 값
- parameter > 액션에 필요한 파라메터 필드 값
사용 예시
- Hive 친구 초대 위치를 딥링크 주소로 전송하는 경우 (Hive SDK v1.19.1부터 socialinvitation 지원 중단)
com.com2us.misample.normal.freefull.apple.global.ios.universal://hive/socialinvitation?uid=172945352 - Hive 친구 초대 위치를 푸시로 전송하는 경우 (Hive SDK v1.19.1부터 socialinvitation 지원 중단)
push://hive/socialinvitation?uid=172945352 - 인게임 내에서 Hive 친구 초대 위치로 이동하는 경우(인터워크) (Hive SDK v1.19.1부터 socialinvitation 지원 중단)
interwork://hive/socialinvitation?uid=172945352
스키마 흐름도
Hive SDK에서 제공하는 스키마
- 1) ({scheme} , interwork, push) ://hive/authlogin
- Hive 로그인 화면으로 이동
게스트 로그인을 하여 접속한 경우에는 Hive 로그인 페이지를, Hive 로그인하여 접속한 경우에는 화면 노출없이 자동로그인이 진행됨.
- 3) ({scheme} , interwork, push) ://hive/socalinquery
- 1:1 문의하기 페이지를 노출함.
- 4) ({scheme} , interwork, push) ://hive/promotionshow?type={number}
- Type 값으로 입력받은 값에 해당하는 viewid를 가진 프로모션 커스텀웹뷰를 노출함.
- 5) ({scheme} , interwork, push) ://hive/offerwallshow
- Offerwall 페이지를 노출함 (Android only)
- 6) ({scheme} , interwork, push) ://hive/promotioncoupon?couponid={couponid}
- couponid로 입력받은 쿠폰 소모처리를 진행.
쿠폰 처리를 진행한 결과는 C2SModuleApi_EngagementConsumeCoupon 콜백으로 전달받는다.
- 7) ({scheme} , interwork, push) ://hive/socialmessage?uid={uid}&text={message}
- uid로 입력 받은 유저에게 텍스트로 입력 받은 문구를 전송한다. (Hive SDK v1.19.1부터 socialmessage 지원 중단)
- 8) ({scheme} , interwork, push) ://hive/socialinvitation?uid={uid}
- uid로 입력 받은 유저에게 초대 메세지를 전송한다. (Hive SDK v1.19.1부터 socialinvitation 지원 중단)
- 9) ({scheme} , interwork, push) ://game/{path}?{query}
- 게임 내부 기능으로 이동하기 위한 스키마
C2SModuleApi_EngagementProcessScheme 콜백이 발생하며, 해당 콜백이 발생하는 경우 전달되는 이벤트 데이터를 확인하여 해당하는 액션을 취해야 한다.
개발 환경
Android 2.3.3 이상, IOS 7 이상, Unity3d, Cocos2d-x, Unreal Engine 4
API 연동 가이드
유저 인게이지먼트 연동 플로우
게임에 유저 인게이지먼트 적용시 게임 진행되는 플로우. 자세한 API 호출 규약 및 델리게이트로 전달받는 데이터 그리고 예시 코드는 이후에 작성되는 내용을 참고하여 진행한다.
<1.10.x FlowChart>
<1.11.0+ FlowChart>
C2SModuleEngagement_ProcessScheme
Android 기능 구현
Android Project에 Process Scheme 기능을 적용시 아래 내용을 게임 클라이언트 코드에 추가하면 딥링크, 푸쉬를 통해 인게이지먼트 모듈 기능을 사용할 수 있다.
인게임 내 링크(Interwork 기능)의 경우, Mercury내부에서 진입하기 때문에 별도의 코드 추가가 필요 없다.
인게임 내 링크(Interwork 기능)의 경우, 반드시 SetReady 이후에 호출하도록 변경되었다. (1.11.0+)
Manifest에 코드 추가하기
Android Project의 Manifest 파일의 MainActivity 코드 안에 아래와 같이 코드를 추가한다.
- 주의: < data android:scheme = ” ” />의 “” 안에 적혀 있는 문구가 해당 앱으로 접속하기 위한 Scheme 값이 되며, 해당 문구는 AppID와 동일한 값이어야 한다.
언리얼 엔진은 HiveSDK_APL.xml 에서 수정한다.
launchMode는 singleTask 기본값으로 되어있으니 생략한다.
1 2 3 4 5 6 |
< intent - filter > < action android:name="android.intent.action.VIEW" /> < category android:name="android.intent.category.DEFAULT" /> < category android:name="android.intent.category.BROWSABLE" /> < data android:scheme="<strong>com.com2us.misample.normal.freefull.google.global.android.common</strong>" /> < / intent - filter > |
Manifest파일의 MainActivity의 launch Mode를 확인. singleTask 혹은 singleTop 모드로 설정해야 한다.
1 2 3 4 5 6 7 |
<activity android:name="com.com2us.misample.normal.freefull.google.global.android.common.MainActivity" android:launchMode="<strong>singleTask</strong>" /> 혹은 <activity android:name="com.com2us.misample.normal.freefull.google.global.android.common.MainActivity" android:launchMode="<strong>singleTop</strong>" /> |
MainActivity에 코드 추가하기
모바일 메세지 내의 딥링크 혹은 푸시 메세지에 온 딥링크를 통해 게임에 접근하게 되는 경우, 해당 URL 값을 받아 처리하는 로직을 추가한다.
작업하고 있는 Android Project의 MainActivity.java에 아래의 코드를 추가한다.
(Unity의 경우 UnityPlayerNativeActivity.java)
언리얼 엔진은 HiveSDK_APL.xml 에서 수정한다. 예시 코드가 포함되어있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
import com.com2us.module.C2SModuleEngagement; import com.com2us.module.C2SModuleError; import com.com2us.module.C2SModuleArgument; import com.com2us.module.C2SModuleCompletionHandler; ... private void doProcessScheme(string scheme) { C2SModuleArgument argProcessScheme = new C2SModuleArgument(); argProcessScheme.put("scheme", scheme); argProcessScheme.put("immediately", true); C2SModuleEngagement.ProcessScheme(argProcessScheme, new C2SModuleCompletionHandler () { @Override public void onComplete(C2SModuleArgument arg, C2SModuleError error){ <span class="guide_font_blue">// host가 game인 경우 게임에서 정의된 데이타로 캐싱했다가 인게임에서 정의된 데로 로직 구현 </span> Object[] events = arg.getObject("events"); if(events != null) { for(Object iter : events) { if(iter instanceof C2SModuleArgument){ int nowIndex = ((C2SModuleArgument)iter).getInteger("index"); Object nowEvent = ((C2SModuleArgument)iter).getObject("event"); if(nowEvent instanceof C2SModuleArgument){ String scheme = ((C2SModuleArgument) nowEvent).getString("scheme"); String host = ((C2SModuleArgument) nowEvent).getString("host"); String path = ((C2SModuleArgument) nowEvent).getString("path"); Object query = ((C2SModuleArgument) nowEvent).getObject("query"); if(query != null) { String queryData = ((C2SModuleArgument) query).getString("<span class="guide_font_gray">(keyname)</span>"); } } } } } }); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
@Override protected void onResume() { super.onResume(); Intent intent = getIntent(); if(intent != null){ String action = intent.getAction(); Uri data = intent.getData(); Bundle bundleData = intent.getExtras(); String scheme = ""; if(data != null){ <span class="guide_font_blue"> // 딥링크 로 접속한 경우</span> scheme = data.toString(); intent.setData(null); }else if (bundleData != null){ <span class="guide_font_blue"> // 푸시를 통해 접속한 경우</span> String pushAction = bundleData.getString("action"); if(pushAction != null){ scheme = pushAction; intent.getExtras().clear(); } } if(!scheme.equals("")){ doProcessScheme(scheme); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
@Override protected void onNewIntent(Intent intent){ super.onNewIntent(intent); String scheme = ""; Bundle intentBundle = intent.getExtras(); Uri data = intent.getData(); if(data != null){ <span class="guide_font_blue">// 딥링크로 들어온 경우</span> scheme = data.toString(); intent.setData(null); }else if(intentBundle != null){ <span class="guide_font_blue"> //푸시를 통해 접속한 경우</span> String inData = intentBundle.getString("action"); if(inData != null){ scheme = inData; intent.getExtras().clear(); } } if(!scheme.equals("")){ doProcessScheme(scheme); } } |
C2SModuleEngagement_SetReady
Engagement를 사용할 준비가 완료되면 SetReady를 호출한다.
Engagement_SetReady참고
적용 결과 예시
1) 게임이 설치되어 있는 경우
게임이 설치되어 있는 경우 게임 팁 메세지 확인 후 게임으로 이동한다.
2) 게임이 설치되어 있지 않은 경우
메시지 내 링크를 클릭하면 게임을 설치 후에만 보상을 받을 수 있음을 알려준다. 게임이 설치되어 있지 않기 때문에 마켓으로 이동시켜 준다.
3) 게임 설치 여부 판단이 안 되는 경우
인텐트(intent)가 불가한 상황에서는 게임 설치 여부 판단이 어렵다. Android 구 버전 혹은 단말기종에 따라 인텐트를 사용할 수 없는 경우 처리되는 플로우.
중국 IP의 경우, Android 는 게임 설치 여부, 인텐트 가능 여부와 관계 없이 아래의 플로우가 진행 되며, 다운 받기 클릭 시 마켓 이동이 아닌 apk 다운로드 페이지로 이동된다.
iOS 기능 구현
iOS Project에 Process Scheme 기능을 적용한다. 아래 내용을 게임 클라이언트 코드에 추가하면 딥링크, 푸쉬를 통해 인게이지먼트 모듈 기능을 사용할 수 있다.
인게임 내 링크(interwork 기능)의 경우, Mercury내부에서 진입하기 때문에 별도의 코드 추가가 필요 없다.
인게임 내 링크(Interwork 기능)의 경우, 반드시 SetReady 이후에 호출하도록 변경되었다. (1.11.0+)
Info에 URL Type 추가
프로젝트 설정에서 Info -> URL Types에 아래 화면과 같이 추가한다.
URL Schemes에 적혀있는 문구가 해당 앱으로 접속하기 위한 Scheme 값이다.
언리얼 엔진은 Unreal 설정하기 플랫폼 – iOS – Extra PList Data 에서 다음과 같은 형태로 URLscheme plist data 직접 추가한다.
1 2 3 4 5 6 7 |
<span class="sc3"><span class="re1"><key<span class="re2">></span></span>CFBundleURLTypes<span class="re1">></span> <span class="re1"><array<span class="re2">></span></span> <span class="re1"><dict<span class="re2">></span></span> <span class="re1"><key<span class="re2">></span></span>CFBundleTypeRole<span class="re1">></span><span class="re1"><string<span class="re2">></span>Editor> <key<span class="re2">></span>CFBundleURLSchemes><array<span class="re2">></span><string<span class="re2">></span>com.com2us.misample.normal.freefull.apple.global.ios.universal>> > ></span></span> |
AppController(AppDelegate)에 코드 추가
아래 코드는 모바일 메세지로 온 딥링크 URL을 클릭해서 게임에 접근 할 때 입력받은 스키마에 해당하는 이벤트를 수행하는 코드이다.
AppDelegate.mm 파일에 아래 코드를 추가한다.
(Unity의 경우 UnityAppController.mm파일에 아래 코드를 추가한다.)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
- (BOOL)application:(UIApplication*)application openURL:(NSURL*)url sourceApplication:(NSString*)sourceApplication annotation:(id)annotation { if(url){ NSError *error = nil; NSLog(@"%@",url.absoluteString); BOOL apiResult = [C2SModuleEngagement ProcessScheme:@{@"scheme":url.absoluteString,@"immediately":@(YES)} error:&error completionHandler:^(NSDictionary *arg, NSError *error) { // host가 game인 경우 게임에서 정의된 데이타로 캐싱했다가 인게임에서 정의된 데로 로직 구현 NSArray* events = arg[@"events"]; if(events != nil) { for(NSDictionary* iter in events) { NSNumber* nowIndex = iter[@"index"]; NSDictionary* nowEvent = iter[@"event"]; NSString* scheme = nowEvent[@"scheme"]; NSString* host = nowEvent[@"host"]; NSString* path = nowEvent[@"path"]; NSDictionary* query = nowEvent[@"query"]; if(query != nill) { NSString* queryData = query[@"(keyname)"]; } } } }]; if (!apiResult || error) { NSLog(@"process scheme with openurl fail : %@", error); } } } - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary <nsstring*, id=""> *)options { return [self application:app openURL:url sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey] annotation:options[UIApplicationOpenURLOptionsAnnotationKey]]; } |
다음은 푸시 메시지로 온 딥링크 URL을 클릭해 게임으로 접속했을 때 입력받은 스키마에 해당하는 이벤트를 수행할 코드이다.
application:didReceiveRemoteNotification은 게임 혹은 앱이 실행 중일 때 RemoteNotification을 받는 경우 호출된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo { if((application.applicationState != UIApplicationStateActive) || ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0)){ NSLog(@"didREcieveRemoteNotification UIApplicationStateActive"); NSError * error = nil; BOOL apiResult = [C2SModuleEngagement ProcessScheme:@{@"scheme":userInfo[@"action"],@"immediately":@(YES)} error:&error completionHandler:^(NSDictionary *arg, NSError *error) { // host가 game인 경우 게임에서 정의된 데이타로 캐싱했다가 인게임에서 정의된 데로 로직 구현 }]; if (!apiResult || error) { NSLog(@"process scheme with push fail : %@", error); } } else { NSLog(@"Ignore remote notification when applicationState is active."); } } |
application:didReceiveRemoteNotification:fetchCompletionHandler는 게임 혹은 앱이 백그라운드에 있을 때 호출된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))handler { if((application.applicationState != UIApplicationStateActive) || ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0)){ NSLog(@"didREcieveRemoteNotification UIApplicationStateActive"); NSError * error = nil; BOOL apiResult = [C2SModuleEngagement ProcessScheme:@{@"scheme":userInfo[@"action"],@"immediately":@(YES)} error:&error completionHandler:^(NSDictionary *arg, NSError *error) { // host가 game인 경우 게임에서 정의된 데이타로 캐싱했다가 인게임에서 정의된 데로 로직 구현 }]; if (!apiResult || error) { NSLog(@"process scheme with push fail : %@", error); } } else { NSLog(@"Ignore remote notification when applicationState is active."); } } |
언리얼 엔진은 FIOSCoreDelegates::OnOpenURL, FCoreDelegates::ApplicationReceivedRemoteNotificationDelegate을 구현한 코드에서 수정한다. 샘플의 예제코드를 참조한다.
C2SModuleEngagement_SetReady
Engagement를 사용할 준비가 완료되면 SetReady를 호출한다.
Engagement_SetReady참고
적용 결과 예시
1) 게임이 설치되어 있는 경우
메시지 내 링크를 클릭하면 바로 게임이 실행된다.
2) 게임이 설치되어 있지 않은 경우
메시지 내 링크를 클릭하면 게임을 설치 후에만 보상을 받을 수 있음을 알려준다.
게임이 설치되어 있지 않기 때문에 마켓으로 이동시켜 준다.
아래 이미지의 2번의 경우는 iOS 단말 특성상 나타나는 팝업.
쿠폰 사용 및 에러 처리
모바일 메시지로 전달한 쿠폰 딥링크 주소를 클릭하여 게임에 진입한 유저는 우편함에서 선물을 받게 된다. 이 때 유저가 사용한 쿠폰 번호와 함께 쿠폰을 사용 했음을 서버에게 알려주고, 쿠폰 번호에 문제가 없다면 클라이언트는 서버로부터 성공 응답을 받는다.
쿠폰 번호에 문제가 있는 경우 에러 쿠폰 코드 리스트 중 하나에 해당될 것이며, 유저에게 에러 상황을 인지해 주고 대처할 수 있도록, 게임 진입 전 메시지로 알려준다.
C2SModuleEngagement_ConsumeCoupon
Engagement_ConsumeCoupon 참고
C2SModuleEngagement_GetEvents
Engagement_GetEvents 참고
샘플 코드
샘플 코드 참고
에러 쿠폰 코드 리스트
Code | 설명 | Code | 설명 | |
---|---|---|---|---|
200 | 잘못된 파라미터로 접근 | 305 | 사용 개수가 만료된 고유 쿠폰 | |
201 | 잘못된 hash값으로 전달 | 306 | 사용 기간이 만료된 쿠폰 | |
202 | 해당 계정 사용 한도 초과 | 307 | 신규/기존 유저를 구분하는 이벤트지만 필요정보가 없거나 AU 시스템 오류 | |
203 | 쿠폰 그룹의 사용 제한 초과 | 308 | 기존 유저 대상 이벤트지만 해당 유저가 아님 | |
204 | 발급된 쿠폰과 넘어온 AppID가 다름 | 309 | 신규 유저 대상 이벤트지만 해당 유저가 아님 | |
300 | 쿠폰 번호 자리수가 잘못됨 | 310 | 신규/기존 이벤트인데 해당 게임에서 입력하지 않음 | |
301 | 전달 받은 프로모션 정보에 해당 쿠폰 정보 없음 | 400 | 아이템 전송 전부 실패 | |
302 | 쿠폰 번호 조회 실패 | 401 | 아이템 전송 일부 실패 | |
303 | 사용 중인 쿠폰 | 500 | DB 에러 | |
304 | 사용 완료된 쿠폰 | 501 | 통신 실패 |
적용 결과 예시
모바일 메시지 내의 쿠폰 딥링크 클릭 시, 에러 쿠폰인 경우, 게임 진입이 안되고 하단 이미지의 1~5번 처럼 에러 상황을 알려주고 대처할 수 있도록 안내 한다.
위의 에러 쿠폰 코드 리스트 중 주로 발생하는 302, 304, 305, 306 번 에러 코드에 한하여 예외 처리 메시지가 적용되어 있으며, 그 외 쿠폰 에러인 경우, 5번처럼 공통으로 대응할 수 있는 메시지가 나온다.
C2SModuleEngagement_ProcessScheme
딥링크와 푸시, 인터워크를 통해 전달 받은 URL을 처리하기 위해 호출하는 API 이다.
딥링크 혹은 푸쉬를 통해 앱에 진입하는 경우 해당 시점에서 전달받은 Scheme값을 ProcessScheme API에 전달하여 해당 함수를 수행하도록 한다.
argument type | type | desc | platform | 비고 |
---|---|---|---|---|
scheme | String | 처리를 요청 할 URL | all | |
immediately | Boolean | 응답을 즉시 받을 지 여부 true : 처리 된 이벤트 정보를 즉시 받는다. false : Arg를 그대로 받으며 처리된 이벤트는 이벤트 큐에 누적된다. C2SModuleEngagement_GetEvents 를 통해 누적된 이벤트를 받을 수 있다. |
all |
Result – Api.Engagement_ProcessScheme
ProcessScheme API가 호출되면 전달받는 콜백함수. Argument로 전달받은 scheme값을 파싱하여 전달.
host값이 “game”인 경우 게임 개발사 내부에서 자체적으로 동작할 로직을 구현하여야 한다.
argument name | type | desc | platform | 비고 |
---|---|---|---|---|
events | Array | 이벤트 데이터 배열 | all |
Array type for events
argument name | type | desc | platform | 비고 |
---|---|---|---|---|
index | integer | 이벤트 인덱스 | all | |
event | Dictionary | 이벤트 정보 | all |
Dictionary type for event
argument name | type | desc | platform | 비고 |
---|---|---|---|---|
scheme | String | 이벤트 Scheme. 이벤트 진입 지점을 의미한다. | all | |
host | String | 이벤트 Host. 이벤트 처리 지점을 의미한다. | all | |
path | String | 이벤트 Path. 이벤트가 수행할 기능을 의미한다. | all | |
query | Dictionary | 이벤트 Query. 이벤트 수행에 필요한 파라메터를 의미한다. | all |
C2SModuleEngagement_ConsumeCoupon
쿠폰 지급 요청 처리를 수행하는 API 이다.
Hive SDK v1.12.0 버전부터 기존의 식별자 파라미터가 삭제되고 통합 식별자로 통일되었다.
현재 사용중인 통합 식별자 language는 아래 API에서 설정 가능하다.
– C2SModuleSocial_Initialize
– C2SModuleSocial_SetGameInfo
argument type | type | desc | platform | 비고 |
---|---|---|---|---|
couponId | String | 사용 처리할 쿠폰 코드 | all | |
language | String | 게임 언어 코드 게임 언어 코드값은 ‘ISO 639 alpha-2′(ISO 639-1) 코드를 기준으로 하며 Hive 연동 가이드라인 언어 항목을 참고한다. |
all | (1.12.0+ 삭제) |
additionalInfo | String | (필수)서버군이 따로 없는 단일 서버군이라도 아래 예제대로 넣어야 함 ex)”addtionalInfo”:”{“server”:”서버 지역 코드값“, “character”:”0″}” |
서버 지역 코드값은 ‘ISO 3166 alpha-2’ 코드를 기준으로 하며 Hive 연동 가이드라인 게임서버 ID 항목을 참고한다.
Result – Api.Engagement_ConsumeCoupon
argument name | type | desc | platform | 비고 |
---|---|---|---|---|
code | Integer | 처리 결과 코드 (성공: 100, 에러 코드 : 아래표 참고) | all | |
message | String | 처리 결과 메세지 (요청 시 보낸 언어 코드에 따라 달라짐) | all |
쿠폰 에러 코드 리스트
Code | 설명 | Code | 설명 | |
---|---|---|---|---|
200 | 잘못된 파라미터로 접근 | 305 | 사용 개수가 만료된 고유 쿠폰 | |
201 | 잘못된 hash값으로 전달 | 306 | 사용 기간이 만료된 쿠폰 | |
202 | 해당 계정 사용 한도 초과 | 307 | 신규/기존 유저를 구분하는 이벤트지만 필요정보가 없거나 AU 시스템 오류 | |
203 | 쿠폰 그룹의 사용 제한 초과 | 308 | 기존 유저 대상 이벤트지만 해당 유저가 아님 | |
204 | 발급된 쿠폰과 넘어온 AppID가 다름 | 309 | 신규 유저 대상 이벤트지만 해당 유저가 아님 | |
300 | 쿠폰 번호 자리수가 잘못됨 | 310 | 신규/기존 이벤트인데 해당 게임에서 입력하지 않음 | |
301 | 전달 받은 프로모션 정보에 해당 쿠폰 정보 없음 | 400 | 아이템 전송 전부 실패 | |
302 | 쿠폰 번호 조회 실패 | 401 | 아이템 전송 일부 실패 | |
303 | 사용 중인 쿠폰 | 500 | DB 에러 | |
304 | 사용 완료된 쿠폰 | 501 | 통신 실패 |
C2SModuleEngagement_GetEvents
ProcessScheme API 호출 시 Immediate 값이 false로 저장된 이벤트들을 불러오는 API이다.
Host 값이 ‘Hive’인 이벤트는 해당하는 이벤트를 호출한다.
Host 값이 ‘game’인 이벤트는 해당 스키마 정보를 EngagementGetEvents 콜백 전달시 JSON 형식으로 전달된다.
(Only 1.10.x)
argument type | type | desc | platform | 비고 |
---|---|---|---|---|
argument 없음 |
Result – Api.Engagement_GetEvents
argument name | type | desc | platform | 비고 |
---|---|---|---|---|
events | Array | 이벤트 데이터 배열 | all |
Array type for events
argument name | type | desc | platform | 비고 |
---|---|---|---|---|
index | integer | 이벤트 인덱스 | all | |
event | Dictionary | 이벤트 정보 | all |
Dictionary type for event
argument name | type | desc | platform | 비고 |
---|---|---|---|---|
scheme | String | 이벤트 Scheme. 이벤트 진입 지점을 의미한다. | all | |
host | String | 이벤트 Host. 이벤트 처리 지점을 의미한다. | all | |
path | String | 이벤트 Path. 이벤트가 수행할 기능을 의미한다. | all | |
query | Dictionary | 이벤트 Query. 이벤트 수행에 필요한 파라메터를 의미한다. | all |
C2SModuleEngagement_SetReady
Engagement를 사용할 준비가 되었음을 모듈에 전달하는 API (1.11.0+)
SetReady 호출 이전에 전달된 Push, Deep link를 통한 스키마는 SetReady 호출 시점에 기능 동작을 수행한다.
SetReady 호출 이후에 전달되는 스키마는 호출 즉시 수행된다.
(* Interwork는 반드시 SetReady를 호출한 이후에 전달되어야 한다.)
Google Play Store에서 Hive IAP v4를 이용해 오프라인 구매가 진행될 경우, 구매 완료 후 앱에서 영수증 정보를 수신하려면 Setready를 호출해야 한다. SetReady 호출 후 C2SModuleInappV4_Restore API를 호출하면 해당 아이템의 영수증 정보를 받을 수 있다.
Hive SDK v1.22.0.3 이상에서 SetReady 호출 시 IAP v4 Android, IAP v4 iOS에서 앱 런타임 중 미성년자의 결제 요청을 부모가 승인하여 트랜잭션의 상태가 구매 보류(Pending) 상태에서 구매 완료 상태로 변경 시 상태가 전달된다. 소모성 상품에 대한 보류 처리가 완료로 변경된 경우 “interwork://hive/iapupdated” 값이, 구독형 상품의 경우 “interwork://hive/iapupdated/subscription” 값이 ProcessScheme 콜백으로 전달된다. 이때 상품 유형에 따라 C2SModuleInAppV4_Restore API를 호출하면 영수증 정보를 받을 수 있다.
logout을 수행하는경우 이전에 호출했던 SetReady의 여부가 초기화되기 때문에, 로그아웃 이후엔 반드시 SetReady를 다시 호출해야 Engagement를 사용할 수 있다.
argument type | type | desc | platform | 비고 |
---|---|---|---|---|
argument 없음 |
Returns
YES일 경우 성공. NO일 경우 실패.
Engagement Callback
EngagementStart, EngagementEnd 콜백 관련 로직은 하단에 작성된 플로우차트를 참고한다.
Result – Api.Engagement_Start
ProcessScheme API 호출시 Scheme의 host값이 “hive”인 이벤트처리가 시작되기 전 클라이언트에게 보내는 콜백
해당 콜백은 로그인 까지 진행된 이후에 콜백이 전달 된다.
argument type | type | desc | platform | 비고 |
---|---|---|---|---|
engagementArg | Dictionary | 인게이지먼트 데이터 – url scheme 파싱해서 전달된 데이터 |
all |
Dictionary type for interworkArg
argument type | type | desc | platform | 비고 |
---|---|---|---|---|
type | string | 인게이지먼트 Api 이름 전달 | all | |
params | Dictionary | Engagement url scheme에 파라메터가 있을 경우 담아서 전달된다. (json 형식의 데이터를 파싱하기 때문에 어떠한 데이터 타입도 올 수 있다.) |
all |
Dictionary type for params
argument type | type | desc | platform | 비고 |
---|---|---|---|---|
params | string | 해당 파라메터의 키값 | all |
Result -Api.Promotion_Show
({scheme} , interwork, push) ://hive/promotionshow?type={number}
({scheme} , interwork, push) ://hive/offerwallshow
유저 인게이지먼트로 시작된 이벤트이면 배너가 닫힐 때 engagementArg함께 콜백이 전달된다.
argument type | type | desc | platform | 비고 |
---|---|---|---|---|
engagementArg | Dictionary | 인게이지먼트 데이터 – url scheme 파싱해서 전달된 데이터 |
all |
key-value for interworkArg
argument type | type | desc | platform | 비고 |
---|---|---|---|---|
type | string | 인게이지먼트 Api 이름 전달 | all | |
params | Dictionary | Engagement url scheme에 파라메터가 있을 경우 담아서 전달된다. (json 형식의 데이터를 파싱하기 때문에 어떠한 데이터 타입도 올 수 있다.) |
all |
Dictionary type for params
argument type | type | desc | platform | 비고 |
---|---|---|---|---|
params | string | 해당 파라메터의 키값 | all |
Result -Api.Sns_Login
({scheme} , interwork, push) ://hive/authlogin
유저 인게이지먼트로 시작된 이벤트이면 로그인이 끝나게 되면 engagementArg 함께 콜백이 전달 된다.
argument type | type | desc | platform | 비고 |
---|---|---|---|---|
engagementArg | Dictionary | 인게이지먼트 데이터 – url scheme 파싱해서 전달된 데이터 |
all |
key-value for interworkArg
argument type | type | desc | platform | 비고 |
---|---|---|---|---|
type | string | 인게이지먼트 Api 이름 전달 | all | |
params | Dictionary | Engagement url scheme에 파라메터가 있을 경우 담아서 전달된다. (json 형식의 데이터를 파싱하기 때문에 어떠한 데이터 타입도 올 수 있다.) |
all |
Dictionary type for params
argument type | type | desc | platform | 비고 |
---|---|---|---|---|
params | string | 해당 파라메터의 키값 | all |
Result -Api.Sns_Show
({scheme} , interwork, push) ://hive/socialinquery
유저 인게이지먼트로 시작된 이벤트이면 engagementArg와 함께 콜백이 전달 된다.
argument type | type | desc | platform | 비고 |
---|---|---|---|---|
engagementArg | Dictionary | 인게이지먼트 데이터 – url scheme 파싱해서 전달된 데이터 |
all |
key-value for interworkArg
argument type | type | desc | platform | 비고 |
---|---|---|---|---|
type | string | 인게이지먼트 Api 이름 전달 | all | |
params | Dictionary | Engagement url scheme에 파라메터가 있을 경우 담아서 전달된다. (json 형식의 데이터를 파싱하기 때문에 어떠한 데이터 타입도 올 수 있다.) |
all |
Dictionary type for params
argument type | type | desc | platform | 비고 |
---|---|---|---|---|
params | string | 해당 Parameter의 키값 | all |
Result -Api.Sns_Message
({scheme} , interwork, push) ://hive/socialinvitation
({scheme} , interwork, push) ://hive/socialmessage
유저 인게이지먼트로 시작된 이벤트이면 engagementArg와 함께 콜백이 전달 된다. (Hive SDK v1.19.1부터 socialinvitation, socialmessage 지원 중단)
argument type | type | desc | platform | 비고 |
---|---|---|---|---|
engagementArg | Dictionary | 인게이지먼트 데이터 – url scheme 파싱해서 전달된 데이터 |
all |
key-value for interworkArg
argument type | type | desc | platform | 비고 |
---|---|---|---|---|
type | string | 인게이지먼트 Api 이름 전달 | all | |
params | Dictionary | Engagement url scheme에 파라메터가 있을 경우 담아서 전달된다. (json 형식의 데이터를 파싱하기 때문에 어떠한 데이터 타입도 올 수 있다.) |
all |
Dictionary type for params
argument type | type | desc | platform | 비고 |
---|---|---|---|---|
params | string | 해당 파라메터의 키값 | all |
Result -Api.Engagement_GameScheme
({scheme} , interwork, push) ://game/~~
({scheme} , interwork, push) ://game/~~
host가 game인 스키마는 GameScheme 콜백을 받는다. (1.11.0+)
argument name | type | desc | platform | 비고 |
---|---|---|---|---|
scheme | String | 이벤트 Scheme. 이벤트 진입 지점을 의미한다. | all | 1.11.0+ |
host | String | 이벤트 Host. 이벤트 처리 지점을 의미한다. | all | 1.11.0+ |
path | String | 이벤트 Path. 이벤트가 수행할 기능을 의미한다. | all | 1.11.0+ |
query | Dictionary | 이벤트 Query. 이벤트 수행에 필요한 파라메터를 의미한다. | all | 1.11.0+ |
Result – Api.Engagement_End
유저 인게이지먼트가 처리에 대한 구현이 되어 있지 않거나 처리가 불가할 경우 해당 콜백이 전달 된다.
argument type | type | desc | platform | 비고 |
---|---|---|---|---|
engagementArg | Dictionary | 인게이지먼트 데이터 – url scheme 파싱해서 전달된 데이터 |
all |
key-value for interworkArg
argument type | type | desc | platform | 비고 |
---|---|---|---|---|
type | string | 인게이지먼트 Api 이름 전달 | all | |
params | Dictionary | Engagement url scheme에 parameter가 있을 경우 담아서 전달된다. (json 형식의 데이터를 파싱하기 때문에 어떠한 데이터 타입도 올 수 있다.) |
all |
Dictionary type for params
argument type | type | desc | platform | 비고 |
---|---|---|---|---|
params | string | 해당 파라메터의 키값 | all |
샘플 코드
public static bool C2SModule.Engagement.ConsumeCoupon(C2SModule.Parameter arg, out C2SModule.Error error, C2SModule.CompletionHandler completionHandler);
– 쿠폰 소모 처리를 수행한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<span class="guide_font_red">/* 1.10.0 추가 */</span> <span class="guide_font_red">/* 쿠폰 소모 처리 */</span> C2SModule.Parameter arg = new C2SModule.Parameter (); arg ["couponId"] = "couponid"; arg ["language"] = "ko" <span class="guide_font_red">// 1.12.0미만 : language 키 설정 필요, 1.12.0이상 : language 키 사용하지 않음.</span> arg ["additionalInfo"] = "" C2SModule.Error error; if(!C2SModule.Engagement.ConsumeCoupon(arg, out error)) { // Error 시 처리 } |
public static bool C2SModule.Engagement.GetEvents(C2SModule.Parameter arg, out C2SModule.Error error,
C2SModule.CompletionHandler completionHandler);
– Immediate 값이 false로 저장된 이벤트들을 불러온다. (1.10.x)
1 2 3 4 5 6 7 8 9 10 |
<span class="guide_font_red">/* 1.10.0 추가 */</span> <span class="guide_font_red">/* 이벤트 호출 */</span> C2SModule.Parameter arg = new C2SModule.Parameter (); C2SModule.Error error; if(!C2SModule.Engagement.GetEvents (arg, out error)) { // Error 시 처리 } |
public static bool C2SModule.Engagement.SetReady(C2SModule.Parameter arg, out C2SModule.Error error,
C2SModule.CompletionHandler completionHandler);
– Engagement를 사용할 준비가 되었음을 모듈에 전달한다. (1.11.0+)
이전에 전달되었던 스키마의 기능들이 동작하며, 이후로 전달되는 스키마는 즉시 수행된다.
(* Interwork는 반드시 SetReady를 호출한 이후에 전달되어야 한다.)
1 2 3 4 5 6 7 8 9 |
<span class="guide_font_red">/* 1.11.0 추가 */</span> C2SModule.Parameter arg = new C2SModule.Parameter (); C2SModule.Error error; if(!C2SModule.Engagement.GetReady (arg, out error)) { // Error 시 처리 } |
Callback
인게이지먼트 모듈 호출 중 전달 받는 콜백 데이터 처리방법에 대한 예제 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
//Unity3d:C2SModule.Engagement.Start public static void ResultDelegate(C2SModule.Api api, C2SModule.Parameter arg, C2SModule.Error error){ switch(api){ case C2SModule.Api.Engagement_Start: if(arg.ContainsKey("engagementArg")){ // Engagement에서 콜백 전달받음 Dictionary<string, object=""> dict = arg["engagementArg"] as Dictionary<string, object="">; string type = dict["type"] as string; Dictionary<string, object=""> paramDict = arg["params"] as Dictionary<string, object="">; } break; } } //Unity3d:C2SModule.Sns.Login public static void ResultDelegate(C2SModule.Api api, C2SModule.Parameter arg, C2SModule.Error error){ switch(api){ case C2SModule.Api.Sns_Login: if(arg.ContainsKey("engagementArg")){ // Engagement에서 콜백 전달받음 Dictionary<string, object=""> dict = arg["engagementArg"] as Dictionary<string, object="">; string type = dict["type"] as string; Dictionary<string, object=""> paramDict = arg["params"] as Dictionary<string, object="">; } break; } } //Unity3d:C2SModule.Sns.Show public static void ResultDelegate(C2SModule.Api api, C2SModule.Parameter arg, C2SModule.Error error){ switch(api){ case C2SModule.Api.Sns_Show: if(arg.ContainsKey("engagementArg")){ // Engagement에서 콜백 전달받음 Dictionary<string, object=""> dict = arg["engagementArg"] as Dictionary<string, object="">; string type = dict["type"] as string; Dictionary<string, object=""> paramDict = arg["params"] as Dictionary<string, object="">; } break; } } //Unity3d:C2SModule.Promotion.Show public static void ResultDelegate(C2SModule.Api api, C2SModule.Parameter arg, C2SModule.Error error){ switch(api){ case C2SModule.Api.Promotion_Show: if(arg.ContainsKey("engagementArg")){ // Engagement에서 콜백 전달받음 Dictionary<string, object=""> dict = arg["engagementArg"] as Dictionary<string, object="">; string type = dict["type"] as string; Dictionary<string, object=""> paramDict = arg["params"] as Dictionary<string, object="">; } break; } } //Unity3d:C2SModule.Engagement.ConsumeCoupon public static void ResultDelegate(C2SModule.Api api, C2SModule.Parameter arg, C2SModule.Error error){ switch(api){ case C2SModule.Api.Engagement_ConsumeCoupon: if(arg.ContainsKey("engagementArg")){ // Engagement에서 콜백 전달받음 Dictionary<string, object=""> dict = arg["engagementArg"] as Dictionary<string, object="">; string type = dict["type"] as string; Dictionary<string, object=""> paramDict = arg["params"] as Dictionary<string, object="">; } break; } } //Unity3d:C2SModule.Sns.Message public static void ResultDelegate(C2SModule.Api api, C2SModule.Parameter arg, C2SModule.Error error){ switch(api){ case C2SModule.Api.Sns_Message: if(arg.ContainsKey("engagementArg")){ // Engagement에서 콜백 전달받음 Dictionary<string, object=""> dict = arg["engagementArg"] as Dictionary<string, object="">; string type = dict["type"] as string; Dictionary<string, object=""> paramDict = arg["params"] as Dictionary<string, object="">; } break; } } //Unity3d:C2SModule.Engagement.GameScheme public static void ResultDelegate(C2SModule.Api api, C2SModule.Parameter arg, C2SModule.Error error){ switch(api){ case C2SModule.Api.Engagement_GameScheme: string scheme = arg["scheme"] as string; string host = arg["host"] as string; string eventstr = arg["event"] as string; Dictionary<string, object=""> queryDict = arg["query"] as Dictionary<string, object="">; if(queryDict != null){ // query 값 파싱 } break; } } //Unity3d:C2SModule.Engagement.End public static void ResultDelegate(C2SModule.Api api, C2SModule.Parameter arg, C2SModule.Error error){ switch(api){ case C2SModule.Api.Engagement_End: if(arg.ContainsKey("engagementArg")){ // Engagement에서 콜백 전달받음 Dictionary<string, object=""> dict = arg["engagementArg"] as Dictionary<string, object="">; string type = dict["type"] as string; Dictionary<string, object=""> paramDict = arg["params"] as Dictionary<string, object="">; } break; } } |
– 쿠폰 소모 처리를 수행한다.
1 2 3 4 5 6 7 8 9 10 |
TSharedPtr arg = MakeShareable(new FJsonObject); arg–>SetStringField(TEXT("couponId"), coupon); arg–>SetStringField(TEXT("language"), language); // 1.12.0미만 : language 키 설정 필요, 1.12.0이상 : language 키 사용하지 않음. arg–>SetStringField(TEXT("additionalInfo"), additionalInfo); FString OutputString; TSharedRef< TJsonWriter<TCHAR, TCondensedJsonPrintPolicy< TCHAR >> > Writer = TJsonWriterFactory<TCHAR, TCondensedJsonPrintPolicy< TCHAR >>::Create(&OutputString); FJsonSerializer::Serialize(arg.ToSharedRef(), Writer); FHiveSDKModule::Get().HiveSDKUEEngagement_ConsumeCoupon(OutputString); |
– Immediate 값이 false로 저장된 이벤트들을 불러온다. (1.10.x)
1 2 |
FString empty; FHiveSDKModule::Get().HiveSDKUEEngagement_GetEvents(empty); |
– Engagement를 사용할 준비가 되었음을 모듈에 전달한다. (1.11.0+)
이전에 전달되었던 스키마의 기능들이 동작하며, 이후로 전달되는 스키마는 즉시 수행된다.
(* Interwork는 반드시 SetReady를 호출한 이후에 전달되어야 한다.)
1 2 |
FString empty; FHiveSDKModule::Get().HiveSDKUEEngagement_SetReady(empty); |
Callback
인게이지먼트 모듈 호출 중 전달 받는 콜백 데이터 처리방법에 대한 예제 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
//C2SModuleEngagement_Start void MYGAMECLASS::ResultDelegate(C2SModuleApi api, const char* json, C2SModuleErrorCode code, const char* message) { //... switch(api) { case C2SModuleApi_EngagementStart: { if(arg->HasField(TEXT("engagementArg"))) { // Engagement에서 콜백 전달받음 TSharedPtr arg2 = arg->GetObjectField(TEXT("engagementArg")); FString type = arg2->GetStringField(TEXT("type")); TSharedPtr paramsArg = arg2->GetObjectField(TEXT("params")); } break; } } //... } //C2SModuleSns_Login void MYGAMECLASS::ResultDelegate(C2SModuleApi api, const char* json, C2SModuleErrorCode code, const char* message) { //... switch(api) { case C2SModuleApi_SnsLogin: { if(arg->HasField(TEXT("engagementArg"))) { // Engagement에서 콜백 전달받음 TSharedPtr arg2 = arg->GetObjectField(TEXT("engagementArg")); FString type = arg2->GetStringField(TEXT("type")); TSharedPtr paramsArg = arg2->GetObjectField(TEXT("params")); } break; } } //... } //C2SModuleSns_Show void MYGAMECLASS::ResultDelegate(C2SModuleApi api, const char* json, C2SModuleErrorCode code, const char* message) { //... switch(api) { case C2SModuleApi_SnsShow: { if(arg->HasField(TEXT("engagementArg"))) { // Engagement에서 콜백 전달받음 TSharedPtr arg2 = arg->GetObjectField(TEXT("engagementArg")); FString type = arg2->GetStringField(TEXT("type")); TSharedPtr paramsArg = arg2->GetObjectField(TEXT("params")); } break; } } //... } //C2SModulePromotion_Show void MYGAMECLASS::ResultDelegate(C2SModuleApi api, const char* json, C2SModuleErrorCode code, const char* message) { //... switch(api) { case C2SModuleApi_PromotionShow: { if(arg->HasField(TEXT("engagementArg"))) { // Engagement에서 콜백 전달받음 TSharedPtr arg2 = arg->GetObjectField(TEXT("engagementArg")); FString type = arg2->GetStringField(TEXT("type")); TSharedPtr paramsArg = arg2->GetObjectField(TEXT("params")); } break; }} //... } //C2SModuleEngagement_ConsumeCoupon void MYGAMECLASS::ResultDelegate(C2SModuleApi api, const char* json, C2SModuleErrorCode code, const char* message) { //... switch(api) { case C2SModuleApi_EngagementConsumeCoupon: { if(arg->HasField(TEXT("engagementArg"))) { // Engagement에서 콜백 전달받음 TSharedPtr arg2 = arg->GetObjectField(TEXT("engagementArg")); FString type = arg2->GetStringField(TEXT("type")); TSharedPtr paramsArg = arg2->GetObjectField(TEXT("params")); } break; }} //... } //C2SModuleSns_Message void MYGAMECLASS::ResultDelegate(C2SModuleApi api, const char* json, C2SModuleErrorCode code, const char* message) { //... switch(api) { case C2SModuleApi_SnsMessage: { // Engagement에서 콜백 전달받음 if(arg->HasField(TEXT("engagementArg"))) { TSharedPtr arg2 = arg->GetObjectField(TEXT("engagementArg")); FString type = arg2->GetStringField(TEXT("type")); TSharedPtr paramsArg = arg2->GetObjectField(TEXT("params")); } break; }} //... } //C2SModuleEngagement_GameScheme void MYGAMECLASS::ResultDelegate(C2SModuleApi api, const char* json, C2SModuleErrorCode code, const char* message) { //... switch(api) { case C2SModuleApi_EngagementGameScheme: { // Engagement에서 콜백 전달받음 FString scheme = arg->GetStringField(TEXT("scheme")); FString host = arg2->GetStringField(TEXT("host")); FString eventStr = arg2->GetStringField(TEXT("event")); TSharedPtr queryArg = arg2->GetObjectField(TEXT("query")); if(queryArg != null){ //query값 파싱 } break; }} //... } //C2SModuleEngagement_End void MYGAMECLASS::ResultDelegate(C2SModuleApi api, const char* json, C2SModuleErrorCode code, const char* message) { //... switch(api) { case C2SModuleApi_EngagementEnd: { if(arg->HasField(TEXT("engagementArg"))) { // Engagement에서 콜백 전달받음 TSharedPtr arg2 = arg->GetObjectField(TEXT("engagementArg")); FString type = arg2->GetStringField(TEXT("type")); TSharedPtr paramsArg = arg2->GetObjectField(TEXT("params")); } break; }} //... } |
– 쿠폰 소모 처리를 수행한다.
1 2 3 4 5 6 7 8 9 |
/* 1.10.0 추가 */ /* 쿠폰 소모 처리 수행 */ NSError* error; // 1.12.0미만 : language 키 설정 필요, 1.12.0이상 : language 키 사용하지 않음. [C2SModuleEngagement ConsumeCoupon:@{@"couponId":@"couponid",@"language":@"ko", @"additionalInfo":@""} error:&error completionHandler:^(NSDictionary* resultArg, NSError* resultError){ if (resultError == nil) { //succeed } }]; |
– Immediate 값이 false로 저장된 이벤트들을 불러온다. (1.10.x)
1 2 3 4 5 6 7 8 9 |
/* 1.10.0 추가 */ /* 이벤트 호출 */ NSError* error; NSDictionary* arg = @{}; [C2SModuleEngagement GetEvents:arg error:&error completionHandler:^(NSDictionary* resultArg, NSError* resultError){ if (resultError == nil) { //succeed } }]; |
– Engagement를 사용할 준비가 되었음을 모듈에 전달한다. (1.11.0+)
이전에 전달되었던 스키마의 기능들이 동작하며, 이후로 전달되는 스키마는 즉시 수행된다.
(* Interwork는 반드시 SetReady를 호출한 이후에 전달되어야 한다.)
1 2 3 4 5 6 7 8 |
/* 1.11.0 추가 */ NSError* error; NSDictionary* arg = @{}; [C2SModuleEngagement SetReady:arg error:&error completionHandler:^(NSDictionary* resultArg, NSError* resultError){ if (resultError == nil) { //succeed } }]; |
Callback
인게이지먼트 모듈 호출 중 전달 받는 콜백 데이터 처리방법에 대한 예제 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
// iOS:C2SModuleEngagement Start - (void)C2SModuleResult:(C2SModuleApi)api parameter:(NSDictionary *)arg error:(NSError *)error{ // public callback switch(api){ case C2SModuleApi_EngagementStart: NSDictionary* dict = arg[@"engagementArg"]; if(dict != nil){ // Engagement에서 콜백 전달받음 NSString* type = dict[@"type"]; NSDictionary* paramDict = arg[@"params"]; } Break; } } // iOS:C2SModuleSns Login - (void)C2SModuleResult:(C2SModuleApi)api parameter:(NSDictionary *)arg error:(NSError *)error{ // public callback switch(api){ case C2SModuleApi_SnsLogin: NSDictionary* dict = arg[@"engagementArg"]; if(dict != nil){ // Engagement에서 콜백 전달받음 NSString* type = dict[@"type"]; NSDictionary* paramDict = arg[@"params"]; } Break; } } // iOS:C2SModuleSns Show - (void)C2SModuleResult:(C2SModuleApi)api parameter:(NSDictionary *)arg error:(NSError *)error{ // public callback switch(api){ case C2SModuleApi_SnsShow: NSDictionary* dict = arg[@"engagementArg"]; if(dict != nil){ // Engagement에서 콜백 전달받음 NSString* type = dict[@"type"]; NSDictionary* paramDict = arg[@"params"]; } Break; } } // iOS:C2SModulePromotion Show - (void)C2SModuleResult:(C2SModuleApi)api parameter:(NSDictionary *)arg error:(NSError *)error{ // public callback switch(api){ case C2SModuleApi_PromotionShow: NSDictionary* dict = arg[@"engagementArg"]; if(dict != nil){ // Engagement에서 콜백 전달받음 NSString* type = dict[@"type"]; NSDictionary* paramDict = arg[@"params"]; } Break; } } // iOS:C2SModuleEngagement ConsumeCoupon - (void)C2SModuleResult:(C2SModuleApi)api parameter:(NSDictionary *)arg error:(NSError *)error{ // public callback switch(api){ case C2SModuleApi_EngagementConsumeCoupon: NSDictionary* dict = arg[@"engagementArg"]; if(dict != nil){ // Engagement에서 콜백 전달받음 NSString* type = dict[@"type"]; NSDictionary* paramDict = arg[@"params"]; } Break; } } // iOS:C2SModuleSns Message - (void)C2SModuleResult:(C2SModuleApi)api parameter:(NSDictionary *)arg error:(NSError *)error{ // public callback switch(api){ case C2SModuleApi_SnsMessage: NSDictionary* dict = arg[@"engagementArg"]; if(dict != nil){ // Engagement에서 콜백 전달받음 NSString* type = dict[@"type"]; NSDictionary* paramDict = arg[@"params"]; } Break; } } // iOS:C2SModuleEngagement GameScheme - (void)C2SModuleResult:(C2SModuleApi)api parameter:(NSDictionary *)arg error:(NSError *)error{ // public callback switch(api){ case C2SModuleApi_EngagementGameScheme: NSString* scheme = dict[@"scheme"]; NSString* host = dict[@"host"]; NSString* eventstr = dict[@"event"]; NSDictionary* query = dict[@"query"]; if(query != null){ // query값 파싱 } Break; } } // iOS:C2SModuleEngagement End - (void)C2SModuleResult:(C2SModuleApi)api parameter:(NSDictionary *)arg error:(NSError *)error{ // public callback switch(api){ case C2SModuleApi_EngagementEnd: NSDictionary* dict = arg[@"engagementArg"]; if(dict != nil){ // Engagement에서 콜백 전달받음 NSString* type = dict[@"type"]; NSDictionary* paramDict = arg[@"params"]; } Break; } } |
– 쿠폰 소모 처리를 수행한다.
1 2 3 4 5 6 7 8 9 10 11 12 |
/* 1.10.0 추가 */ /* 쿠폰 소모 처리를 수행 */ Json::Value arg; arg ["couponId"] = "couponid"; arg ["language"] = "ko"; // 1.12.0미만 : language 키 설정 필요, 1.12.0이상 : language 키 사용하지 않음. arg ["additionalInfo"] = ""; Json::StyledWriter writer; std::string strJSON = writer.write(arg); C2SModule_Cocos2dx::C2SModuleError error; if( ::C2SModuleEngagement_ConsumeCoupon( strJSON.c_str(), &error ) == false ) { CCLog( "====>>>> Engagement_ConsumeCoupon error (%s)", error.get()->GetMessage() ); } |
C2SModule_Cocos2dx::C2SModuleCompletionHandler* completionHandler = NULL);
– Immediate 값이 false로 저장된 이벤트들을 불러온다. (1.10.x)
1 2 3 4 5 6 7 8 9 |
/* 1.10.0 추가 */ /* 저장된 이벤트 호출 */ Json::Value arg; Json::StyledWriter writer; std::string strJSON = writer.write(arg); C2SModule_Cocos2dx::C2SModuleError error; if( ::C2SModuleEngagement_GetEvents( strJSON.c_str(), &error ) == false ) { CCLog( "====>>>> Engagement_GetEvents error (%s)", error.get()->GetMessage() ); } |
C2SModule_Cocos2dx::C2SModuleCompletionHandler* completionHandler = NULL);
– Engagement를 사용할 준비가 되었음을 모듈에 전달한다. (1.11.0+)
이전에 전달되었던 스키마의 기능들이 동작하며, 이후로 전달되는 스키마는 즉시 수행된다.
(* Interwork는 반드시 SetReady를 호출한 이후에 전달되어야 한다.)
1 2 3 4 5 6 7 8 |
/* 1.11.0 추가 */ Json::Value arg; Json::StyledWriter writer; std::string strJSON = writer.write(arg); C2SModule_Cocos2dx::C2SModuleError error; if( ::C2SModuleEngagement_SetReady( strJSON.c_str(), &error ) == false ) { CCLog( "====>>>> Engagement_SetReady error (%s)", error.get()->GetMessage() ); } |
Callback
인게이지먼트 모듈 호출 중 전달 받는 콜백 데이터 처리방법에 대한 예제 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
// Cocos2d-x:C2SModuleEngagement_Start void DealCallback::ResultDelegate(C2SModuleApi api, const char* json, C2SModuleErrorCode code, const* message){ switch(api){ case C2SModuleApi_EngagementStart: Json::Value arg; Json::Reader reader; if(reader.parse(json,arg) == false) {return ;} if(arg.isMember("engagementArg") { // Engagement에서 콜백 전달받음 Json::Value engageArg = arg["engagementArg"]; std::string type = engageArg.get("type","").asString(); Json::Value paramsArg = engageArg["params"]; } break; } } // Cocos2d-x:C2SModuleSns_Login void DealCallback::ResultDelegate(C2SModuleApi api, const char* json, C2SModuleErrorCode code, const* message){ switch(api){ case C2SModuleApi_SnsLogin: Json::Value arg; Json::Reader reader; if(reader.parse(json,arg) == false) {return ;} if(arg.isMember("engagementArg") { // Engagement에서 콜백 전달받음 Json::Value engageArg = arg["engagementArg"]; std::string type = engageArg.get("type","").asString(); Json::Value paramsArg = engageArg["params"]; } break; } } // Cocos2d-x:C2SModuleSns_Show void DealCallback::ResultDelegate(C2SModuleApi api, const char* json, C2SModuleErrorCode code, const* message){ switch(api){ case C2SModuleApi_SnsShow: Json::Value arg; Json::Reader reader; if(reader.parse(json,arg) == false) {return ;} if(arg.isMember("engagementArg") { // Engagement에서 콜백 전달받음 Json::Value engageArg = arg["engagementArg"]; std::string type = engageArg.get("type","").asString(); Json::Value paramsArg = engageArg["params"]; } break; } } // Cocos2d-x:C2SModulePromotion_Show void DealCallback::ResultDelegate(C2SModuleApi api, const char* json, C2SModuleErrorCode code, const* message){ switch(api){ case C2SModuleApi_PromotionShow: Json::Value arg; Json::Reader reader; if(reader.parse(json,arg) == false) {return ;} if(arg.isMember("engagementArg") { // Engagement에서 콜백 전달받음 Json::Value engageArg = arg["engagementArg"]; std::string type = engageArg.get("type","").asString(); Json::Value paramsArg = engageArg["params"]; } break; } } // Cocos2d-x:C2SModuleEngagement_ConsumeCoupon void DealCallback::ResultDelegate(C2SModuleApi api, const char* json, C2SModuleErrorCode code, const* message){ switch(api){ case C2SModuleApi_EngagementConsumeCoupon: Json::Value arg; Json::Reader reader; if(reader.parse(json,arg) == false) {return ;} if(arg.isMember("engagementArg") { // Engagement에서 콜백 전달받음 Json::Value engageArg = arg["engagementArg"]; std::string type = engageArg.get("type","").asString(); Json::Value paramsArg = engageArg["params"]; } break; } } // Cocos2d-x:C2SModuleSns_Message void DealCallback::ResultDelegate(C2SModuleApi api, const char* json, C2SModuleErrorCode code, const* message){ switch(api){ case C2SModuleApi_SnsMessage: Json::Value arg; Json::Reader reader; if(reader.parse(json,arg) == false) {return ;} if(arg.isMember("engagementArg") { // Engagement에서 콜백 전달받음 Json::Value engageArg = arg["engagementArg"]; std::string type = engageArg.get("type","").asString(); Json::Value paramsArg = engageArg["params"]; } break; } } // Cocos2d-x:C2SModuleEngagement_GameScheme void DealCallback::ResultDelegate(C2SModuleApi api, const char* json, C2SModuleErrorCode code, const* message){ switch(api){ case C2SModuleApi_EngagementGameScheme: Json::Value arg; Json::Reader reader; if(reader.parse(json,arg) == false) {return ;} std::string scheme = arg.get("scheme","").asString(); std::string host = arg.get("host","").asString(); std::string eventstr = arg.get("event","").asString(); Json::Value query = arg["query"]; if(query != null){ // query값 파싱 } break; } } // Cocos2d-x:C2SModuleEngagement_End void DealCallback::ResultDelegate(C2SModuleApi api, const char* json, C2SModuleErrorCode code, const* message){ switch(api){ case C2SModuleApi_EngagementEnd: Json::Value arg; Json::Reader reader; if(reader.parse(json,arg) == false) {return ;} if(arg.isMember("engagementArg") { // Engagement에서 콜백 전달받음 Json::Value engageArg = arg["engagementArg"]; std::string type = engageArg.get("type","").asString(); Json::Value paramsArg = engageArg["params"]; } break; } } |