Android NativeMethods Pattern

2013-10-10T00:00:00+00:00 Android C++ Java

Androidっていうか単純にJNIに関する事だと思うので(ry

おそらくは通常だと

JNIEXPORT JNICALL jstring Java_パッケージ_say(JNIEnv* env, jobject thiz) {
}

的な感じでパッケージ名とメソッド名をconcatしたような名前の関数を定義する方式が一般的に知られていると思われるのですが、Androidのコアパッケージのソースとか色々見ているとNativeMethodsパターンな方式を採用しているのが多い。つまり上記のように定義しないっていうのがAndroidでは一般的なのかなと。んまぁNDKというかこういう辺りな事をやる事自体まったく無いんだけれどもやってみた

Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES := sample.cpp
LOCAL_MODULE := sample
LOCAL_LDLIBS := -llog

include $(BUILD_SHARED_LIBRARY)

別に必要性無いんじゃないかって思いますけど(ry

sample.cpp

#include <stdio.h>
#include <jni.h>
#include <android/log.h>

#define LOG_TAG "sample"
#define LOGV(...) __android_log_write(ANDROID_LOG_VERBOSE,LOG_TAG,__VA_ARGS__)

jstring say(JNIEnv* env, jobject thiz) {
  return env->NewStringUTF("ほげ ふが ふーばー");
}

static JNINativeMethod methods[] = {
  { "say", "()Ljava/lang/String;", (void*)say }
};

static int registerNativeMethods(JNIEnv* env, const char* className,
  JNINativeMethod* gMethods, int numMethods) {

  LOGV("registerNativeMethods");

  jclass clazz = env->FindClass(className);

  if (clazz == NULL) return JNI_FALSE;
  if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) return JNI_FALSE;

  return JNI_TRUE;
}

jint JNI_OnLoad(JavaVM* vm, void* reserved) {
  LOGV("JNI_OnLoad");

  JNIEnv* env;
  if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) return -1;

  registerNativeMethods(env, "sample/test/Sample", methods, 1);

  return (jint)JNI_VERSION_1_4;
}

ってな感じでJNIEXPORTやらJNICALLやら含まれないし、関数名の定義方法もパッケージ名とかそういうのを意識してやる方法っていうのを採用していない。

んで上記コード中にもあるようにsample.test.Sampleっていうクラスにマッピングする前提になっている?と思うので

package sample.test;

public class Sample {

    static {
        System.loadLibrary("sample");
    }

    public native String say();
}

な感じで定義しとけば良い。で起動してログ辺り見てみると

V/sample  (24768): JNI_OnLoad
V/sample  (24768): registerNativeMethods
V/sample  (24768): say: ほげ ふが ふーばー

的な感じで出てる。んまぁそういうネイティブメソッドのマッピング的な方式も採用できるっつー事で

ちなみに http://developer.android.com/training/articles/perf-jni.html っていうのがあるので一読必須かと

Robolectric+powermockito rubygemsサーバーを作る