Android SDK (Cocos2d-x)

1. 들어가며

이 문서는 Android용 SmartBeat를 Cocos2d-x에 도입하기 위한 순서를 기술했습니다.
동작이 검증된 Cocos2d-x(C/C++) 버전은 2.1.4, 2.1.5, 2.2, 2.2.3, 3.1.1, 3.2이고, Cocos2d-JS 버전은 3.7, 3.8, 3.13.1입니다.

이 SDK가 대응하고 있는 Cocos2d-x상의 언어는 C/C++ 및 JavaScript입니다. 동작 대상의 AndroidOS는 2.3 이후입니다.
※ 보통 Android판은 2.2이후이지만、2.2는 Java 뿐이기에 대상에서 제외했습니다.

2. Android Project에 SDK를 임포트하는 방법

Step1:라이브러리 임포트하기

아래에서 SmartBeat SDK를 다운로드하고 unzip하십시오.


다른 형식의 SDK는 여기 에서 다운로드하십시오.

  • Android Studio
  • Eclipse + ADT
[smartbeat-android-<version>.jar]을 [libcocos2dx]Project의 libs 폴더(cocos2d/cocos/platform/android/java/libs)에 복사합니다.
(libs폴더가 존재하지 않는 경우、src폴더와 같은 계층에 새로 작성합니다.)[libcocos2dx]의Project의build.gradle을 열어서, dependencies쪽에 아래의 내용을 추가함.

dependencies {
    compile fileTree(dir: '../java/libs', include: ['*.jar'])
}
[smartbeat-android-<version>.jar]을 [libcocos2dx]Project의 libs 폴더에 복사합니다.
(libs폴더가 존재하지 않는 경우、src폴더와 같은 계층에 새로 작성합니다.)coco2dx_and_1

Step2:Application클래스 작성과 API키 설정

Cocos2d-x에서 신규 Android AndroidProject를 작성시에 생성되는 <project-name>.java와 같은 계층에 Application클래스를 신규로 작성합니다.
Cocos2d-x에 샘플로 들어있는 SimpleGame의 경우에도、아래의 화면과 같이 SimpleGame.java와 같은 폴더에 둡니다. (MyApplication.java를 신규작성)

cocos2dx_and_2

추가한 MyApplication.java에 아래와 같이 구현합니다.

package org.cocos2dx.simplegame;

import com.smrtbeat.SmartBeat;

import android.app.Application;

public class MyApplication extends Application{
    public void onCreate() {
        SmartBeat.initAndStartSession(this, "API키");
    }
}

첫번째 패키지 명은 대상이 되는 App의 패키지 명, [API 키]는 콘솔로부터 Project를 신규 작성시에 발행되어진 키를 설정합니다.

Step3:AndroidManifest.xml의 변경

AndroidManifest.xml를 열고、application의 요소를 찾으면[android:name]의 속성이 없기에、아래와 같이 Step2에서 추가로 적은 클래스명을 적습니다.

cocos2dx_and_3

또한 Internet버전(android.permission.INTERNET)을 추가합니다. (이미 추가되어져 있는 경우에는 불필요)

cocos2dx_and_4

이것은 App안에서 발생된 Crash 데이터를 SmartBeat 서버에 보내기위해 최소한으로 필요한 권한입니다.

Step4:유저 카운트 수 중복방지 설정

SDK버전 1.12이후

유저 수의 집계에 광고ID를 사용하여 동일한 유저의 중복된 카운트를 방지합니다. 따라서 App의 재설치를 반복하더라도 불필요한 MAU(Monthly Active Users) 수의 증가를 막을 수 있습니다.

※ 중복된 유저의 카운트를 막는 설정을 유효화하는 것으로 오디언스 기능도 유효화 됩니다.
※ 이 기능은 Google Play services 4.0이후의 버전이 설치된 단말을 사용하는 유저의 카운트에만 유효합니다. (그 외의 유저는 기존대로 카운트됩니다.)

이 기능을 유효화하기 위해서는 아래의 순서대로 App에Google Play services를 넣어 주세요. 이 기능을 유효화하지 않을 경우에는 아래의 순서가 불필요합니다.

  • Android Studio
  • Eclipse + ADT
Google Repository의 다운로드

