안드로이드 스튜디오에서 NDK 사용하기

안드로이드 스튜디오에서 NDK 사용하는 법을 찾다가
어느 분이 윈도우즈10에서 안드로이드 스튜디오로 NDK 사용하고
추가로 OpenCV까지 돌리는 예제가 있길래 따라해봤습니다. (http://webnautes.tistory.com/923)

참고로 저는 Mac에서 작업 했습니다.

OS : El Capitan 10.11.6
안드로이드 스튜디오 버전 2.1.3

뉴 플젝 해서 하나 만듭니다.

제 핸폰이 5.1 이라 SDK도 5.1만 깔아놓았습니다.

뭐 연습이니 그냥 빈액티비티로 만들어줍니다.

package kr.co.linsoo.opencvtest;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    static {
        System.loadLibrary("hello");
    }
    public native String hello();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView textView = (TextView) findViewById(R.id.textView);

        textView.setText(hello());
    }
}

MainActivity.java 파일입니다.

이제 JNI 폴더를 추가해줄 차례입니다.
위 사진처럼 App을 클릭하고 우클릭해서 New->Folder->JNI Folder를 선택하면 됩니다.

보통 여기다 많이 하는지 그냥 Finish 눌러요.

이제  ⌘ + , 를 눌러서 Preferences… 로 들어갑니다.

그럼 위 이미지 같은 창이 뜨는데 거기서 Tools-External Tools를 선택합니다.
위 이미지는 javah가 이미 있지만 저걸 추가 해야 합니다 하단에 + 늘 눌러줍니다.

위 이미지 처럼 입력 해줍니다.

Parameters : -v -jni -d $ModuleFileDir$/src/main/jni $FileClass$
Working directory : $SourcepathEntry$

우측 insert macro.. 누르면 쉽게 입력할수 있긴 하지만 그마져도 귀찮은 사람을 위해
Parameter에 경로는 위에 jni폴더 추가 할때 경로 입니다 잘 확인하고 하세요.

참고로 javah가 무슨 용도인가 궁금해서 찾아봤습니다.

javah – C Header and Stub File Generator
javah produces C header files and C source files from a Java class. These files provide the connective glue that allow your Java and C code to interact.
출처: http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javah.html

자바 클래스에서 c헤더나 c 소스를 뽑아낼때 쓰는거라고 하네요.

참고로 파라미터에 들어간 옵션 설명은 이렇습니다.

jni파일을 사용할 java 파일을 선택하고 마우스 우클릭 해서 External Tools-javah를 선택합니다.

아마 별 문제 없이 위처럼 종료될겁니다.
이제 jni 폴더에 보면 파일이 하나 생겼을겁니다.
저는 kr_co_linsoo_opencvtest_MainActiivity.h  라는 파일이 생겼죠.

/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>
/* Header for class kr_co_linsoo_opencvtest_MainActivity */
#ifndef _Included_kr_co_linsoo_opencvtest_MainActivity
#define _Included_kr_co_linsoo_opencvtest_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     kr_co_linsoo_opencvtest_MainActivity
 * Method:    hello
 * Signature: ()Ljava/lang/String;
 */JNIEXPORT jstring JNICALL Java_kr_co_linsoo_opencvtest_MainActivity_hello
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

예전에 이클립스에서 할때는 이거 다 일일이 타이핑 하라고 하던데…
이젠 쉽게 만드네요 ㅋㅋㅋ

이젠 c파일을 추가합니다.

//
// Created by linsoo on 2016. 8. 26..
//

#include "kr_co_linsoo_opencvtest_MainActivity.h"

JNIEXPORT jstring JNICALL Java_kr_co_linsoo_opencvtest_MainActivity_hello(JNIEnv *env, jobject obj){
    return env->NewStringUTF("Linsoo.co.kr");
}

파일명은 맘대로입니다. 저는 헤더파일이랑 동일하게 kr_co_linsoo_opencvtest_MainActivity.cpp 로 해줬습니다.

이 상태에서 빌드를 하면 에러뜹니다.
Error:Execution failed for task ‘:app:compileDebugNdk’.
> Error: NDK integration is deprecated in the current plugin.  Consider trying the new experimental plugin.  For details, see http://tools.android.com/tech-docs/new-build-system/gradle-experimental.  Set “android.useDeprecatedNdk=true” in gradle.properties to continue using the current NDK integration.

gradle.properties 파일 열고 맨 밑에 android.useDeprcatedNDK=true 를 입력합니다.

다시 빌드 합니다 그리고 또 에러납니다.
에러에 뜨는 사이트에 접속해 봅니다.
http://tools.android.com/tech-docs/new-build-system/gradle-experimental
밑에 좀 내려가면 이런 구문이 있습니다.

Ndk Integration
The experimental plugin comes with NDK integration for creating native applications.  To use the NDK integration:
Use the SDK Manager inside Studio to download the NDK.
Set ndk.dir in local.properties or the ANDROID_NDK_HOME environment variable to the directory containing the NDK.
Add an android.ndk block to the model in build.gradle.

The build.gradle of a simple NDK application may look like this:

apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
ndk {
moduleName "native"
}
}
} 

*Note that the moduleName is required.  It determines the name of the resulting native library.

대충 요약하자면 build.gradle  안에 android 블럭안에 ndk 블록을 추가해라 그리고 모듈네임은 호출할 네이티브 함수명임. 그래서 추가해줬습니다.

근데 말이죠. 저 ndk블럭을 그냥 안드로이드 블럭 안에 넣으면 안되더군요.
defaultConfig 블럭 안에다 넣어야지만 에러가 안나네요.
그냥 안드로이드 블럭 안에 넣으면 아래와 같은 에러가 뜹니다.
Error:(7, 0) Could not find method ndk() for arguments [build_1czpsirmd9p4vacra5yp60jxk$_run_closure1$_closure3@4a964f08] on project ‘:app’ of type org.gradle.api.Project.
Gradle 사용법을 잘 모르는 상태에서 해서 에러 원인을 모르겠네요.

뭐 암튼

추가 하면 상단에 이런 메세지가 뜹니다 Sync Now를 눌러줍니다.
그리고 빌드하고 실행하면

이렇게 나옵니다.

OpenCV까지 쓰는거 쓸려다가 너무 길어지는거 같아서 두개로 나눕니다.
예전에 안드로이드 스튜디오에서 ndk 쓸려면 뭔가 이것저것 해주는게 많았는데 (이클립스에 비해)
요즘은 딱히 별로 해주는거 없이 기본적인 빌드폼이 잡히네요. 세상 참 편해졌습니다.


크리에이티브 커먼즈 라이선스Linsoo의 저작물인 이 저작물은(는)크리에이티브 커먼즈 저작자표시-동일조건변경허락 4.0 국제 라이선스에 따라 이용할 수 있습니다.

댓글 남기기

이메일은 공개되지 않습니다.

This site uses Akismet to reduce spam. Learn how your comment data is processed.