Android Studio에서 JNI 빌드하기

우선,

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 부분 유의)

Leave a Comment

Your email address will not be published. Required fields are marked *