본문 바로가기
프로그래밍 놀이터/안드로이드, Java

[Android/안드로이드] JNI Tutorial HelloJNI ( 샘플 소스 포함 )

by 돼지왕 왕돼지 2012. 3. 24.
반응형

안녕하세요 돼지왕왕돼지입니다.

지난번에는 일반 console application 에서의 JNI 를 사용하는 법에 대해 알아보았습니다.
2012/03/24 - [프로그래밍 놀이터/자바] - [Java] JNI Tutorial ( HelloJNI )

이번에는 안드로이드에서의 JNI Tutorial HelloJNI 를 알아봅니다.
 


HelloJNI.zip




 

Android JNI Tutorial HelloJNI


Android JNI 사용을 위한 준비물.


1. 일반 Android 앱 개발 도구
   ( Java, Eclipse, Android SDK등 요런 녀석들은 다들 가지고 있을 것이라고 생각합니다. )


2. Android NDK.
 - Android NDK 는 Native Development KIT 으로 native program 개발을 위한 개발 도구입니다.
   아래 사이트에서 다운로드 받을 수 있으며, 이클립스처럼 압축을 푸는 것만으로 설치가 끝납니다.
   단!! 설치되는 폴더 path 에 space 가 들어있지 않아야 합니다.
   ( 필자는 나중에 위치를 옮겼습니다. )

   http://developer.android.com/sdk/ndk/index.html  

3. Cygwin
 - Cygwin 은windows 환경에서 Linux 의 환경을 가상으로 쓸 수 있도록 도와주는 terminal program 입니다.  왜 Linux 환경이 필요할까요? 안드로이드는 Linux OS 를 바탕으로 한 framework 입니다. 그래서 library 를 만들 때 so 파일로 만들어주어야 android 에서 사용할 수 있습니다. Windows 는 dll 로 library 를 만드는 것 아시죠? 그래서 so 파일을 만들지 위해 linux 환경이 필요한 것입니다.
   아래 사이트에서 "setup.exe" 를 클릭하여 setup 파일을 다운받아 설치해주면 됩니다.
   http://cygwin.com/install.html 

2012/03/24 - [프로그래밍 놀이터/안드로이드] - [Android/안드로이드] cygwin 설치방법 ( JNI 사용 위한 native library compile에 focus )




HelloJNI 만들기.


Android 용 HelloJNI 는 Button 을 누르면 TextView 에 string 을 출력하는데, 이 string 을 JNI 를 통해 native 코드로 가져오는 것입니다. 결과화면을 미리 볼까요? "printHelloJNI With JNI" 버튼을 눌러 "This is JNI test :)" 라는 string 을 native 로부터 얻어와 프린트해줍니다.



1. 먼저 Android Project 를 만듭니다. ( 이건 다 하실 수 있죠? )
   쉬운 library compile 을 위해서 project 를 ndk 설치폴더의 하위폴더로 만들어줍니다.
   (만약 다른 workspace 에 미리 만들어버렸다면 프로젝트 우클릭 - [Refactor] - [Move] 로 위치를 변경합니다. )





2. layout 파일을 작성합니다. 저는 기본 폼을 따라 main.xml 로 하였습니다.

<layout/main.xml>

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:orientation="vertical" >

    <TextView

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:id="@+id/textivew"

        />

    <Button

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="printHelloJNI With JNI"

        android:id="@+id/btn" 

        />

</LinearLayout>


3. Activity 파일을 작성합니다.

<JNITest.java>

package com.sklee.jnitest;


import android.app.Activity;

import android.os.Bundle;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.TextView;


public class JNITestActivity extends Activity {

    private TextView mTextView;

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        

        mTextView = (TextView) findViewById( R.id.textivew );

        

        findViewById( R.id.btn ).setOnClickListener( new OnClickListener() {

public void onClick(View v) {

mTextView.setText( new HelloJNI().getString() );

}

});

    }

}




4. JNI 연결을 위해 native function을 정의하는 HelloJNI.java 를 만듭니다.

<HelloJNI.java>

package com.sklee.jnitest;