Android SDK Manager에서 Google Repository를 설치해 주세요.
install_google_repository

build.gradle의 편집

App의 모듈의 build.gradle를 열고 아래와 같이 dependencies에 play-services를 추가해 주세요. 추가한 play-services의 버전은 최신 버전(https://developers.google.com/android/guides/releases를 참조)을 지정해 주세요.

dependencies {
    compile fileTree(dir: '../java/libs', include: ['*.jar'])
    compile 'com.google.android.gms:play-services:8.4.0'
}

build.gradle편집 후에는 Android Studio툴바의 [Sync Project with Gradle Files] 버튼에서 편집결과를 프로젝트에 동기화해 주세요.

Google Play services 다운로드

Android SDK Manager에서 Google Play services를 설치해 주세요.
install_google_play_services

프로젝트의 추가

Eclipse에서 [File] -> [Import]로부터 [Existing Android Code into Workspace]를 선택、google-play-services_lib를 프로젝트에 임포트해주세요. google-play-services_lib는 Android SDK의 설치 폴더 바로 아래의 폴더에 있습니다.

<android-sdk>/extras/google/google_play_services/libproject/google-play-services_lib

「Copy projects into workspace」의 체크는 ON으로 해 주세요.
import_google_play_services

라이브러리의 추가

App의 프로젝트의 프로퍼티를 열고 [Android]설정의 [Library]항목에 있는 [Add...]버튼을 클릭하여 google-play-services_lib를 추가해 주세요.
library_google_play_services

manifest파일의 편집

App의 manifest파일을 열고 <application>요소에 아래의 내용을 추가해 주세요.

<meta-data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />

Step5:onResume, onPause의 등록(Android4.0보다 이전(API레벨 13이전)도 대상으로 하는 경우에만)

각 Activity의 onResume()、onPause()에 아래의 코드를 추가해 주세요.

import com.smrtbeat.SmartBeat;

@Override
protected void onResume(){
    super.onResume();
    SmartBeat.notifyOnResume(this);
    //your code
}

@Override
protected void onPause(){
    super.onPause();
    SmartBeat.notifyOnPause(this);
    //your code
}

Cocos2d-x에서는 Cocos2dxActivity를 계승한 클래스가 하나 존재하므로 그곳에 구현해 주세요.(SimpleGame의 경우에는 SimpleGame.java)

cocos2dx_and_5

Step6:Proguard의 설정(Proguard 유효시에만)

Proguard를 유효로 할 경우 Proguard의 설정에 아래를 추가해 주세요.

-dontwarn com.smrtbeat.**
-keep class com.smrtbeat.** { *; }

일반적으로는 프로젝트의 루트에 있는 proguard-project.txt 또는 proguard-rules.pro를 편집해 주세요.

Step4의 유저 카운트 중복방지설정을 유효화한 경우에는 아래의 설정을 추가해 주세요.

-dontwarn com.google.android.gms.**

3. Cocos2d-JS에러 취득(SDK버전 1.17이후)

SDK버전 1.17이후

아래의 순서대로 JavaScript바인딩을 유효화 하여, Cocos2d-JS의 JavaScript쪽 에러를 취득할 수 있습니다.
※ 2장의 내용에 따라 프로젝트에 SDK를 도입한 후, 아래의 순서를 따라해 주세요.
※ JavaScript에러 취득은 Cocos2d-x v3.7이상에서 대응합니다.
※ JavaScript를 사용하지 않은 앱은 아래의 순서가 불필요합니다.

SmartBeat JavaScript 바인딩 라이브러리 복사

프로젝트 폴더의 frameworks/cocos2d-x/external 아래에 smartbeat 폴더를 복사합니다.

<프로젝트>
└ frameworks
  └ cocos2d-x
    └ external
      └ smartbeat
        ├ include
        │ └ SmartBeatJSBinding.h
        └ prebuilt
          └ android
            ├ armeabi
            │ └ libSmartBeatJSBinding.a
            
            └ Android.mk

빌드 설정을 변경

프로젝트 폴더의 frameworks/runtime-src/proj.android/jni/Android.mk를 열어 LOCAL_STATIC_LIBRARIES와 import-module을 추가합니다.

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := cocos2djs_shared
LOCAL_MODULE_FILENAME := libcocos2djs
LOCAL_SRC_FILES := hellojavascript/main.cpp \
                   ../../Classes/AppDelegate.cpp
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes
LOCAL_STATIC_LIBRARIES := cocos2d_js_static \
                          SmartBeatJSBinding #이 부분을 추가
LOCAL_EXPORT_CFLAGS := -DCOCOS2D_DEBUG=2 -DCOCOS2D_JAVASCRIPT
include $(BUILD_SHARED_LIBRARY)
$(call import-module, scripting/js-bindings/proj.android)
$(call import-module, external/smartbeat/prebuilt/android) #이 부분을 추가

SmartBeat JavaScript 바인딩 등록

프로젝트 폴더의 frameworks/runtime-src/Classes/AppDelegate.cpp를 열고, 아래의 include문을 추가합니다.

#include <SmartBeatJSBinding.h>

AppDelegate::applicationDidFinishLaunching()안에 sc->start()를 호출하기 전에 아래의 1행을 추가합니다.

bool AppDelegate::applicationDidFinishLaunching()
{
    ...
    sc->addRegisterCallback(...);
    sc->addRegisterCallback(...);
    ...
    sc->addRegisterCallback(SmartBeat::registerSmartBeatJSBinding); //이 부분을 추가
    sc->start();
    ...
}

4. 옵션 기능

4.1 화면캡쳐 기능(OpenGL ES)

이 기능을 유효화 하면 OpenGL ES에서 그린 화면의 캡쳐 기능을 유효화 할 수 있습니다.
SDK에서는 App 표시중의 최신 화면을 정기적으로 캡쳐하고, Crash 발생 시 최신 1장을
SmartBeat서버에 보냅니다."
※1 본 기능은 Android4.0 이상의 기능입니다. (4.0미만의 경우에는 구현상에 문제는 없지만, 기능은 동작하지 않습니다.)
※2 기능은 OpenGL ES 2.0 이상을 이용할 경우에만 기능합니다. (1.x를 이용할 경우에는 구현상에 문제는 없지만 동작하지 않습니다.)
※3 본 기능은 Whitelist에 등록된 플랫폼에서만 동작합니다. 제6장 참조

유효화 방법

본 기능을 유효로 하면 다음에 기술하는 대로 3가지의 API 호출을 구현할 필요가 있습니다.

OpenGL ES 버젼 설정

Cocos2dxRenderer.java을 열고、onSurfaceCreated(final GL10 pGL10, final EGLConfig pEGLConfig)의 함수에 아래와 같이 추가해 주세요."
첫 번째 파라미터는 Cocos2dxGLSurfaceView.java의 setEGLContextClientVersion에 보내지는 값과 동일한 값을 설정해 주세요."
두 번째 파라미터는 StencilBuffer의 이용 유무를 설정해 주세요.Cocos2d-x의 CCClippingNode/ClippingNode를 이용할 경우에는 true입니다. 또한, true가 설정 되어진 경우 화면 캡쳐는 Android4.3이후에만 유효가 됩니다."

또한 동일한 파일에 아래의 import문도 추가해 주세요.

import com.smrtbeat.SmartBeat;

<2.x의 경우>
Cocos2dxRender.java의 패스는 [/cocos2dx/platform/android/java/src/org/cocos2dx/lib/Cocos2dxRenderer.java]입니다.
<3.x의 경우>
Cocos2dxRender.java의 패스는 [/cocos/platform/android/java/src/org/cocos2dx/lib/Cocos2dxRenderer.java]입니다.

OpenGL드로잉 전 후에서 API의 호출

Cocos2dxRenderer.java를 열고, onDrawFrame(final GL10 gl)에 아래와 같이 Cocos2dxRenderer.nativeRender()를 끼워 넣는 것으로、
구현을 추가해 주세요.
<2.x의 경우>
Cocos2dxRender.java의 패스는 [/cocos2dx/platform/android/java/src/org/cocos2dx/lib/Cocos2dxRenderer.java]입니다.
<3.x의 경우>
Cocos2dxRender.java의 패스는 [/cocos/platform/android/java/src/org/cocos2dx/lib/Cocos2dxRenderer.java]입니다.

cocos2dx_and_7

추가 API

또한 임의의 디바이스를 whitelist에 추가 할 경우、아래의 API를 이용해서 추가 가능합니다.

SmartBeat.whiteListModelForOpenGLES(모델 명);

[모델 명]은 Android의 API(Build.MODEL)로부터 취득 된 값을 설정할 수 있습니다.
whitelist에 추가된 경우에도 초기화에 실패했을 경우나 Android의 OS버젼이 서포트 되지 않는 경우 등에는 동작하지 않습니다.
정상적으로 동작이 개시 되었는지 아닌지에 대해서는 beginOnDrawFrame()의 리턴 값으로 확인할 수 있습니다.

4.2 로그 출력

SDK버전 1.16이후

단말 로그에 출력하지 않고, 로그를 수집할 수 있습니다.
※ 64KB 미만일 경우 최대 500행, 그 외의 경우에는 64KB까지 로그를 취득합니다.
※ 4.3장의 LogCat출력 기능을 유효화 한 경우, 이 기능에 의한 로그는 크래시 데이터에 포함되지 않고, LogCat의 로그만 크래시 데이터에 포함됩니다.

유효화 방법

아래의 API호출을 실현하면 로그를 보존할 수 있습니다.

■ Java
SmartBeat.log("message");
■ C/C++

NDK(C/C++)로부터 로그 출력을 할 경우에는 아래와 같이 함수를 준비하여 JNI 기능을 사용해 위의 API를 호출해 주세요. SDK에는 아래가 구현된 cpp파일이 포함되어 있습니다.

void SmartBeat_log(JNIEnv* env, const char* msg)
{
    jclass cls = env->FindClass("com/smrtbeat/SmartBeat");
    if (cls == NULL)
        return;
    jmethodID method = env->GetStaticMethodID(cls, "log", "(Ljava/lang/String;)V");
    if (method == NULL) {
        env->DeleteLocalRef(cls);
        return;
    }
    jstring str = env->NewStringUTF(msg);
    if (str == NULL) {
        env->DeleteLocalRef(cls);
        return;
    }
    env->CallStaticVoidMethod(cls, method, str);
    env->DeleteLocalRef(str);
    env->DeleteLocalRef(cls);
}
■ JavaScript
SmartBeat.log('message');

4.3 LogCat 출력

LogCat의 출력을 Crash 데이터에 포함시킬 경우에는 LogCat 출력기능을 유효로 해 주세요.
※ 제 2장 Step2에서 동작한 Application클래스에 구현해 주세요.
※ 64KB 미만일 경우에는 최대 500행, 그 외의 경우에는 64KB까지 최신 로그를 취득합니다.
※ 이 기능을 유효화 한 경우, 4.2장의 로그 출력API에 의한 로그는 크래시 데이터에 포함되지 않고, LogCat로그만 크래시 데이터에 포함됩니다.

유효화 방법
■ Java
SmartBeat.enableLogCat();

또한 아래와 같이 폴더를 파라미터로 주면 필터 된 로그만 취득할 수 있습니다.

SmartBeat.enableLogCat(“*:W”);

필터에 관한 상세내용은 Android 사이트를 참조해 주세요.
http://developer.android.com/tools/debugging/debugging-log.html#filteringOutput

또한 Android4.1보다 전(API레벨 15이전)에 있어서는 LogCat를 출력하기 위해 아래의 Permission이 필요합니다.
Android4.1 이후에는 Permission의 설정은 불필요 하지만 자신의 App이 출력한 Log만 취득할 수 있습니다.

<uses-permission android:name="android.permission.READ_LOGS"/>
■ JavaScript

JavaScript에서 해당하는 함수는 없습니다.

4.4 유저ID 설정

대상의 App이 관리하는 유저를 식별할 ID가 이미 있는경우、그것을 설정할 수 있습니다.
설정된 유저ID는 Crash와 함께 SmartBeat에 보내집니다. 어떤 유저에서 Crash가 발생했는지는 관리콘솔상에서 확인할 수 있습니다.

유효화 방법

아래의 API호출을 구현하여 설정 가능합니다.

■ Java
SmartBeat.setUserId("user001");
■ JavaScript
SmartBeat.setUserId('user001');

4.5 확장 정보

Crash정보에 확장정보를 부여할 수 있습니다. App에 따라서는 유저가 설정한 정보와 App 안에 보존된 정보가 Crash해석에 도움이 됩니다.

유효화 방법

아래의 API호출을 구현하면 임의의 키명과 값을 세트로 Crash 데이터와 함께 보존할 수 있습니다.
값을 변경하고 싶은 경우는 동일한 키명으로 추가하면, 새로운 값으로 덮어집니다.

■ Java
SmartBeat.addExtraData("key1", "value1");
SmartBeat.addExtraData("area", "Tokyo");

또한 확장정보를 HasMap을 사용해서 복수로 동시에 설정할 수 있습니다.

HashMap<String, String> map = new HashMap<String, String>();
map.put("key1", "value1");
map.put("area", "Tokyo");
SmartBeat.addExtraData(map);
■ JavaScript
SmartBeat.addExtraData('key1', 'value1');
SmartBeat.addExtraData('area', 'Tokyo');

4.6 breadcrumb기능

임의의 포인트에서 breadcrumb을 남기면 에러 발생까지의 유저가 행한 조작과 화면이동 등을 수집할 수 있습니다.

유효화 방법

breadcrumb남길(기록을 남기고 싶은)장소에서 아래의 API를 호출해 주세요.
breadcrumb은 가장 마지막에 기록된 것부터 최대 16개까지 보존됩니다.
예를들면,[맵 화면] → [게임 화면] → [설정화면]등과 키가 되는 화면 이동 시에 남길 경우, 에러 직전에 유저가 어떻게 화면을 이동했는지를 알 수 있습니다.

■ Java
SmartBeat.leaveBreadcrumbs("game scene 1");
■ JavaScript
SmartBeat.leaveBreadcrumb('game scene 1');

4.7 에러 수집을 유효화・무효화 변경

SDK버전 1.6이후

초기상태를 에러 수집 무효화로하고, 도중에 에러 수집을 유효화로 하고 싶은 경우에 이용할 수 있습니다.

유효화 방법

Ste3:API키 설정에서 기술한 API대신에 아래의 API를 기동시에 유효화하거나 무효화 하는 설정을 해 주세요.

public class MyApplication extends Application {
    @Override
    public void onCreate () {
        boolean enable = false; //무효화한 상태로 기동할 경우에는 false
        SmartBeat.initAndStartSession(this, "API키", enable);
    }
}

그 다음, 유효로 하고 싶은 경우에는 임의이 장소에서 아래의 코드를 호출해 주세요. 호출된 이후에 발생한 에러부터 수집됩니다.
덧붙여, 유효화・무효화 설정은 매번 기동시에 initAndStartSession(Application app, String appKey, boolean enabled)에서 설정해 주세요.

■ Java

유효화

SmartBeat.enable();

무효화

SmartBeat.disable();

상태 취득

boolean enabled = SmartBeat.isEnabled();
■ JavaScript

유효화

SmartBeat.enable();

무효화

SmartBeat.disable();

상태 취득

var enabled = SmartBeat.isEnabled();

4.8 Catch한 JavaScript에러 보존

SDK버전 1.17이후

Cocos2d-JS에서 앱이 Catch한 JavaScript에러를 기록할 수 있습니다.

유효화 방법
try {
    throw new Error();
} catch (e) {
    SmartBeat.logException(e);
}

4.9 심볼파일 자동 업로드

[.so Upload script]또는[.so Upload Jenkins plugin]을 빌드환경에 적용함으로써 매번 빌드를 작성할때 자동으로C/C++의 심볼파일을 업로드 하는게 가능합니다.

자세한 내용은, 각각 제공되는 스크립트 안의 readme 파일을 확인 해 주세요.

업로드 대상

업로드 대상 폴더는 어플리케이션의 Android프로젝트의libs폴더를 지정해 주세요.

4.10 오디언스 기능

유저 식별자로서 Advertising ID for Android 또는 IDFA for iOS를 사용하여
애플리케이션을 이용하는 유저의 남여비와 연령분포를 확인할 수 있습니다.

중복된 유저의 카운트를 막는 설정을 유효화하는 것으로 오디언스 기능도 유효화 됩니다.
중복된 유저의 카운트를 막는 설정에 대해서는 여기를 참조해 주세요.

5. 그 외 Permission

SmartBeat는 Crash 로그 수집시에 해석에 필요한 단말의 상태 등 주변 정보도 같이 기록합니다.
그러한 정보 중에는 Permission의 부여가 필요한 것도 있습니다. SmartBeat는 권한이 없어
정보를 취득하지 못했을 경우 "no permission"이라고 기록하지만 Permission을 부여하면 아래의 정보를 취득할 수 있습니다.

Permission명 취득가능 정보
android.permission.ACCESS_NETWORK_STATE NW접속상태

6. 리소스 소비

SDK도입에 따른 리소스 소비량 계측 결과를 아래에 표시했습니다.

단말 항목 SDK도입 시 기본 화면
캡쳐 유효
OpenGL ES화면
캡쳐 유효
Nexus7 (2012)
Android 4.4.2
메모리 소비량
CPU 부하
약 1.7MB 증가
증감 없음
약 4.3MB 증가
평균 약 6.4% 증가
약 5.3MB 증가
평균 약 4.4% 증가
Xperia AX
Android 4.1.2
메모리 소비량
CPU 부하
약 0.6MB 증가
증감 없음
약 5.0MB 증가
평균 약 3.0% 증가
약 5.9MB 증가
평균 약 4.1% 증가
Xperia Ray
Android 2.3.4
메모리 소비량
CPU 부하
약 1.1MB 증가
증감 없음
약 3.4MB 증가
평균 약 9.0% 증가
지원 없음

※ 화면캡쳐를 유효화 한 경우에는 화면의 화소수에 따라서 메모리 소비량이 증가
※ 화면캡쳐를 유효화 한 경우에는 화면 취득, 인코드 처리, 보존 처리가 들어가기에 CPU 부하가 증가

7. OpenGL ES화면캡쳐대상 단말

OpenGL ES화면캡쳐 기능을 지원 대상으로 기술합니다.

디바이스 명 Build.MODEL 검증 OS
버젼
SDK
버젼
NEXUS 5 Nexus 5 4.4 1.8 -
AQUOS PAD SH-06F SH-06F 4.4.2 1.8 -
AQUOS ZETA SH-04F SH-04F 4.4.2 1.8 -
Xperia ZL2 SOL25 SOL25 4.4.2 1.8 -
Xperia Z1 SOL23 SOL23 4.4.2 1.13 -
Xperia Z1 f SO-02F SO-02F 4.4.2 1.13 -
HTC J butterfly HTL23 HTL23 4.4.4 1.13 -
isai LGL22 4.4.2 1.13 -
Galaxy S5 SM-G900K 5.0 1.14 -

8. 개정이력

2014년 11월 20일 Cocos2d-x 3.x에서 실현방법의 주석을 추가로 기입

개정일 변경 사항
2014년 6월 2일 초판 발행
2014년 10월 23일 [4.2 화면캡쳐 기능]의 유효화 방법을 변경
[7. OpenGL ES화면캡쳐대상 단말]의 대상단말을 변경
2016년 1월 6일 [Step4:유저 카운트 중복방지 설정]을 추가(SDK버전 1.12이후)
[Step6:Proguard의 설정(Proguard를 유효화한 경우)]을 변경
2016년 3월 14일 [7. OpenGL ES화면캡쳐대상 단말]의 대상 단말을 변경
2016년 4월 8일 [7. OpenGL ES화면캡쳐대상 단말]의 대상 단말을 변경
2016년 4월 20일 [4.10 오디언스 기능]을 추가
2016년 11월 21일 [4.2 로그 출력]을 추가(SDK버전 1.16이후)
[4.3 LogCat출력]의 보충 설명을 추가
2016년 12월 22일 [1. 들어가며]에서 Cocos2d-x 동작 검증을 한 버전과 대응 언어를 갱신
[3. Cocos2d-JS의 에러 취득]를 추가(SDK버전 1.17이후)
[4. 옵션 기능]의 각장에 JavaScript의 API를 추가
[4.6 breadcrumb 기능]을 추가
[4.7 에러 수집 유효화・무효화 변경]을 추가
[4.8 Catch한 JavaScript에러 보존]을 추가
2017년 3월 29일 [2. Cocos2d-x(Android) Project에 SDK를 임포트 하는 방법]에Android Studio에서순서를 추가
[4.9 심볼파일 자동 업로드]을 추가