ndk-build를 이용한

Native Code 빌드 및 사용방법

 

다음과 같은 이유로 Android App에서 Native Code(C/C++등)로 코드를 작성하여 사용해야 할 경우가 존재합니다.

  • 처리 속도 및 성능향상
  • C/C++로 만들어진 코드 재사용
  • Native Code로만 개발 가능한 기능 구현등

 

본 포스팅에서는 Android Studio에서 Native Code를 작성하고 빌드하는 방법에 대해 "최대한 많은 스크린 샷"을 통해 설명하고자 합니다.

작성 예제는 Native코드를 포함한 라이브러리(ndklib)와 이 라이브러리를 사용하는 app(ndklibdemo)으로 모듈을를 구분하여 작성 하도록 하겠습니다.

 

프로젝트 및 라이브러리 생성

1. 프로젝트 생성

프로젝트 타입을 'Empty Activity'로 선택합니다.

 

적당한 프로젝트 이름을 지정합니다. "ndklibdemo"로 설정했습니다.

 

2.라이브러리 모듈생성

[File>New>New Module..] 메뉴를 통해 새로운 라이브러리 모듈 추가

(Native Code가 작성될 모듈입니다.)

"Android Library"를 선택합니다.
적당한 라이브러리 명을 지정합니다. "ndklib"로 지정했습니다.
프로젝트에 ndklib 라이브러리가 추가 되었습니다.

 

Native Code 빌드를 위한 툴킷 설치

1. NDK  설치

1) [Tool>SDK Manager] 메뉴를 통해 프로젝트 설정 창을 열고 [SDK Tools]탭을 선택후,

[NDK] 항목을 체크해서 설치합니다.

(1) Android NDK는 Native Development Kit의 약자로, C / C++과 같은 Native 언어를 사용하여 앱의 일부를 구현할 수있게 해주는 개발 툴킷입니다.

 

NDK 빌드환경 구성 및 코드 작성

1. C/C++ 소스 폴더 생성

1) 프로젝트 표시창의 뷰타입을 "Project"로 변경 후,

ndklib 라이브러리의 [ src/main ] 하위에 jni 폴더를 생성합니다.

2. NDK 빌드환경 구성

1) [File>Setting] 메뉴을 통해 설정 다이얼로그를 연후, [Tool>External Tools] 항목을 선택합니다.

본 스크린 샷에는 이미 설정된 3개의 구성이 이미 존재합니다. 이 3개의 구성을 아래의 설명대로 생성합니다.

2) NDK Group에 세가지 환경을 추가합니다. 각각의 역할은 아래와 같으며 각 설정방법은 아래에 기술합니다.

(1) ndklib-javah

- Java Class를 기반으로 Jni규격에 맞게 헤더파일을 생성해주는 역할

(2) ndklib-build

- Native(C/C++) 코드를 빌드하는 구성

(3) ndklib-clean

- Native(C/C++) 코드의 빌드 결과물을 지워주는 구성 

3) [ + ] 버튼을 눌러 각 구성을 추가합니다.

1) ndklib-javah

(1) Group: NDK

(2) Program: javah.exe의 경로를 적어 줍니다.

$JDKPath$\bin\javah.exe

(3) Arguments: javah.exe 실행시 전달되는 파라미터 입니다. 그냥 아래 내용대로 적어 줍니다.

-classpath "$Classpath$" -v -jni $FileClass$

(4) Working directory: Native Code 소스파일을 작성할 폴더 경로를 적어 줍니다.

D:\Git-Repos\Android\ndklibdemo\ndklib\src\main\jni

- 위에서 생성한 jni폴더를 지정합니다.

- 지정한 경로에 헤더파일 생성됩니다.

2) ndklib-build

(1) Group: NDK

(2) Program: ndk-build.cmd의 경로를 적어 줍니다.

$JDKPath$\bin\javah.exeC:\Users\unodi\AppData\Local\Android\Sdk\ndk-bundle\ndk-build.cmd

(3) Working directory: Library module의 src/main 폴더 경로를 적어 줍니다. 

D:\Git-Repos\Android\ndklibdemo\ndklib\src\main

(3) ndklib-clean

(1) Group: NDK

(2) Program: ndk-build.cmd의 경로를 적어 줍니다.

$JDKPath$\bin\javah.exeC:\Users\unodi\AppData\Local\Android\Sdk\ndk-bundle\ndk-build.cmd

(3) Arguments:

clean

(4) Working directory: Library의 main 폴더 경로를 적어 줍니다. 

D:\Git-Repos\Android\ndklibdemo\ndklib\src\main

 

Native Code 작성

