[출처] : https://www.davidlab.net/ko/tech/using-the-android-ndk-with-android-studio-part1/
javah를 이용해서 c header 파일을 생성할때 다음과 같이 한다.
java source code의 최상위 폴더로 이동. 여기서는 project/app/src/main으로 이동하고 다음과 같이 사용한다.
javah -classpath ./java/ com.erato.example.examplendk.ExampleNDK
위에서 보면 classpath는 소스코드가 존재하는 폴더를 가리키고, 그 폴더 기준으로 클래스를 입력해준다.
따라서 폴더를 기준으로 com/erato/example/examplendk/ExampleNDK.java가 존재하므로, 클래스명은
com.erato.example.examplendk.ExampleNDK에 적어주면 된다.
========================================================================
아래 출처에서 제일 중요한 부분만 별도로 언급해보자.
1. gradle.properties
android.useDeprecatedNdk=true
위와 같이 꼭 추가해줘야 ndk-build가 적용된다.
2. app/build.gradle
아래 defaultConfig에 ndk 항목에 ldLibs는 추가해줘야 하는 라이브러를 직접 명시해줘야 한다.
이를테면 jni/Android.mk에서 android_log를 사용하는데, 이곳에 명시를 안하면 'undefined reference' 에러가 발생한다.
명심하자!
defaultConfig {
applicationId "com.erato.example.examplendk"
minSdkVersion 23
targetSdkVersion 24
versionCode 1
versionName "1.0"
ndk {
moduleName "libexamplendk"
ldLibs "log"
}
}
또한 아래 jniLibs의 경로는 지정하지 않으면, app에서 System.loadLibray("examplendk") 시에 라이브러리 못찾는다고 죽는다.
sourceSets.main {
jniLibs.srcDir 'src/main/libs'
jni.srcDirs = [] //disable automatic ndk-build call
}
==============================================================================
NDK는 C/C++과 같은 Native Code를 위한 언어를 이용하여 Android App의 일부분을 구현할 수 있도록 도와주는 Toolset입니다.
이것을 이용하면 개발자는 기존에 Embedded Linux에서 개발하던 방식과 유사하게 C/C++로 구현하여 Toolset으로 Build한 Native Library를 Java의 JNI를 이용하여 Java Code내에서 사용할 수 있게 됩니다.
기존의 Eclipse 기반의 ADT를 이용하는 경우에는 Eclipse의 CDT Plugin을 이용하여 IDE Level의 NDK 지원이 가능했지만, Android Studio의 경우에는 C/C++ Compile 및 Debugging을 제대로 지원하지 않기 때문에 NDK를 적용하는데 어려움이 있습니다.
이번 Post에서는 Android Studio에서 생성한 Project에 NDK로 Build한 Library를 사용하는 방법과 Build System에 통합하여 Build하는 방법 및 Debugging하는 방법에 대해서 알아보도록 하겠습니다.
1. NDK 설치
먼저, Android Studio와 Android SDK가 System에 설치되어야 있어야 합니다. Ubuntu의 경우에는 이 Post를 참고하여 설치하면 됩니다.
설치가 완료되었다면, System에 Android NDK를 설치하기 위해서 Android Developers에서 NDK를 Download합니다.
그리고 다음과 같이 입력하여 NDK를 설치합니다.
- Ubuntu의 경우:
- Mac OS X의 경우:
2. Project에 NDK 적용
이번 항목에서는 설치된 NDK를 Android Studio Project에서 사용하도록 설정하는 방법에 대해서 예제와 함께 설명합니다.
이번 항목은 이해를 위하여 Step-by-Step으로 따라할 수 있도록 작성되었습니다. |
Android Studio 1.3 이상에서 새로운 NDK 지원을 사용할 수 있습니다. 하지만 아직 실험적인 상태이기 때문에 실제 개발에 사용하기에는 무리가 있습니다. (자세한 내용은Experimental Plugin User Guide 참조) 떄문에 이 Post에서는 지금까지 Android Studio에서 NDK를 사용하던 방식 그대로를 사용합니다. 추후 Release를 통해 정식으로 지원된다면 이 내용은 Update될 것입니다. |
2.1 Project 생성
먼저, 새로운 Project를 생성합니다. Create New Project Dialog에서 위와 같이 App Name에 NDKTest라고 입력하고 Domain은 상황에 맞게 입력한 후 Next를 누릅니다.
Target Devices는 Default로 두고 Next를 누릅니다.
Activity 선택에서는 Blank Activity를 선택하고 Next를 누릅니다.
Activity 설정에서는 Default로 두고 Finish를 눌러 Project 생성을 완료합니다.
2.2 Source Code 수정
이제 생성된 Project의 Source를 수정해 봅시다. app/src/main/res/layout/content_main.xml을 열어서 기본적으로 추가되어 있는 TextView를 다음과 같이 수정합니다.
그 다음, MainActivity.java를 열어서 다음과 같은 내용을 추가합니다.
위의 Code를 간단히 설명하면 다음과 같습니다.
- Line 2-4: NDK로 Build한 Native Library를 Load합니다. Argument로는 Library File Name에서 Prefix인 lib와 확장자를 뺀 것을 입력합니다. (libndktest.so ndktest)
- Line 6: Native Library에서 구현한 Method의 Interface를 native keyword로 선언합니다. 이렇게 선언된 Method는 실제로 구현되어 있지 않아도 Build가 가능합니다.
- Line 11-12: Activity 생성 시에 Layout에 정의된 TextView에 Native Method를 호출한 결과를 출력하는 Code입니다.
Source를 모두 수정했다면, Build > Make Project를 눌러 Source를 Build합니다.
2.3 JNI Code 생성
NDK는 Native Code 구현을 위해 Java의 JNI(Java Native Interface)를 사용합니다.
간단하게 말하면, NDK는 Java에서 지원하는 Native Code 호출 규약인 JNI를 이용해서 Native Code를 App에서 사용할 수 있도록 도와줍니다.
떄문에 Java Source에서 선언한 Native Method를 구현하기 위해서는 JNI를 위한 C/C++ Header를 생성하고, 생성된 Header에 선언된 Native Method에 해당하는 Interface를 C/C++ Code로 구현하면 됩니다.
먼저 Android Studio의 Terminal(Alt + F12)을 열고, Build된 Java Class를 이용하여 Header를 생성하기 위해서 다음과 같이 입력합니다.
javah 명령에서 유의할 것은 app/build.gradle에 정의되어 있는 targetSdkVersion에 맞는 경로를 -classpath에 추가해 주어야 합니다. 위의 경우는 API 23(Android 6.0)을 사용할 경우의 예입니다.
그리고 javah의 마지막 인자에 Package Name을 포함한 MainActivity class의 Full Name을 적어야 합니다.
생성이 제대로 되었다면 위의 그림과 같이 PROJECT_HOME/app/src/main/jni/fully_qualified_class_name.h가 생성됩니다.
이제 생성된 Header를 이용하여 Native Code를 구현해야 합니다. app/src/main/jni/main.cpp를 생성하고 다음과 같이 입력하고 저장합니다.
위의 구현은 다음과 같은 구조로 되어 있습니다.
- Line 1: javah로 생성된 Header를 Include합니다. Header 이름은 상황에 맞게 변경해야 합니다.
- Line 3: 생성된 Header에서 MainActivity.java에서 선언한 getStringFromNative()에 해당하는 Interface의 Prototype을 그대로 복사하여 입력하고 인자에 변수명을 추가합니다.
- Line 4: 실제 구현내용입니다. String을 생성하여 Return합니다.
JNI 구현에 대한 자세한 내용은 이 Post에서 다루지 않습니다. 좀 더 자세한 내용은 Oracle의 JNI Specification에서 확인할 수 있습니다. |
2.4 Android.mk 생성
Native Code까지 구현이 완료되었다면, Library로 Build하기 위해 Android.mk를 생성해야 합니다.
NDK에서는 Native Code의 Build를 위해서 GNU Make를 사용합니다. Android.mk는 Make를 위한 Makefile 형식으로 된 Build 설정 File로 Native Library를 Build할 때 사용됩니다.
app/src/main/jni/Android.mk를 생성하고 다음과 같이 입력합니다.
위의 내용을 간단히 설명하면 다음과 같습니다.
- Line 5: LOCAL_MODULE에는 생성될 Library의 이름을 입력합니다. 위에서는 MainActivity.java에서 loadLibrary()의 인자로 입력하였던 Library 이름인 ndktest가 사용되었습니다.
- Line 6: LOCAL_SRC_FILES에는 Build할 Source File을 입력합니다. 여러 개일 경우 Space로 구분하여 입력하면 됩니다. 위의 내용에서는 이전에 생성한 main.cpp를 Source로 지정하였습니다.
- Line 7: LOCAL_LDLIBS Library Link 시에 사용하는 ld 명령을 위한 Option을 지정합니다. 위의 경우는 Android의 Logcat을 사용하기 위한 Option이 추가되어 있습니다.
자세한 Android.mk의 사용법은 ANDROID_NDK_HOME/docs에 위치한 Documentation에서 확인할 수 있습니다. |
2.5 Application.mk 생성
Application.mk도 Android.mk와 마찬가지로 Native Library Build 시에 필요한 File로, Build 시에 Android App과 관련된 설정을 지정할 수 있습니다.
app/src/main/jni/Application.mk를 생성하고 다음과 같이 입력합니다.
위의 내용에서는 APP_ABI 변수에 Native Library Build를 위해 Target ABI(Application Binary Interface)를 설정합니다.
ABI는 Binary Level의 호환 Interface를 의미합니다. 이것은 CPU Type에 의존하며, NDK는 armeabi, x86, mips 등의 ABI를 지원합니다.
위와 같이 all로 입력할 경우 Android가 지원하는 모든 ABI를 위한 Native Library를 Build하게 됩니다.
자세한 Application.mk의 사용법은 ANDROID_NDK_HOME/docs에 위치한 Documentation에서 확인할 수 있습니다. |
2.6 Gradle 설정
NDK를 위한 Code를 모두 작성했으니 이제 Gradle Build System을 수정해 봅시다.
먼저 그에 앞서, Gradle에서 NDK에 포함된 명령들을 사용하기 위해서 System에 설치된 NDK의 경로를 입력해야 합니다.
File > Project Structure > SDK Location에서 Android NDK location에 System에 설치된 NDK의 경로를 입력합니다.
NDK의 경로는 PROJECT_HOME/local.properties에 저장됩니다. |
Android Studio 1.3 이상의 경우, Android Gradle Plugin에서 새로 지원하는 실험적인 NDK 지원 대신에 이전 Version에서 사용하던 방식을 사용하도록 설정해야 합니다.
설정을 위해서 gradle.properties에 다음과 같은 내용을 추가합니다.
그 다음, App을 Build할 때 NDK를 이용하여 Native Library도 같이 Build할 수 있도록 build.gradle을 수정해야 합니다.1 2
app/build.gradle에 다음과 같은 내용을 추가합니다.
build.gradle을 수정했다면 Sync Now를 눌러 동기화합니다.
2.7 Project Build 및 Test
이제 모든 작업이 끝났습니다. Android Studio에서 Run > Run을 실행하여 Project를 Build하고 Emulator 또는 Device에서 실행하여 Test합니다.
Native Library가 Build되었는지 확인하려면 위의 그림과 같이 Gradle Console Tool Window에 buildNative Task가 실행되었는 지 확인하면 됩니다.
App을 실행하면 위와 같이 TextView에 JNI Code에서 Return한 Text가 표시되는 것을 확인할 수 있습니다.
2.8 Source
지금까지 구현한 NDK Project의 Source를 얻으려면 다음과 같이 Terminal에서 입력합니다.
Clone 후에 Android Studio를 실행한 다음, Open an existing Android Studio project(또는 File > Open)을 눌러 android-examples/NDKTest를 Import하면 됩니다.
3. 마치면서…
이상으로 System에 NDK를 설치하고 Android Studio에서 NDK를 이용하여 Native Library를 Build하고 Java Source에서 사용하는 방법을 알아보았습니다.
이어지는 Part 2에서는 Android Studio에서 Native Library와 Java Code를 같이 Debugging하는 방법과 몇 가지 Tip을 공유하도록 하겠습니다.
'Programming > Android' 카테고리의 다른 글
UI 없이 service를 broadcast 수신 받아 띄위기 (0) | 2017.04.27 |
---|---|
empty activity 만들기 (0) | 2017.04.27 |
Android TIF 관련. (0) | 2016.07.12 |
안드로이드 jack 빌드 에러 (0) | 2016.07.04 |
이클립스에서 안드로이드 소스코드 연결해서 보기 (0) | 2011.09.01 |