[Android-NDK] NativeActivity 에서 다른 Shared Library 추가시 앱이 구동 안되는 문제 - 해결 -

Android NDK (Native Development Kit) 을 이용해서 개발하고 있습니다. NativeActivity 를 이용하고 있습니다. 그런데 작지만 해결하기 어려운 버그가 있습니다. 

NativeActivity 는 Java 의 Activity 의 일종인데 JNI 를 이용한 Native C/C++ Entry Point 를 쓰레드 (Thread)를 이용해서 호출하는 부분을 잘 감싸서 NDK 를 이용해서 개발하고자 하는 사람들에게 편의를 제공할려는 목적으로 만들어 진것으로 보입니다. 특히나 게임 , 전화, 멀티미디어 용 어플리케이션을 개발하는 사람들은 필히 관심을 가져볼 만합니다. 

발생한 이슈는  제가 추천한 책에서 언급된 소스에 다른 모듈을 붙일려고 하는 순간에 발생했습니다. 참고로 만들어본 Android.mk 파일입니다. 



LOCAL_PATH := $(call my-dir)
TOP_ROOT_PATH := $(LOCAL_PATH)

include $(call all-subdir-makefiles) 
# 이 하위 Android.mk 에서 Shared Library 를 만들어 줍니다. 
# 그 라이브러리 이름을  codec 이라고 (예를 들어서) 해줍니다. 

include $(CLEAR_VARS)

LOCAL_PATH = $(TOP_ROOT_PATH)

LS_CPPP=$(subst $(1)/, ,$(wildcard $(1)/*.cpp ))

LOCAL_MODULE := game 
LOCAL_SRC_FILES := $(call LS_CPPP,$(LOCAL_PATH))

LOCAL_CFLAGS += -D GL_GLEXT_PROTOTYPES

LOCAL_LDLIBS := -landroid -llog -lEGL -lGLESv1_CM
LOCAL_STATIC_LIBRARIES := android_native_app_glue png
LOCAL_SHARED_LIBRARIES := codec                          
# 이 부분이 문제의 그 부분입니다. 

include $(BUILD_SHARED_LIBRARY)

$(call import-module, android/native_app_glue)
$(call import-module, libpng)


이게 대체 뭐지? 라고 생각하시는 분들은 제가 곧 'NDK 프로그래밍 따라하기' 포스트 한 두개를 올릴테니 그 때까지 이 부분을 보실 필요는 없습니다. 

위의 Android.mk 를 이용해서 컴파일을 하면 libgame.so 가 만들어 집니다. 책에서 나와 있는 그대로 만들어 집니다. 그러나 codec 이라는 (libcodec.so)를 이용해야 하는 필요가 생겨서 따로 만들어 줘서 프로젝트에 포함시켜 주면 실행이 안되고 에러가 발생합니다. 

잘 된 캡슐화의 문제점 중의 한가지가 난감한 에러가 발생하면 해결하기 어렵다는 점입니다. 구글링도 해보고 여러가지 독립적인 테스트를 해 본 결과 전혀 엉뚱한 작업을 진행중에 해결이 됐습니다. 100% 확신을 한 바는 아니지만 NativeActivity 가 결국 Java 클래스 이고 내부적으로는 결국 JNI 를 이용해서 Library 를 불러오는데, 정해진 방법으로만 호출하기 때문에 (위의 예제의 경우에는 libgame.so ) 다른 라이브러리를 호출을 못하기 때문에 발생하는 것 같습니다. 따라서 해결해 주기 위해서는 몇가지 수동으로 처리해 줘야 합니다. 

$ cd $PROJECT_ROOT
$ cd src/com/comjuck/game     (없으면 만들어 주셔야 합니다)
$ emacs NativeActivity

package com.comjuck.game;

import android.app.NativeActivity;
import android.os.Bundle;

public class GameActivity extends NativeActivity {

	static {
		System.loadLibrary("codec");
	}


  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
  }
  
}


GameActivity 를 만들어주고 NativeActivity 에서 상속을 받습니다. (물론 package 경로에 맞춰주는 것을 잊어주시면 안됩니다) , 그리고 위에서 표기한 대로 추가해 준 라이브러리를 직접 불러줍니다. 
그리고 AndroidManifest.xml 을 열어서 추가해 준 Activity 를 android.app.NativeActivity 대신 지정해 줍니다. 

$ cd $PROJECT_ROOT
$ emacs AndroidManifest.xml 
 

    <activity android:name="PhoneActivity"
                  android:label="@string/app_name">


이제는 문제 없이 앱이 실행되는군요. 

ps. 이걸 알아내기 위해서 4시간을 소모했습니다. ㅜ.ㅜ