일단
고전적인 방법
1. 액티비티 클래스에서 먼저 static 으로 만들고자 하는 ndk 모듈을 로딩한다.
JniTwo 라는 이름은 C++ 모듈이름으로 Android.mk 에 [ LOCAL_MODULE := jniTwo ] 라고 나중에 똑같이 적으면 된다.
static { System.loadLibrary("jniTwo"); }
2. 모듈을 로드했으면 액티비티 클래스에서 쓸 함수를 이름만 정의한다.
private native String getStr(String str);
3. src->main->jni 폴더를 만든다.
4. 그 안에 cpp 파일을 만든다. * 헤더는 나중에 수동을 만들거다.
// // Created by kimtaeho on 2019-10-12. // #include <string.h> JNIEXPORT jstring JNICALL Java_com_example_myapplication_MainActivity_getStr(JNIEnv *env, jobject thiz, jstring str) { char buf[255]; char appendMsg[] = " JNI Hello"; const char *ch1 = env->GetStringUTFChars(str, 0); strcpy(buf, ch1); strcat(buf, appendMsg); return env->NewStringUTF(buf); }
5. 액티비티 클래스에서 함수를 사용해본다.
TextView ttt = (TextView)findViewById(R.id.ttt); ttt.setText(getStr("Kim"));
6. Android Studio Setting 에서 Tools->External Tools 에 새로 생성해서 다음과 같이 적는다.
Program : C:\Program Files\Java\jdk1.8.0_191\bin\javah.exe Arguments : -classpath "$Classpath$" -v -jni $FileClass$ Working Directory : C:\workspace\MyApplication2\app\src\main\jni
8. 모듈을 로드하는 Activity Class 에서 마우스오른쪽 [External Tools] 에서 6에서 생성한 것을 선택하면 복잡한 h 파일이 생성된다. 해당 파일의 맨 밑에 cpp 에서 만든 함수가 정의되어 있는것을 확인하고 파일이름을 적당히 바꾸고 cpp 에서 include 한다.
9. jni 폴더에 Android.mk 를 만들어 모듈이름고 소스 파일이름을 지정한다.
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := jniTwo LOCAL_SRC_FILES := Two.cpp LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY)
10. build.gradle(app) 에 다음과 같이 추가.
import org.apache.tools.ant.taskdefs.condition.Os // 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 { ... 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' }
11. gradle.properties 에 추가
android.useDeprecatedNdk=true
0 comments:
댓글 쓰기