AndroidでCプログラムを使ってみる
Androidのアプリ開発にCのソースを使う方法について、自分用の防備録として書いておく。
Android NDKのインストール
AndroidでCのプログラムを使う場合は、NDKが必要です。NDKのインストール方法はgoogleさんで出てくるので、ここでは省略。
基本的に、android-ndkをダウンロードして、解凍するだけ。2010.9.9現在だと、android-ndk-r4bでした。
コンパイルするための環境設定
- 解凍した android-ndk-r4b を、適当なフォルダにコピーします。cygwinにログインしたときに見えた方がよさそうなので、とりあえず、cygwinの自分のホームディレクトリ下にコピー。
- .bashrcに設定を追加
android-ndk-r4bを置いた場所を示すために、下記の設定を追加。
export ANDROID_NDK_ROOT=C:/cygwin/home/minao/android-ndk-r4b
export PATH=$PATH:/cygdrive/c/cygwin/home/minao/android-ndk-r4b
新規プロジェクトを作ってみる
- 自分のhome下にprojectsフォルダを作成します。
- eclipsから新規のandroidプロジェクトを作ります。
プロジェクト名をCtestとして、Use default locationのチェックを外し、cygwinのhome下に今作ったprojectsの中にCtestというフォルダを指定します。下図のように指定して完了。プロジェクトができます。
jniフォルダの作成
プロジェクトができたフォルダ(Ctest)にCソース用のjniフォルダを作ります。jniフォルダにCのソースとmakeファイル(*.mak)を作ります。今回は、hello-jniのサンプルを真似します。
ctest.cプログラムの作成
hello-jniのソースを少し改造して、CプログラムからCatLogができるように、log.hをインクルードしました。LOGI, LOGEをdefineします。関数は1つだけです。関数名が特徴的ですね。
#include <string.h> #include <jni.h> #include <android/log.h> #define LOG_TAG "Ctest" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) jstring Java_com_example_momoonga_ctest_CtestActivity_stringFromJNI( JNIEnv* env, jobject thiz ) { LOGI("Infomation Message CTest"); LOGE("Error Message CTest"); return (*env)->NewStringUTF(env, "Return Message of C test"); }
Makefileの作成
Android.makを作成します。LOCAL_MODULEがjavaから読み込むライブラリ名になります。log.hをインクルードしたので、-llogオプションを付けています。
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := ctest_module LOCAL_SRC_FILES := ctest.c LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY)
Cプログラムのビルド
cygwinを用いて、プログラムをビルドします。ログインして、cd projects/Ctestフォルダに移動します。そして、ndk-buildを実行します。これで、ctest_module.soがCtest/libs/armeabi下に生成されます。
CtestActivity.javaの編集
自動生成されたCtestActivity.javaをCプログラムを読み込むように編集します。これもhello-jniサンプルを流用します。System.loadLibrary("ctest_module")としてライブラリ名を指定します。後はpublic nativeで関数を指定すれば使えます。
package com.example.momoonga.ctest; import android.app.Activity; import android.os.Bundle; import android.widget.TextView; public class CtestActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //setContentView(R.layout.main); TextView tv = new TextView(this); tv.setText( stringFromJNI() ); setContentView(tv); } public native String stringFromJNI(); public native String unimplementedStringFromJNI(); static { System.loadLibrary("ctest_module"); } }
ちょっとメモ
eclipsでjavaプログラムを修正しながら、Cのプログラムも修正していると、ライブラリがうまく見えなくなってしまうことがあるようです。そんなときには、Cのモジュール名を変えてやれば、再認識してくれることが多いです。
例えば、ctest_module1とかして、もう一度、ndk-build します。当然、javaのSystem.loadLibrary()も書き換えなくてはなりませんが、これでうまく行くことが多いです。
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := ctest_module1 LOCAL_SRC_FILES := ctest.c LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY)
今日はこの辺で。