public class HelloJNI {

private static final String LIB_NAME = "hellojni";

public native String getString();

static{

System.loadLibrary( LIB_NAME );

}

}


[왜 Activity 하나에 몰아넣지 않나요?]


5. JNI header 파일 추출.
  해당 프로젝트의 폴더의  /bin/classes 폴더로 이동합니다. 다음 커맨드 라인 명령을 통해서 jni header 파일을 추출합니다.

javah -jni com.sklee.jnitest.HelloJNI


다른 tutorial 들에서는 /bin 폴더에서 이 명령을 수행하라고 합니다. 하지만, 저는 계속 에러가 나더라구요. 그래서 classes 로 이동하여 했더니 잘 됩니다. 사실 classes 안에 들어간 후부터 package 폴더가 시작되니 classes 까지 가서 명령어를 입력하는 것이 맞습니다.
( javah 가 안 된다면, java sdk 의 bin 폴더를 환경 변수 path 로 걸어주세요. )

생성되는 .h 파일은 명령어를 실행한 폴더에 만들어지며, 이름은 packageName + class파일이름이기 떄문에 이 예제의 경우는 com_sklee_jnitest_HelloJNI.h 로 만들어집니다. 편의를 위해 HelloJNI.h 로 rename 해줍시다.


6. header 파일을 기준으로 native 코드 c 파일을 만들어줍니다.

<HelloJNI.c>

#include <jni.h>

#include "HelloJNI.h"


JNIEXPORT jstring JNICALL Java_com_sklee_jnitest_HelloJNI_getString(JNIEnv *env, jobject object){

return (*env)->NewStringUTF( env, "This is JNI test :)" );

}


jni.h 는 jni 를 위해 include 해야 하며, 기 생성한 HelloJNI.h 는 link 을 위해 include 해줍니다.
signature 는 이해하기가 어려울 수 있는데, HelloJNI.h 안에 있는 signature 를 그대로 사용하면 됩니다.


7. Library compile 을 위한 Android.mk 를 만들어줍니다.


<Android.mk>

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := hellojni

LOCAL_SRC_FILES := HelloJNI.c

include $(BUILD_SHARED_LIBRARY)


 Android.mk 에 대한 정확한 이해를 위해서는 많은 공부가 필요합니다. Tutorial 이기 때문에 여기서는 간단한 이해만을 해보겠습니다. 여기서 우리가 주의깊게 봐야할 내용은 2가지인데요. LOCAL_MODULE 과 LOCAL_SRC_FILES 입니다. LOCAL_MODULE 은 output 으로 나오는 library file 이름이라고 보시면 됩니다. 이 부분은 System.loadLibrary( "여기" )의 "여기" 부분과 이름이 같아야 합니다. LOCAL_SRC_FILES 는 library 에 들어갈 native 코드파일들을 명시합니다. 우리는 1개의 c파일만 가지고 있으니 HelloJNI.c 를 써줍니다.



8. native 와 관련된 파일들을 프로젝트의 "jni" folder 를 만들어서 복사해줍니다. 
   native 관련 파일들은 HelloJNI.h, HelloJNI.c, Android.mk 3개입니다.
   

9. cygwin 을 이용해서 library compile 을 해줍니다.
  먼저 cygwin terminal 을 실행합니다.
  프로젝트의 main 폴더로 이동하여, ndk-build를 실행시켜줍니다.

  저는 프로젝트를 NDK/works/HelloJNI 에 생성했기에 "../../ndk-build" 로 명령을 실행했습니다.


결과물은 libs/armeabi/libhellojni.so 로 저장이 됩니다.

전체 결과를 [Package Explorer]를 통해 볼까요?





10 . 모든 준비는 끝났습니다. 이제 보통 안드로이드 앱을 실행시키듯 싱행해주시면 되겠습니다.

10-1. 간혹 Library Link 가 맞지 않는 경우가 있는데. 그럴 땐 다음과 같이 
        
java.lang.UnsatisfiedLinkError 가 발생합니다.
        이 때는 library link 부분을 점검해주시면 되겠습니다.












반응형

댓글