우선,
https://codelabs.developers.google.com/codelabs/android-studio-jni
여기에 속아선 안된다!
아직 Android Studio에서는 공식적으로 지원하지 않는 것으로 생각하는 게 정신건강에 좋다. 오로지 android ndk를 위해서만 작성한 코드만 있다면 상관없지만, 3rd party 라이브러리같은 걸 Android Studio에서 소스 컴파일 해서 사용하는 것은 불가능하다.
gradle 파일에 task를 추가하는 식으로 사용하는 것이 가장 효과적이다.
이 포스팅에서는 다음과 같은 방식을 추천한다.
디렉토리 구조
my_project/
my_module/
jni/
libs/
src/main/java/
Gradle 파일
my_module/build.gradle에 아래 내용을 추가해서 jni 코드가 있음을 Android Studio가 알아채지 못하도록 하자
android {
sourceSets {
main {
jni.srcDirs = []
jniLibs.srcDirs 'libs'
}
}
}
(참고로 기본적으로 Android Studio가 인식하는 경로는 my_project/my_module/src/main/jni
이다)
jniLibs는 .so 파일(소스코드가 아닌)이 있는 위치로 지정한 것이다. 소스코드는 Android Studio가 빌드할 필요가 없지만 .so 파일들은 패키지에 포함되어야하므로 경로를 지정해주어야한다.
이제 my_project/my_module/jni/
의 코드들을 my_project/my_module/libs/
로 빌드하는 task를 생성해야한다. (출처)
task ndkBuild(type: Exec) {
workingDir file(‘./‘)
commandLine getNdkBuildCmd()
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependOn ndkBuild
}
task cleanNative(type: Exec) {
workingDir file(‘./‘)
commandLine getNdkBuildCmd(), ‘clean'
}
clean.dependsOn cleanNative
마지막 줄에 clean task의 dependsOn을 지정하는 부분 유의
ndk-build
의 위치를 가져오는 함수를 선언해준다.
def getNdkDir() {
if (System.env.ANDROID_NDK_ROOT != null)
return System.env.ANDROID_NDK_ROOT
Properties properties = new Properties()
properties.load(project.rootProject.file(‘local.properties’).newDataInputStream())
def ndkdir = properties.getProperty(‘ndk.dir’, null)
if (ndkdir == null)
throw new GradleException(“NDK location not found. Define location with ndk.dir int the local.properties file or with an ANDROID_NDK_ROOT environment variable.”)
return ndkdir
}
def getNdkBuildCmd() {
def ndkbuild = getNdkDir() + “/ndk-build"
if (Os.isFamily(Os.FAMILY_WINDOWS))
ndkbuild += “.cmd"
return ndkbuild
}
위 내용들을 모두 적용한 모습은 아래와 같다.
import org.apache.tools.ant.taskdefs.condition.Os
android {
sourceSets {
main {
jni.srcDirs = []
jniLibs.srcDirs ‘libs'
}
}
task ndkBuild(type: Exec) {
workingDir file(‘./‘)
commandLine getNdkBuildCmd()
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependOn ndkBuild
}
task cleanNative(type: Exec) {
workingDir file(‘./‘)
commandLine getNdkBuildCmd(), ‘clean'
}
clean.dependsOn cleanNative
}
def getNdkDir() {
if (System.env.ANDROID_NDK_ROOT != null)
return System.env.ANDROID_NDK_ROOT
Properties properties = new Properties()
properties.load(project.rootProject.file(‘local.properties’).newDataInputStream())
def ndkdir = properties.getProperty(‘ndk.dir’, null)
if (ndkdir == null)
throw new GradleException(“NDK location not found. Define location with ndk.dir int the local.properties file or with an ANDROID_NDK_ROOT environment variable.”)
return ndkdir
}
def getNdkBuildCmd() {
def ndkbuild = getNdkDir() + “/ndk-build"
if (Os.isFamily(Os.FAMILY_WINDOWS))
ndkbuild += “.cmd"
return ndkbuild
}
(맨 윗줄 import 부분 유의)