이 글을 작성했을 때보다 더 나중에 나온
안드로이드 스튜디오 2.2.2로 빌드하는 방법을 새로 작성하였습니다.
http://tibyte.kr/272
개발환경
Windows 10 64bit
Android Studio 1.5.1
jdk 1.8.0_71
target sdk version : 23
min sdk version : 15
기본 설정
- JDK 설치
- JDK 환경변수 (PATH)설정
- 안드로이드 스튜디오 설치
- NDK 다운로드
안드로이드 스튜디오에서 새 프로젝트를 만든다.
이 포스트에서는 프로젝트 이름을 ndktest로 정한다.
프로젝트 창에서는 Project Files를 선택해야 디렉터리 경로를 보기 쉽다.
File - Project Structure - Android NDK location 에서 다운받은 NDK 경로를 지정한다.
안드로이드 스튜디오를 통해 설치했다면 자동지정된다.
java 어플리케이션 만들기
안드로이드에서 빈 액티비티로 프로젝트를 만들면 TextView하나가 나와있는데,
C/C++ 네이티브 코드에서 보낸 메시지를 여기에 띄워 본다.
프로젝트 디렉터리를 기준으로
app/src/main/res/layout/content_main.xml
파일에 있는 TextView에게 id를 붙여준다.
android:id="@+id/textView" |
MainActivity.java 파일에 네이티브 라이브러리를 로드하는 구분과 메서드 선언을 적는다.
static { System.loadLibrary("ndktest"); } public native String getStringFromNative(); |
onCreate 메서드 내에서는 위에서 선언한 함수를 호출하여 텍스트뷰에 쓴다.
TextView view = (TextView)findViewById(R.id.textView); view.setText(getStringFromNative()); |
Build - Make Project로 빌드한다.
javah로 JNI용 C++ 헤더파일 제작
이 작업을 하기 전에 먼저 환경변수에 ANDROID_HOME이라는 값을 안드로이드 SDK 경로로 지정해 두면 편하다.
Windows 환경에서 안드로이드 스튜디오를 통해 안드로이드 SDK를 설치했을 때 기본 경로는 C:\Users\유저이름\AppData\Local\Android\sdk 이다.
프로젝트 디렉터리를 기준으로
app/src/main
으로 이동하여 커맨드창을 열고 다음과 같이 javah를 실행한다. (Windows 기준)
도메인 경로와 프로젝트 이름(여기서는 ndktest)는 프로젝트에 맞게 설정.
$ javah -d jni -classpath %ANDROID_HOME%/platforms/android-23/android.jar;%ANDROID_HOME%/extras/android/support/v7/appcompat/libs/android-support-v7-appcompat.jar;%ANDROID_HOME%/extras/android/support/v4/android-support-v4.jar;../../build/intermediates/classes/debug 도메인.경로.ndktest.MainActivity |
만약 ANDROID_HOME 경로의 extras/android 디렉터리에 support가 없다면
Tools - Android - SDK Manager - Appearance - System Settings - Android SDK - SDK Tools 로 들어가
Android Support Library 를 설치한다.
성공적으로 실행되었다면
app/src/main/jni 에 헤더파일(.h)이 생성된다.
C++ 네이티브 코드 작성
간단한 C++ 코드를 작성한다.
여기서 주의할 점은 위에서 생성한 헤더파일을 로드해야하고, 함수 이름도
Java_도메인_경로_프로젝트이름_Java클래스명_Java메서드명 형식으로 되어야 한다는 것이다.
JNIEXPORT jstring JNICALL Java_kr_tibyte_ndktest_MainActivity_getStringFromNative(JNIEnv *env, jobject obj)
아래 코드에 있는 도메인 (kr_tibyte)는 프로젝트에 맞게 고친다.
#include "kr_tibyte_ndktest_MainActivity.h" #include <string> #include <sstream>
using namespace std;
JNIEXPORT jstring JNICALL Java_kr_tibyte_ndktest_MainActivity_getStringFromNative(JNIEnv *env, jobject obj) {
stringstream ss; for(int i=1; i<=9; i++) { for (int j=1; j<=9; j++) { int n = i*j; ss << " "; if(n < 10) ss << "0"; ss << n; } ss << endl; }
string str = ss.str(); return env->NewStringUTF(str.c_str()); } |
makefile(*.mk) 설정
app/src/main/jni 안에 Android.mk를 만든다.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ndktest LOCAL_SRC_FILES := main.cpp LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY) |
LOCAL_MODULE은 생성될 네이티브 모듈의 이름,LOCAL_SRC_FILES는 모듈을 만드는 데 사용될 소스파일들의 목록이다.
app/src/main/jni 안에 Application.mk를 만든다.
APP_ABI := armeabi APP_STL := gnustl_static |
여기서는 컴파일을 위한 옵션 플래그들을 지정할 수 있다.
APP_STL을 지정하여 C++에서 STL 요소들을 사용할 수 있다.
APP_ABI는 ABI(Application Binary Interface)를 지정할 수 있는데 armeabi, armeabi-v7a, mips, x86등이 있으니 필요에 따라 설정한다.
gradle 설정
app/build.gradle을 수정한다.
apply plugin: 'com.android.application'
android { compileSdkVersion 23 buildToolsVersion "23.0.2"
defaultConfig { applicationId "kr.tibyte.ndktest" minSdkVersion 15 targetSdkVersion 23 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug { jniDebuggable true } }
sourceSets.main { //네이티브 라이브러리 경로 jniLibs.srcDir 'src/main/libs' //JNI소스 경로 jni.srcDirs = [] }
//안드로이드 스튜디오에서 Java 소스를 빌드할 때 buildNative task를 실행시킴 tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn buildNative }
//네이티브 소스 빌드 task buildNative(type: Exec, description: 'Compile JNI source via NDK') { def ndkDir = android.ndkDirectory commandLine "$ndkDir/ndk-build.cmd", 'NDK_DEBUG=1', '-C', file('src/main').absolutePath }
//네이티브 라이브러리 삭제 task cleanNative(type: Exec, description: 'Clean JNI object files') { def ndkDir = android.ndkDirectory commandLine "$ndkDir/ndk-build.cmd", '-C', file('src/main').absolutePath, 'clean' } clean.dependsOn 'cleanNative'
} dependencies { compile 'com.android.support:appcompat-v7:23.1.1' compile 'com.android.support:design:23.1.1' }
|
결과
이제 애플리케이션을 빌드하고 기기에서 실행시키면
C++ 코드에서 처리한 결과가 MainActivity의 TextView로 표시된다.
코드 모음
https://github.com/tibyte/practice/tree/master/android/ndktest
참조
https://stackoverflow.com/questions/21096819/jni-and-gradle-in-android-studio
http://stackoverflow.com/questions/21999829/how-do-i-read-properties-defined-in-local-properties-in-build-gradle
http://stackoverflow.com/questions/21096819/jni-and-gradle-in-android-studio
http://i5on9i.blogspot.kr/2015/02/android-studio-ndk-hello-world.html
https://www.davidlab.net/ko/tech/using-the-android-ndk-with-android-studio-part1/