ネイティブOpenCVを利用したくて、Ubuntuのセットアップをはじめた。
空いているマシン無くて、VirtualBoxでセットアップ中…
ミスった、
Kernel考えてなかった
VMWareに変更...
とりあえず、GUIを入れてみる。
インスト時に間違えて日本語選択したから、コンソールで バケたよorz
そー言えば、
アンドロイドアプリの開発環境で、一番開発しやすい環境ってなんだろう?
やっぱり人それぞれなのかなぁ。
とりあえず、GUIであがってきた。
Javaを入れよう。
sudo apt-get update
sudo apt-get sun-java6-jdk
念のためSDKをSunに切り替え
sudo update-alternatives --config java
Sunしかないって怒られたorz
http://developer.android.com/sdk/index.html
Linux 用のSDKをダウンロード
ダウンロードが終わったら
Homeディレクトリに展開する。
Eclipseを入れよう。
Eclipse Classic をダウンロード
http://www.eclipse.org/downloads/
.bashrcを編集して、SDKのtoolsディレクトリをpathに追加。
PATH=$PATH:$HOME/android-sdk-linux_86/tools
Eclipse ADT プラグインのインストール
メニューの Help – Install New Software を選択
Add ボタン押下
Nameに、ADT Plugin
Locationに、http://dl-ssl.google.com/android/eclipse/
何も表示されない。
調べてみたら、Location
https://dl-ssl.google.com/android/eclipse/だった
Eclipseプラグインをインストールした後にリブートしたら
Android SDKマネージャーが起動してきた。
なんか勝手にインストールしてくれるっぽいので任せてみた。
前はこんなことにならなかったような気がするんだが...
Android-sdkのディレクトリも他の場所をしていされていたのだが、とりあえずデフォで進んでみよう。
とりあえず、パスの変更もしておくかなぁ。
ANDROID_SDK_HOME=$HOME/android-sdk
export ANDROID_SDK_HOME
PATH = $PATH:$ ANDROID_SDK_HOME/tools: $ANDROID_SDK_HOME/platforms:$ANDROID_SDK_HOME/platform-tools
タグ :androidUbuntuEclipse
eclipseの設定が終わったので
Android SDK Managerを起動してみたら
Android4.0.3と Android2.1のSDKPlatformだけインストールされてた。
俺の端末はAndroid4.0だから、手動で設定。
eclipseの設定が終わってデバッグテスト。
実機を接続すると、なんか文字化けして認識せず。
調べてみたら以下をやらなきゃいけないらしい。
http://developer.android.com/guide/developing/device.html#setting-up
1./etc/udev/rules.d/51-android.rules.ファイルを作った
2.SUBSYSTEM=="usb", ATTR{idVendor}=="0bb4", MODE="0666", GROUP="plugdev" 書いた 一部修正
3.chmod a+r /etc/udev/rules.d/51-android.rules実施
4.再起動
うまくいった。
DeploymentTargetSelectionModeをManualにしたはずだが、
Automaticになってた。
なぜだろう?
やっと、やりたいことにたどり着いた。
android-ndk-r7をセットアップ
http://developer.android.com/sdk/ndk/index.html
からLinux用をダウンロード。
HOMEに解凍して、PATHを追加。
android NDK r7では、ビルド時に「android-ndk-r7/prebuilt/linux-x86/bin/awk」コマンドが使われているみたい。
この「awk」は64bitでコンパイルされてて、32bit環境ではエラーが発生するのらしい。
そのため、シンボリックリンクを作成して、ローカルの「awk」を利用するとのこと。
cd (android-ndk-r7)/prebuilt/linux-x86/bin/
mv awk awk.bak
ln -s /usr/bin/awk awk
エラーが出るかでないかはわからないが、とりあえずヤッとく。
OpenCVのインストールは
「Open Computer Vision Library - Browse /opencv-android/2.3.1 at SourceForge.net」から
「OpenCV-2.3.1-android-bin.tar.bz2」をダウンロードし、
任意の場所へ解凍するだけ。
解凍して出来たサンプル「tutorial-3-native」をeclipseにインポート。
[プロジェクト名]を「Tutorial 2 Advanced -1.Add Native OpenCV」
インポートしたら怒られたけど無視して次に進む。
ターミナルを起動。
ターミナルでtutorial-3-nativeのプロジェクトルートへ移動
ndk-build
Eclipseに戻ってプロジェクトをリフレッシュし、
Android端末にアプリをデプロイ。
アプリは動作するけど、カメラのViewが黒いまま。
色々やったけど、見込みなし。
Galaxy Nexusではサンプル動かないのかなぁ。
利用可能なAPI
ZLib:データ圧縮・解凍用ライブラリ APIレベル3以降
Math Library: cos関数などmath.hで提供される数学ライブラリ APIレベル3以降
Log Library:Nativeからログ出力を行うためのライブラリ APIレベル3以降
Dynamic Linker:共有ライブラリを動的リンクする昨日を提供 APIレベル3以降
Pthread Library:POSIX系OSに実装されているスレッドライブラリ
pthread_cancel関数などは利用できない APIレベル3以降
OpenGL ES ,EGL:高速な2D/3D描画が可能なグラフィックスAPI APIレベル5、9以降
jnigraphics: NativeでJavaのBitmapを効率よく扱うことが出来る機能を持ったライブラリ OS2.2以降
OpenSL ES:圧縮音声・PCM波形の再生や録音が可能なサウンド用API APIレベル9以降
OS4.0以降であればMP3やACCなどの圧縮音声をPCM形式へデコードできる
ネイティブアプリケーションAPI:Javaコードを書かずにC/C++言語のみでアプリケーションを作るためのライブラリ群。Androidoの画像表示の基本Activityクラスのネイティブ版NativeActivityやassetsからのファイル読み込みセンサーの利用などが可能 OS2.3 APIレベル9以降
OpenMAX ALは低レベルなマルチメディアストリーミング用API
MPEG-2ts形式の動画を再生可能。 OS4.0 APIレベル14以降
以上、基本的なことなんだろうなぁ。
理解していかねば・・・
開発環境はこの前、OpenCVの勉強のときに作った環境をそのまま利用。
UbuntuServer8(OnVMWare)、Eclipse Indigo、Android SDK、Android NDK、
パスの設定、ADTのインストール、エミュレーターの設定
が済んでいる状態。
実機:GalaxyNexus、HT-03a rooted OS2.2(...だったと思う)
とりあえず、本にしたがってNDKの動作環境を確認してみる。
プロジェクトの作成
ProjectName:HelloNDK
BuildTarget:2.1
ApplicationName:HelloNDK
Package:com.example.hellondk
Create Activity:HelloNdk
MinimumSDK:7
プロジェクト上で新規ディレクトリの作成
フォルダ名をjniにする
Cソースコードの実装
jniフォルダ内にhello-ndk.cを作成
ソースを開いて入力。
# include
#include
void
Java_com_example_hellondk_HelloNDK_sayHello(JNIEnv* env,jobject thiz)
{
__android_log_write(ANDROID_LOG_INFO, __FILE__,"hello world!");
}
Android.mkの作成
jniディレクトリにAndroid.mkを作成
その中に、コードを記入。
Local_PATH:=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:=hello-ndk
LOCAL_SRC_FILES:=hello-ndk.c
LOCAL_LDLIBS:=-llog
include $(BUILD_SHARED_LIBRARY)
ターミナルでビルド
ターミナルを起動して、共有ライブラリをビルドする。
プロジェクトのディレクトリに移動し
ndk-build
を実行。
エラー発生
/workspace/HelloNDK/jni/hello-ndk.c:7: undefined reference to `__android_log_write'
collect2: ld returned 1 exit status
make: *** [/home/administrator/workspace/HelloNDK/obj/local/armeabi/libhello-ndk.so] Error 1
何度やっても、同じ結果。
Webを探し回ったが見つからず。
確認しなおしたら、
LOCAL_LDLIBS:=-llog
スペルミス...orz 時間食った
とりあえず、build結果はこんな感じ
/workspace/HelloNDK/jni$ ndk-build
Compile thumb : hello-ndk <= hello-ndk.c
SharedLibrary : libhello-ndk.so
Install : libhello-ndk.so => libs/armeabi/libhello-ndk.so
JavaでNativeCodeを呼び出してみる。
こんな感じ
public class HelloNDK extends Activity {
/** Called when the activity is first created. */
static{
System.loadLibrary("helo-ndk");
}
public native void sayHello();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
sayHello();
}
}
Log上に結果こんな感じ
05-04 17:23:41.470: I//workspace/HelloNDK/jni/hello-ndk.c(333): hello world!
とりあえず、NDKの動作は確認できた。
良かったよかった。
開発が出来るなぁ。
さっき作ったhello-ndk.cを改良
引数を持たせたものを追加してみる。
/*追加内容*/
Jint
Java_com_example_hellondk_HelloNDK_addInt(JNIEnv* env, jobject thiz, jint a, jint b)
{
return a+b;
}
Javaコードも変更
onCreate()内を変更
Log.i("addInt() result",String.valueOf(addInt(1,2)));
ターミナルでndk-buildを実行。
またエラー
jintがJintになってた。orz
修正後、無事Build完了。
eclipseでデバック。
なぜか1回目エラーになったけど、二回目はちゃんとログ吐いたよ。
05-04 21:50:57.714: I/addInt() result(274): 3
よかったよかった。
ヘッダファイルを自動的に作成してくれるらしい。
(Cとかカジッたくらいだからイマイチ便利さがわかってないけど)
なんとなく、便利なんだと思う。
とりあえず、ターミナルでプロジェクトの ディレクトリ以下のbinに移動
javah com.example.hellondk.HelloNDK
を実行してみる。
やっぱり怒られた。
com.example.hellondk.HelloNDK にアクセスできないとか言ってる。
今回は参考書どおりスペルミスなくやっているんだが・・
ぐぐって見た。
javahではまっている人は多いみたい。
javah -classpath bin -d jni $パッケージ名$
とかクラスパスを明示的にしてjavahを実行してる。
自分のディレクトリを確認したら、
bin/classes/com/example/hellondk/
になってた。
cdでプロジェクトホームに移動して、
javah -classpath bin/classes -d jni com.example.hellondk.HelloNDK
を実行してみた。
無事成功。
jniにこんなのが出来てた。
com_example_hellondk_HelloNDK.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class com_example_hellondk_HelloNDK */
#ifndef _Included_com_example_hellondk_HelloNDK
#define _Included_com_example_hellondk_HelloNDK
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_hellondk_HelloNDK
* Method: sayHello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_example_hellondk_HelloNDK_sayHello
(JNIEnv *, jobject);
/*
* Class: com_example_hellondk_HelloNDK
* Method: addInt
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_example_hellondk_HelloNDK_addInt
(JNIEnv *, jobject, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
この状態で、
hello-ndk.cを編集。
hello-ndk.c
#include
#include
#include "com_example_hellondk_HelloNDK.h"
/*jvoid
Java_com_example_hellondk_HelloNDK_sayHello(JNIEnv* env, jobject thiz)*/
JNIEXPORT void JNICALL Java_com_example_hellondk_HelloNDK_sayHello(JNIEnv* env, jobject thiz)
{
__android_log_write(ANDROID_LOG_INFO, __FILE__,"hello world!");
}
/*jint
Java_com_example_hellondk_HelloNDK_addInt(JNIEnv* env, jobject thiz, jint a, jint b)*/
JNIEXPORT jint JNICALL Java_com_example_hellondk_HelloNDK_addInt(JNIEnv* env, jobject thiz, jint a, jint b)
{
return a+b;
}
いつものようにndk-build
エラー無くとおった。
HelloNDK.javaでsayHelloも呼び出せるようにしてデバック。
05-05 00:27:24.984: I//home/administrator/workspace/HelloNDK/jni/hello-ndk.c(301): hello world!
05-05 00:27:24.984: I/addInt() result(301): 3
ちゃんと動いたよ。
ヘッダファイルもちゃんと使えたらしい。
HelloNDK.javaに
public native void handleString();
を追加して
javahを実行して
hello-ndk.cを変更
#include
#include
#include "com_example_hellondk_HelloNDK.h"
#include
/*jvoid
Java_com_example_hellondk_HelloNDK_sayHello(JNIEnv* env, jobject thiz)*/
JNIEXPORT void JNICALL Java_com_example_hellondk_HelloNDK_sayHello(JNIEnv* env, jobject thiz)
{
__android_log_write(ANDROID_LOG_INFO, __FILE__,"hello world!");
}
/*jint
Java_com_example_hellondk_HelloNDK_addInt(JNIEnv* env, jobject thiz, jint a, jint b)*/
JNIEXPORT jint JNICALL Java_com_example_hellondk_HelloNDK_addInt(JNIEnv* env, jobject thiz, jint a, jint b)
{
return a+b;
}
JNIEXPORT void JNICALL Java_com_example_hellondk_HelloNDK_handleString(JNIEnv* env, jobject thiz)
{
jstring jstr;
jsize str_len;
const jchar* jb_str;
jboolean is_copy;
/*UTF-8文字列からインスタンス作成*/
jstr=(*env) -> NewStringUTF(env,"HELLO WORLD!");
assert(jstr);
/*長さ取得*/
str_len = (*env) -> GetStringUTFLength(env, jstr);
__android_log_print(ANDROID_LOG_INFO, __FILE__,"str_len=%d", str_len);
/*UTF-8文字列ポインタ*/
jb_str=(*env) -> GetStringUTFChars(env, jstr, &is_copy);
assert(jb_str);
__android_log_print(ANDROID_LOG_INFO, __FILE__,"jb_str=%s", jb_str);
/*GetStringUTFCharsで使用したjb_strを開放*/
(*env) ->ReleaseStringUTFChars(env, jstr, jb_str);
}
ndk-buildしてみる。
warningが出てる。 ポインタの型が違うらしい
とりあえずデバック実行してみる。
ログにちゃんと出力されたよ~
05-05 01:47:04.864: I//home/administrator/workspace/HelloNDK/jni/hello-ndk.c(329): hello world!
05-05 01:47:04.874: I/addInt() result(329): 3
05-05 01:47:04.874: I//home/administrator/workspace/HelloNDK/jni/hello-ndk.c(329): str_len=12
05-05 01:47:04.874: I//home/administrator/workspace/HelloNDK/jni/hello-ndk.c(329): jb_str=HELLO WORLD!
この後、ペタ返しアプリに浮気・・
だらだらと長くなった・・・