환경 설정 및 NDK 설치는 http://kylblog.tistory.com/14 여기서 확인 하시고 이 포스트를 보시면 됩니다.
1. JNI 폴더 생성 및 JNI 샘플 코드 작성
프로젝트명 - app - src - main - jni 폴더 생성
안드로이드 스튜디오에서 바로 생성하셔도 되고 폴더에 들어가서 새폴더로 생성하셔도 무관합니다.
C 파일 생성 후 샘플코드를 작성 해 보겠습니다
// 헤더파일은 생성 후 추후에 넣도록 합니다
//JNIEXPORT jstring JNICALL Java_ < 자신의 프로젝트명, 클래스명 입력>_<원하는 함수명 입력>
JNIEXPORT jstring JNICALL Java_com_example_user_myapplication_MainActivity_getJNI(JNIEnv *env, jobject obj) {
return env->NewStringUTF("Message from jniMain);
} |
2. java 소스 코드 작성 ( JNI 호출)
java 소스 코드에서 JNI 코딩한 것을 호출하는 코드를 입력해 보겠습니다.
호출 된 텍스트 문은 TextView에 뿌려주도록 합니다.
public class MainActivity extends AppCompatActivity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
TextView jniText = (TextView)findViewById(R.id.Text); jniText.setText(getJNI());
}
static { System.loadLibrary("FirstJNI"); // 원하는 라이브러리 명 입력, Android.mk 파일에서 입력할 LOCAL_MODULE 명과 맞추면 됩니다. } public native String getJNI();
}
|
3. 헤더 파일 생성
헤더 파일을 가지고 있어서 JNI 코드가 오류 없이 실행 할 수 있습니다.
헤더 파일을 간편하게 실행하기 위해서 만들어준 Tool 은 이전 포스트에서 확인 할 수 있습니다. http://kylblog.tistory.com/14
java 코드 오른쪽 클릭 후 External Tool 클릭 ( 저는 Group을 ndk 로 적었기에 ndk 이며 기본은 Externel Tool 입니다.)
Externel Tools 실행 후 제대로 실행이 되었다면 jni 폴더에 cpp 폴더 외에 .h 파일이 생성되었을 것 입니다.
.h 생성 후 cpp 파일에 헤더 파일 추가
#include <com_example_user_myapplication_MainActivity.h> // 자신의 프로젝트 명과 클래스명 입력해주시면 됩니다. JNIEXPORT jstring JNICALL Java_com_example_user_myapplication_MainActivity_getJNI(JNIEnv *env, jobject obj) {
return env->NewStringUTF("hello jni"); }
|
3. Android.mk 파일 생성
프로젝트명 - app - src - main - jni 폴더 에서 Android.mk 파일을 생성하여 입력합니다.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := FirstJNI LOCAL_SRC_FILES := <자신의cpp파일명>.cpp LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY) |
4. build.gradle(app) 수정
추가할 부분만 추가해주시면 됩니다.
import org.apache.tools.ant.taskdefs.condition.Os apply plugin: 'com.android.application'
///////////////////////////////////////////////////////////////////////////////////////////추가 // Project Structure에서 설정한 NDK 경로를 읽어들여 Return합니다. def getNdkBuildPath() { Properties properties = new Properties() properties.load(project.rootProject.file('local.properties').newDataInputStream())
def command = properties.getProperty('ndk.dir') if (Os.isFamily(Os.FAMILY_WINDOWS)) { command += "\\ndk-build.cmd" } else { command += "/ndk-build" }
return command } ////////////////////////////////////////////////////////////////////////////////////////////// android { compileSdkVersion 23 buildToolsVersion "23.0.3"
defaultConfig { applicationId "com.example.user.myapplication" minSdkVersion 15 targetSdkVersion 23 versionCode 1 versionName "1.0"
ndk { abiFilters "armeabi","armeabi-v7a" } } /////////////////////////////////////////////////////////////////////////////////////////////추가
sourceSets.main { // Compile된 Native Library가 위치하는 경로를 설정합니다. jniLibs.srcDir 'src/main/libs'
// 여기에 JNI Source 경로를 설정하면 Android Studio에서 기본적으로 지원하는 Native // Library Build가 이루어집니다. 이 경우에 Android.mk와 Application.mk를 // 자동으로 생성하기 때문에 편리하지만, 세부 설정이 어렵기 때문에 JNI Source의 // 경로를 지정하지 않습니다. jni.srcDirs = [] }
ext { // 아직은 Task 내에서 Build Type을 구분할 방법이 없기 때문에 이 Property를 // 이용해 Native Library를 Debugging 가능하도록 Build할 지 결정합니다. nativeDebuggable = true }
// NDK의 ndk-build 명령을 이용하여 Native Library를 Build하기 위한 Task를 정의합니다. //noinspection GroovyAssignabilityCheck task buildNative(type: Exec, description: 'Compile JNI source via NDK') { if (nativeDebuggable) { commandLine getNdkBuildPath(), 'NDK_DEBUG=1', '-C', file('src/main').absolutePath } else { commandLine getNdkBuildPath(), '-C', file('src/main').absolutePath } }
// App의 Java Code를 Compile할 때 buildNative Task를 실행하여 Native Library도 같이 // Build되도록 설정합니다. tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn buildNative }
// NDK로 생성된 Native Library와 Object를 삭제하기 위한 Task를 정의합니다. //noinspection GroovyAssignabilityCheck task cleanNative(type: Exec, description: 'Clean native objs and lib') { commandLine getNdkBuildPath(), '-C', file('src/main').absolutePath, 'clean' }
// Gradle의 clean Task를 실행할 떄, cleanNative Task를 실행하도록 설정합니다. clean.dependsOn 'cleanNative'
//////////////////////////////////////////////////////////////////////////////////////////////
buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } }
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.4.0' }
|
5. gradle.properties 수정
위의 작업을 마무리 하시고 build 작업을 하시면 gradle.properties 오류가 발생 합니다.
android.useDeprecatedNdk=true
추가 후 rebuild를 하시면
C 로 작성한 것을 불러 오는 걸 확인 하실 수 있습니다.
만약 실행이 안되신다면 .so 파일이 생성되었는지 확인하거나 Crean Project 후에 build 해보세요!