1. Native Wrapping Java Class 작성

1) [라이브러리>java>패키지]에 Native API를 Wrapping하는 Java Class를 작성합니다.

Class 이름을 "NativeWrapper"로 지정했습니다.

2) 생성된 Wrapping class에 라이브러리를 로드하는 기본 코드를 구현합니다.

static {

   System.loadLibrary("ndklib");

}

"ndklib"부분은 생성된 라이브러리의 이름을 기술 합니다.

public native int nativeSum(int a, int b);

native로 구현할 함수의 원형을 기술 합니다.

이 선언을 기반으로 javah가 Jni규격에 맞는 함수명을 생성하게 됩니다.

2. Native 코드 작성

1) Header 파일 생성

위에서 생성한 클래스에서 오른쪽 마우스를 누른후, [NDK>ndklib-javah] 메뉴를 선택해서 헤더파일을 생성합니다.

아래와 같이 class파일을 찾지 못한다고 표시되는 경우, 프로젝트를 한번 빌드한후 다시 시도합니다.

정상적으로 수행되면 아래와 같이 *.h 파일이 생성됩니다.

생성된 header파일은 [jni] 폴더에서 확인 할 수 있습니다.(ndklib-javah 환경 구성에서 지정한 경로 입니다.)

Jni 규격에 맞게 함수명과 파라미터가 작성됩니다.

2) cpp 파일 구현

헤더파일이 위치한 [jni]폴더에 cpp파일을 생성하여 함수내용을 구현합니다.

#include "com_thirteenrain_ndklib_NativeWrapper.h"

JNIEXPORT jint JNICALL Java_com_thirteenrain_ndklib_NativeWrapper_nativeSum
(JNIEnv *env, jobject obj, jint a, jint b)
{
     return a+b;
}

 

Gradle연동

1. android.mk 생성

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := ndklib

FILES := NativeSum.cpp

LOCAL_SRC_FILES := $(FILES)

LOCAL_LDLIBS := -llog

include $(BUILD_SHARED_LIBRARY)

"ndklib" - 라이브러리 이름을 기술합니다.

NativeSum.cpp - 빌드할 CPP 파일을 기술합니다.

2. NDK build - gradle 연동

1) Java Wrapping Class를 오른쪽 클릭하여 NDK Build를 Gradle과 연동합니다.

(1) Build System: ndk-build

(2) project Path: 위에서 생성한 Android.mk를 선택합니다.

이 작업을 통해 ndklib 모듈의 gradle에 NativeBuild 구문이 추가되어, Gradle빌드시 ndkBuild가 함께 진행되도록 설정됩니다.

android {
     externalNativeBuild {
          ndkBuild {
               path file('src/main/jni/Android.mk')
           }
     }
}

이상으로 Native Code 라이브러리 생성을 위한 설정이 완료되었습니다.

 

Native Code Library Build

1. Java Wrapping Class 우클릭 > NDK > ndklib-build 메뉴를 통해 Native Code를 빌드 할 수 있습니다.

2. ndklib/src/main/libs 하위에 라이브러리 파일(*.so)이 생성됩니다.

 

Native Library 사용

1. 코드 작성

1) 테스트를 위해 MainActivity의 onCreate 메소드에 ndklib의 NativeWapper.nativeSum을 호출하는 코드를 삽입합니다.

NativeWrapper nativeApi = new NativeWrapper();
int result = nativeApi.nativeSum(5, 10);

2. dependency 추가

1) [Alt+Enter] 단축키로 ndklib에 대한 dependency를 추가해 줍니다.

2) ndklib에 대한 dependency가 추가되었습니다.

디버깅

1) 디버깅 Tool설치

(1) LLDB

: Native Debugging을 위해서는 LLDB를 설치해야 합니다.(LLDB는 Android Studio에서 사용하는 Native Debugger입니다.)

2) Debug type

(1) Debug type이 [java]로 설정되어 있으면 Native Code에 대한 디버깅이 되지 않습니다.

: Java - Java Code만 디버깅 합니다.

: Auto - 디버깅 대상을 자동으로 판단합니다.

: Native - Native Code만 디버깅 합니다.

: Dual - Java, Native 둘다 디버깅 합니다.

 

실행확인

1) cpp 소스에 중단점을 설정합니다.

2) 툴바의 디버그 버튼 혹은 [Shit+F9] 단축키를 눌러 디버그를 진행합니다.

3) 중단점에 적중되어 Native Code 디버깅이 가능합니다.

 

  1. dd 2020.04.24 00:52

    javah.exe 파일이 없네요 ㅠㅠ

+ Recent posts