서적에 관한 질문 및 오류 등을 문의 할 수 있으며, 저자로부터 직접 답변을 받을 수 있습니다.
아~ 이제야 소스확인을 했습니다.
올려주신 코드를 보니
JNIEXPORT jstring JNICALL Java_com_sklee_jnitest_HelloJNI_getString(JNIEnv *env, jobject object){
jstring buf_devid = NULL;
jclass cls_context = (*env)->FindClass(env, "android/content/Context");
jfieldID fid = (*env)->GetStaticFieldID(env, cls_context, "TELEPHONY_SERVICE", "Ljava/lang/String;");
jstring str = (*env)->GetStaticObjectField(env, cls_context, fid);
jmethodID mid = (*env)->GetMethodID(env, cls_context, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
jobject telephony = (*env)->CallObjectMethod(env, cls_context, mid, str); <= 여기가 잘못되었는데 왜냐하면 context 객체가 생성된 타이밍에서 getSystemService 를 가져오셔야 합니다. 왜냐하면 abstract 함수이기 때문이죠.
다시 말해서 Activity가 만들어지면서 context가 생기는데 이 context를 통해서 저 함수를 호출하셔야 한다는 말이죠
jclass cls_tm = (*env)->FindClass(env, "android/telephony/TelephonyManager");
mid = (*env)->GetMethodID(env, cls_tm, "getDeviceId", "()Ljava/lang/String;");
str = (*env)->CallObjectMethod(env, cls_tm, mid); <= 여기서도 마찬가지로 액티비티에서 나온 context 를 통해서 생성된 TelephonyManager를 통해서 호출해야 합니다.
jsize len_jstr = (*env)->GetStringUTFLength(env, str);
(*env)->GetStringUTFRegion(env, str, 0, len_jstr, buf_devid);
return (*env)->NewStringUTF(env, buf_devid);
}
제가 코드를 다시 정리해 보았는데 이렇게 짜시면 되겠습니다.
자바에서 하는 순서 그대로 Native 에서 하시면 됩니다.
---------------------------------------------------------------------------------------------------------------------------------------
JAVA CODE
package com.sklee.jnitest;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
public class JNITestActivity extends Activity {
private TextView mTextView;
private Context mContext;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mContext = getApplicationContext();
mTextView = (TextView) findViewById(R.id.textivew);
System.loadLibrary("hellojni");
findViewById(R.id.btn).setOnClickListener(new OnClickListener() {
public void onClick(View v) {
/*
* TelephonyManager tManager = (TelephonyManager)
* getSystemService(Context.TELEPHONY_SERVICE); String mDeviceID
* = tManager.getDeviceId(); Log.e("HOHO", "HOHO : " +
* mDeviceID);
*/
mTextView.setText(getString());
}
});
}
public native String getString();
}
---------------------------------------------------------------------------------------------------------------------------------------
NATIVE CODE
#include <string.h>
#include <jni.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <android/log.h>
#include "HelloJNI.h"
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "libnav", __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , "libnav", __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO , "libnav", __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN , "libnav", __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , "libnav", __VA_ARGS__)
JNIEXPORT jstring JNICALL Java_com_sklee_jnitest_JNITestActivity_getString(JNIEnv *env, jobject obj){
jclass cls =(*env)->GetObjectClass(env, obj);
jfieldID fid = (*env)->GetFieldID(env, cls, "mContext", "Landroid/content/Context;");
jobject mContext = (*env)->GetObjectField(env, obj, fid);
jclass cls_context = (*env)->FindClass(env, "android/content/Context");
jmethodID getSystemService = (*env)->GetMethodID(env, cls_context, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
jfieldID TELEPHONY_SERVICE = (*env)->GetStaticFieldID(env, cls_context, "TELEPHONY_SERVICE", "Ljava/lang/String;");
jstring str = (*env)->GetStaticObjectField(env, cls_context, TELEPHONY_SERVICE);
jobject telephonymanager = (*env)->CallObjectMethod(env, mContext, getSystemService, str);
jclass cls_tm = (*env)->FindClass(env, "android/telephony/TelephonyManager");
jmethodID getDeviceId = (*env)->GetMethodID(env, cls_tm, "getDeviceId", "()Ljava/lang/String;");
jstring deviceid = (*env)->CallObjectMethod(env, telephonymanager, getDeviceId);
jsize len_jstr = (*env)->GetStringUTFLength(env, deviceid);
LOGE("HOHO deviceid lenth : %d",len_jstr);
return deviceid;
}
제가 지금 소스를 잠시 살펴보니 getSystemService 라는 함수가 Context class에서 abstract 함수로 되어 있어서 호출을 못하고 있는것으로 보입니다.
getSystemService 가 실제 구현되어 있는 클래스에서 호출을 해야 할것 같은데요.
지금 제 pc 환경이 올려주신 소스를 돌려볼 수가 없는상태라. 내일 회사에가서 확인해보면 정확히 알수 있을것 같습니다.