2009年3月29日日曜日



f:id:bs-android:20090122021549g:image


日本Androidの会の関西支部の活動報告です。


2009/3/28に第2回ハンズオンセミナーin大阪を開催しました。


会場提供していただいた株式会社パソナテックさま、どうもありがとうございました。




  • 公演内容



「OpenGL事始め」(宮川彬央さん)


OpenGLの入門編で取っ掛かり安い内容でした。


 講演資料


 プロジェクトファイル一式


「GPSはじめの一歩」(山本慎也さん)


GPSの入門編です。2点間の距離の計算やDDMSでのGPSエミュレーションの方法等、はじめの一歩以上の充実した内容でした。


 講演資料


 プロジェクトファイル一式


PIAX(P2P Interactive Agent eXtensions) on Androidの挑戦」(吉田幹さん)


PIAXとAndroidの熱いお話し。60ページ近くに及ぶ膨大なドキュメントは圧巻です。


「個人の技術者が世界を変える!」という熱い話は聞き応えがありました。


 講演資料


「もっとServiceしよう」(有山圭二さん)


AIDLを使用してサービスを実装するハンズオン。


サービスについて知れば知るほど使い道が難しいとおっしゃっていたのが印象的でした。


 講演資料


 プロジェクト一式


「動画再生アプリ」(杉本礼彦)


簡単な動画再生アプリ作成のハンズオンを行いました。うまく再生できるか心配でしたが、うまく行ってよかったです。


 講演資料


 サンプル動画



参加された皆様、どうもありがとうございました。


お疲れ様でした。


4月には弊社は新事務所に引越しいたします。


引越し後には弊社オフィスのあるビルの会議室を利用して


弊社主催でセミナーを開催したいと思います!


よろしくおねがいします。





第2回Androidハンズオンセミナーin大阪レポート



f:id:bs-android:20090122021549g:image


日本Androidの会の関西支部の活動報告です。


2009/3/28に第2回ハンズオンセミナーin大阪を開催しました。


会場提供していただいた株式会社パソナテックさま、どうもありがとうございました。




  • 公演内容



「OpenGL事始め」(宮川彬央さん)


OpenGLの入門編で取っ掛かり安い内容でした。


 講演資料


 プロジェクトファイル一式


「GPSはじめの一歩」(山本慎也さん)


GPSの入門編です。2点間の距離の計算やDDMSでのGPSエミュレーションの方法等、はじめの一歩以上の充実した内容でした。


 講演資料


 プロジェクトファイル一式


PIAX(P2P Interactive Agent eXtensions) on Androidの挑戦」(吉田幹さん)


PIAXとAndroidの熱いお話し。60ページ近くに及ぶ膨大なドキュメントは圧巻です。


「個人の技術者が世界を変える!」という熱い話は聞き応えがありました。


 講演資料


「もっとServiceしよう」(有山圭二さん)


AIDLを使用してサービスを実装するハンズオン。


サービスについて知れば知るほど使い道が難しいとおっしゃっていたのが印象的でした。


 講演資料


 プロジェクト一式


「動画再生アプリ」(杉本礼彦)


簡単な動画再生アプリ作成のハンズオンを行いました。うまく再生できるか心配でしたが、うまく行ってよかったです。


 講演資料


 サンプル動画



参加された皆様、どうもありがとうございました。


お疲れ様でした。


4月には弊社は新事務所に引越しいたします。


引越し後には弊社オフィスのあるビルの会議室を利用して


弊社主催でセミナーを開催したいと思います!


よろしくおねがいします。





2009年3月24日火曜日



AndroidでJNIを使う方法をドキュメントにまとめました。


PDF版はこちら


Androidのコンパイル環境を構築されていることが前提です。


よろしければAndroidのコンパイル環境を整える方法にあるPDFのコンパイル環境構築資料をご覧ください。



AndroidでJNI – Android meets JNI


株式会社ブリリアントサービス 勉どろいどチーム 


                   和泉憲二


                   門口敏広


                   藤田竜史





 このドキュメントでは、androidアプリケーション(Dalvik VM)からJNI(Java Native Interface)を使用して、C/C++言語で作成した共有ライブラリのJNIメソッドをコールする、一連の方法について解説します。


開発環境

本ドキュメントでは、以下の開発環境が用意されている事を前提に、説明を進めます。








用意する環境本ドキュメントにおける確認済みの環境
androidアプリケーション開発環境(eclipse + android ADT)WindowsXP SP3上
JDK開発環境WindowsXP SP3上のJDK 1.6.0.12
android build環境*1WindowsXP SP3のVMware上にUbuntu Linux 8.04日本語版で構築

本ドキュメントで作成する、サンプルアプリケーションの説明


androidアプリ側からJNIメソッドをコールし、JNIメソッドより返却された文字列をandroidアプリのTextViewで描画します。







androidアプリケーションJNItestJNIメソッドから返却された文字列をTextViewを使用して画面上に表示する。
共有ライブラリモジュールlibJNItestNativeコールされた戻り値として、文字列を返却する。

また今回作成するネイティブメソッドの仕様は、以下の通りとします。









ネイティブメソッド名getTestStringFromNative
引数なし
戻り値String
説明戻り値として、“from Native Code String”という文字列を返却します。




1.android アプリケーション JNItest の作成

androidアプリケーションの作成

まず、JNIヘッダの生成を行うために、ライブラリのロードとネイティブメソッド定義を含むソースコードを作成します。


eclipseのandroid ADTを使用し、以下の構成で新規プロジェクトの作成を行います。









プロジェクト名JNItest
パッケージ名jp.co.brilliantservice.JNItestPkg
アクティビティー名JNItest
アプリケーション名JNItest

f:id:bs-android:20090324114821p:image


次に、TextViewにJNIメソッドからの返却文字列を設定するために、レイアウトファイル(main.xml)の編集を行います。


パッケージエクスプローラーの [JNItest]-[res]-[layout]-main.xmlを以下のように編集します。



01 : <?xml version="1.0" encoding="utf-8"?>
02 : <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
03 : android:orientation="vertical"
04 : android:layout_width="fill_parent"
05 : android:layout_height="fill_parent"
06 : >
07 : <TextView
08 : android:id="@+id/txtTest"
09 : android:layout_width="fill_parent"
10 : android:layout_height="wrap_content"
11 : />
12 : </LinearLayout>


8行目にandroid id txtTest定義を付加し、ウィザードで自動生成されるhello world文字列の表示を削除します。


次に、JNItest.javaの編集を行います。



01 : package jp.co.brilliantservice.JNItestPkg;
02 :
03 : import android.app.Activity;
04 : import android.os.Bundle;
05 : import android.widget.TextView;
06 :
07 : public class JNItest extends Activity {
08 : static {
09 : // ライブラリをロード
10 : System.loadLibrary("JNItestNative");
11 : }
12 : // ネイティブメソッドを定義
13 : public native String getTestStringFromNative();
14 :
15 : /** Called when the activity is first created. */
16 : @Override
17 : public void onCreate(Bundle savedInstanceState) {
18 : super.onCreate(savedInstanceState);
19 : setContentView(R.layout.main);
20 :
21 : // ネイティブメソッドをコールして文字列を取得
22 : String strText = getTestStringFromNative();
23 :
24 : // 取得文字列をTextViewに設定
25 : TextView txtTest = (TextView)findViewById(R.id.txtTest);
26 : txtTest.setText(strText);
27 : }
28 : }


10行目で共有ライブラリのロードを行います。また、13行目ではネイティブメソッドの定義を行っています。





JNIヘッダファイルの生成

「androidアプリケーションの作成」で、eclipse上でのコンパイルが正常に行われ、以下のディレクトリにJNItest.classが生成されている事を確認します。


JNItest\bin\jp\co\brilliantservice\JNItestPkg\


次に、javah(JDK付属のJNIヘッダ作成ツール)を使用して、JNI実装用のC/C++言語ヘッダを生成します。


コマンドプロンプトを起動し、eclipseプロジェクトのJNItestディレクトリにcd で移動の上、以下のコマンドを実行します。



JNItest>javah -classpath bin -d jni jp.co.brilliantservice.JNItestPkg.JNItest


ディレクトリJNItest\jniにjp_co_brilliantservice_JNItestPkg_JNItest.h が生成されます。このファイルが、JNIヘッダファイルです。



JNIヘッダファイル jp_co_brilliantservice_JNItestPkg_JNItest.h



01 : /* DO NOT EDIT THIS FILE - it is machine generated */
02 : #include <jni.h>
03 : /* Header for class jp_co_brilliantservice_JNItestPkg_JNItest */
04 :
05 : #ifndef _Included_jp_co_brilliantservice_JNItestPkg_JNItest
06 : #define _Included_jp_co_brilliantservice_JNItestPkg_JNItest
07 : #ifdef __cplusplus
08 : extern "C" {
09 : #endif
10 : /*
11 : * Class: jp_co_brilliantservice_JNItestPkg_JNItest
12 : * Method: getTestStringFromNative
13 : * Signature: ()Ljava/lang/String;
14 : */
15 : JNIEXPORT jstring JNICALL Java_jp_co_brilliantservice_JNItestPkg_JNItest_getTestStringFromNative
16 : (JNIEnv *, jobject);
17 :
18 : #ifdef __cplusplus
19 : }
20 : #endif
21 : #endif






2.共有ライブラリ libJNItestNative.so の作成

文字列を返却するメソッドを、android build環境上にC言語で実装します。


その際、「JNIヘッダファイルの生成」 で自動生成した、JNIヘッダで宣言されているJNI関数プロトタイプに合わせて実装します。





本ドキュメントにおける、android build環境(ソースコードツリー)のビルドルート及び共有ライブラリ作成位置は以下の通りとします。








ビルドルート~/mydroid
共有ライブラリ作成位置~/mydroid/external/libJNItestNative
共有ライブラリファイル名libJNItestNative.so

上記共有ライブラリ作成位置には以下のファイルを作成または用意します。本項ではJNIメソッドの実装・Makefileの作成方法について説明します。








JNIメソッドソースファイル名GetTestStringFromNative.c
MakefileAndroid.mk
JNIヘッダファイルjp_co_brilliantservice_JNItestPkg_JNItest.h




JNIメソッドの実装

JNIのメソッドは以下のようなソースになります。


メソッド実行時に、単純に文字列を返却するのみのコードです。



getTestStringFromNative.c



1 : #include "jp_co_brilliantservice_JNItestPkg_JNItest.h"
2 :
3 : JNIEXPORT jstring JNICALL Java_jp_co_brilliantservice_JNItestPkg_JNItest_getTestStringFromNative
4 : ( JNIEnv *env, jobject obj )
5 : {
6 : return (*env)->NewStringUTF(env, (char *)"from Native Code String");
7 : }






Makefile 「Android.mk」の作成

androidの個別ビルド用Makefile 「Android.mk」 の作成を行います。



Android.mk



01 : LOCAL_PATH:= $(call my-dir)
02 :
03 : include $(CLEAR_VARS)
04 :
05 : LOCAL_SRC_FILES := \
06 : getTestStringFromNative.c
07 :
08 : LOCAL_C_INCLUDES := \
09 : $(JNI_H_INCLUDE) \
10 :
11 : LOCAL_MODULE := libJNItestNative
12 :
13 : LOCAL_PRELINK_MODULE := false
14 :
15 : include $(BUILD_SHARED_LIBRARY)



5・6行目にソースファイル名、11行目にライブラリモジュール名を定義しています。


上記をふまえ、androidでJNIを実現する上において、最も注目すべき点は、以下の3点です。




  • JNIヘッダをインクルードするための定義(9行目)

  • prelinkを解除するための定義(13行目)

  • 共有ライブラリをビルドするための定義(15行目)


prelink関連の情報については、後述のNote:でまとめます。





共有ライブラリのビルド

端末コンソールを起動の上、以下のコマンドを実行し、ディレクトリ内のみのビルドを行えるように、~/mydroid/build/ にある、envsetup.sh を評価しておきます。



$cd ~/mydroid
$. build/envsetup.sh


続いて、以下のコマンドを実行し、共有ライブラリ位置のビルドを行います。



$cd external/libJNItestNative/
$mm


ビルドが成功すると、以下のようにログが表示されます。



make: ディレクトリ `/home/kenken/mydroid' に入ります
build/core/product_config.mk:211: WARNING: adding test OTA key
============================================
TARGET_PRODUCT=generic
TARGET_BUILD_VARIANT=eng
TARGET_SIMULATOR=
TARGET_BUILD_TYPE=release
TARGET_ARCH=arm
HOST_ARCH=x86
HOST_OS=linux
HOST_BUILD_TYPE=release
BUILD_ID=
============================================
build/core/main.mk:180: implicitly installing apns-conf_sdk.xml
target thumb C: libJNItestNative <= /home/kenken/mydroid/external/libJNItestNative/getTestStringFromNative.c
target SharedLib: libJNItestNative (out/target/product/generic/obj/SHARED_LIBRARIES/libJNItestNative_intermediates/LINKED/libJNItestNative.so)
target Non-prelinked: libJNItestNative (out/target/product/generic/symbols/system/lib/libJNItestNative.so)
target Strip: libJNItestNative (out/target/product/generic/obj/lib/libJNItestNative.so)
Install: out/target/product/generic/system/lib/libJNItestNative.so
Finding NOTICE files: out/target/product/generic/obj/NOTICE_FILES/hash-timestamp
Combining NOTICE files: out/target/product/generic/obj/NOTICE.html
gzip -c out/target/product/generic/obj/NOTICE.html > out/target/product/generic/obj/NOTICE.html.gz
make: ディレクトリ `/home/kenken/mydroid' から出ます


共有ライブラリ libJNItestNative.so は以下のディレクトリに格納されます。


~mydroid/out/target/product/generic/system/lib/





Note: prelink map 及び、共有ライブラリにおけるprelink定義について

androidの共有ライブラリはデフォルトでprelink mapというテキストファイルに、メモリマップテーブルに固定アドレスでマッピングするように構成されています。


(~/mydroid/build/core/prelink-linux-arm.map)


これは、メモリ上への頻繁なロード・アンロードを避け、速度アップをするための処置となっています。



~/mydroid/build/core/prelink-linux-arm.map (抜粋)



001 :
002 : # 0xC0000000 - 0xFFFFFFFF Kernel
003 : # 0xB0100000 - 0xBFFFFFFF Thread 0 Stack
004 : # 0xB0000000 - 0xB00FFFFF Linker
005 : # 0xA0000000 - 0xBFFFFFFF Prelinked System Libraries
006 : # 0x90000000 - 0x9FFFFFFF Prelinked App Libraries
007 : # 0x80000000 - 0x8FFFFFFF Non-prelinked Libraries
008 : # 0x40000000 - 0x7FFFFFFF mmap'd stuff
009 : # 0x10000000 - 0x3FFFFFFF Thread Stacks
010 : # 0x00000000 - 0x0FFFFFFF .text / .data / heap
011 :
012 : # core system libraries
013 : libdl.so 0xAFF00000



112 : libctest.so 0x9A700000
113 : libUAPI_jni.so 0x9A500000
114 : librpc.so 0x9A400000
115 : libtrace_test.so 0x9A300000
116 : libsrec_jni.so 0x9A200000



上記のように、prelink mapに登録するモジュール名及び固定アドレスを列挙して定義を行います。


しかし、固定アドレスにマッピングされるという事は、ビルドの度にシステムイメージまで作成し、入れ替えないといけないという事を意味しています。


これではJNIを使用するアプリケーションはインストールを自由に行うことが極めて困難であると言わざるを得ません。


Android.mkでは、デフォルト動作がprelink map有効となっており、prelink mapに共有ライブラリを登録しないと、ビルドエラーが発生してしまいます。



ビルドエラーの例



01 : ~/mydroid/external/libJNItestNative$ mm
02 : make: ディレクトリ `/home/kenken/mydroid' に入ります
03 : build/core/product_config.mk:211: WARNING: adding test OTA key
04 : ============================================
05 : TARGET_PRODUCT=generic
06 : TARGET_BUILD_VARIANT=eng
07 : TARGET_SIMULATOR=
08 : TARGET_BUILD_TYPE=release
09 : TARGET_ARCH=arm
10 : HOST_ARCH=x86
11 : HOST_OS=linux
12 : HOST_BUILD_TYPE=release
13 : BUILD_ID=
14 : ============================================
15 : build/core/main.mk:180: implicitly installing apns-conf_sdk.xml
16 : target thumb C: libJNItestNative <= /home/kenken/mydroid/external/libJNItestNative/getTestStringFromNative.c
17 : target SharedLib: libJNItestNative (out/target/product/generic/obj/SHARED_LIBRARIES/libJNItestNative_intermediates/LINKED/libJNItestNative.so)
18 : target Prelink: libJNItestNative (out/target/product/generic/symbols/system/lib/libJNItestNative.so)
19 : build/tools/apriori/prelinkmap.c(137): library 'libJNItestNative.so' not in prelink map
20 : make: *** [out/target/product/generic/symbols/system/lib/libJNItestNative.so] エラー 1
21 : make: ディレクトリ `/home/kenken/mydroid' から出ます



上記のビルドエラーの場合、19行目に、「prelink mapに含まれていない」(library 'libJNItestNative.so' not in prelink map)というエラーが確認できます。


prelink mapに登録せず、ビルドを行うためには、Android.mkに以下の1行を追加し、ビルドを行います。(prelink 無効化の定義)



LOCAL_PRELINK_MODULE := false





3.アプリケーションの実行

androidアプリ実行の前に、共有ライブラリ libJNItestNative.so を、あらかじめエミュレータの/sysytem/lib ディレクトリにコピーします。


1. コマンドプロンプトを起動し、androidエミュレータを以下のコマンドで起動します。



>start emulator


2. エミュレータ上のディレクトリ /system/lib への書き込みを有効にするために、以下のコマンドを実行します。



>adb remount


3. 共有ライブラリを /system/lib ディレクトリにコピーします。カレントディレクトリに、「2. 共有ライブラリ libJNItestNative.so の作成」で作成したモジュールをあらかじめ用意した上、以下のコマンドを実行します。



>adb push libJNItestNative.so /system/lib


4. androidエミュレータの起動を維持したままの状態で、eclipseからandroidアプリJNItestを


起動します。


起動に成功すると、以下のように実行結果が表示されます。


f:id:bs-android:20090324120809p:image



以上です。


もし、記述間違いなどがありましたらご指摘いただけると幸いです。




*1:androidのソースコードツリーでシステムイメージがbuild出来る環境。ソースの入手方法・ビルド環境構築方法については、こちらを参照。





AndroidでJNIを使う方法



AndroidでJNIを使う方法をドキュメントにまとめました。


PDF版はこちら


Androidのコンパイル環境を構築されていることが前提です。


よろしければAndroidのコンパイル環境を整える方法にあるPDFのコンパイル環境構築資料をご覧ください。



AndroidでJNI – Android meets JNI


株式会社ブリリアントサービス 勉どろいどチーム 


                   和泉憲二


                   門口敏広


                   藤田竜史





 このドキュメントでは、androidアプリケーション(Dalvik VM)からJNI(Java Native Interface)を使用して、C/C++言語で作成した共有ライブラリのJNIメソッドをコールする、一連の方法について解説します。


開発環境

本ドキュメントでは、以下の開発環境が用意されている事を前提に、説明を進めます。








用意する環境本ドキュメントにおける確認済みの環境
androidアプリケーション開発環境(eclipse + android ADT)WindowsXP SP3上
JDK開発環境WindowsXP SP3上のJDK 1.6.0.12
android build環境*1WindowsXP SP3のVMware上にUbuntu Linux 8.04日本語版で構築

本ドキュメントで作成する、サンプルアプリケーションの説明


androidアプリ側からJNIメソッドをコールし、JNIメソッドより返却された文字列をandroidアプリのTextViewで描画します。







androidアプリケーションJNItestJNIメソッドから返却された文字列をTextViewを使用して画面上に表示する。
共有ライブラリモジュールlibJNItestNativeコールされた戻り値として、文字列を返却する。

また今回作成するネイティブメソッドの仕様は、以下の通りとします。









ネイティブメソッド名getTestStringFromNative
引数なし
戻り値String
説明戻り値として、“from Native Code String”という文字列を返却します。




1.android アプリケーション JNItest の作成

androidアプリケーションの作成

まず、JNIヘッダの生成を行うために、ライブラリのロードとネイティブメソッド定義を含むソースコードを作成します。


eclipseのandroid ADTを使用し、以下の構成で新規プロジェクトの作成を行います。









プロジェクト名JNItest
パッケージ名jp.co.brilliantservice.JNItestPkg
アクティビティー名JNItest
アプリケーション名JNItest

f:id:bs-android:20090324114821p:image


次に、TextViewにJNIメソッドからの返却文字列を設定するために、レイアウトファイル(main.xml)の編集を行います。


パッケージエクスプローラーの [JNItest]-[res]-[layout]-main.xmlを以下のように編集します。



01 : <?xml version="1.0" encoding="utf-8"?>
02 : <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
03 : android:orientation="vertical"
04 : android:layout_width="fill_parent"
05 : android:layout_height="fill_parent"
06 : >
07 : <TextView
08 : android:id="@+id/txtTest"
09 : android:layout_width="fill_parent"
10 : android:layout_height="wrap_content"
11 : />
12 : </LinearLayout>


8行目にandroid id txtTest定義を付加し、ウィザードで自動生成されるhello world文字列の表示を削除します。


次に、JNItest.javaの編集を行います。



01 : package jp.co.brilliantservice.JNItestPkg;
02 :
03 : import android.app.Activity;
04 : import android.os.Bundle;
05 : import android.widget.TextView;
06 :
07 : public class JNItest extends Activity {
08 : static {
09 : // ライブラリをロード
10 : System.loadLibrary("JNItestNative");
11 : }
12 : // ネイティブメソッドを定義
13 : public native String getTestStringFromNative();
14 :
15 : /** Called when the activity is first created. */
16 : @Override
17 : public void onCreate(Bundle savedInstanceState) {
18 : super.onCreate(savedInstanceState);
19 : setContentView(R.layout.main);
20 :
21 : // ネイティブメソッドをコールして文字列を取得
22 : String strText = getTestStringFromNative();
23 :
24 : // 取得文字列をTextViewに設定
25 : TextView txtTest = (TextView)findViewById(R.id.txtTest);
26 : txtTest.setText(strText);
27 : }
28 : }


10行目で共有ライブラリのロードを行います。また、13行目ではネイティブメソッドの定義を行っています。





JNIヘッダファイルの生成

「androidアプリケーションの作成」で、eclipse上でのコンパイルが正常に行われ、以下のディレクトリにJNItest.classが生成されている事を確認します。


JNItest\bin\jp\co\brilliantservice\JNItestPkg\


次に、javah(JDK付属のJNIヘッダ作成ツール)を使用して、JNI実装用のC/C++言語ヘッダを生成します。


コマンドプロンプトを起動し、eclipseプロジェクトのJNItestディレクトリにcd で移動の上、以下のコマンドを実行します。



JNItest>javah -classpath bin -d jni jp.co.brilliantservice.JNItestPkg.JNItest


ディレクトリJNItest\jniにjp_co_brilliantservice_JNItestPkg_JNItest.h が生成されます。このファイルが、JNIヘッダファイルです。



JNIヘッダファイル jp_co_brilliantservice_JNItestPkg_JNItest.h



01 : /* DO NOT EDIT THIS FILE - it is machine generated */
02 : #include <jni.h>
03 : /* Header for class jp_co_brilliantservice_JNItestPkg_JNItest */
04 :
05 : #ifndef _Included_jp_co_brilliantservice_JNItestPkg_JNItest
06 : #define _Included_jp_co_brilliantservice_JNItestPkg_JNItest
07 : #ifdef __cplusplus
08 : extern "C" {
09 : #endif
10 : /*
11 : * Class: jp_co_brilliantservice_JNItestPkg_JNItest
12 : * Method: getTestStringFromNative
13 : * Signature: ()Ljava/lang/String;
14 : */
15 : JNIEXPORT jstring JNICALL Java_jp_co_brilliantservice_JNItestPkg_JNItest_getTestStringFromNative
16 : (JNIEnv *, jobject);
17 :
18 : #ifdef __cplusplus
19 : }
20 : #endif
21 : #endif






2.共有ライブラリ libJNItestNative.so の作成

文字列を返却するメソッドを、android build環境上にC言語で実装します。


その際、「JNIヘッダファイルの生成」 で自動生成した、JNIヘッダで宣言されているJNI関数プロトタイプに合わせて実装します。





本ドキュメントにおける、android build環境(ソースコードツリー)のビルドルート及び共有ライブラリ作成位置は以下の通りとします。








ビルドルート~/mydroid
共有ライブラリ作成位置~/mydroid/external/libJNItestNative
共有ライブラリファイル名libJNItestNative.so

上記共有ライブラリ作成位置には以下のファイルを作成または用意します。本項ではJNIメソッドの実装・Makefileの作成方法について説明します。








JNIメソッドソースファイル名GetTestStringFromNative.c
MakefileAndroid.mk
JNIヘッダファイルjp_co_brilliantservice_JNItestPkg_JNItest.h




JNIメソッドの実装

JNIのメソッドは以下のようなソースになります。


メソッド実行時に、単純に文字列を返却するのみのコードです。



getTestStringFromNative.c



1 : #include "jp_co_brilliantservice_JNItestPkg_JNItest.h"
2 :
3 : JNIEXPORT jstring JNICALL Java_jp_co_brilliantservice_JNItestPkg_JNItest_getTestStringFromNative
4 : ( JNIEnv *env, jobject obj )
5 : {
6 : return (*env)->NewStringUTF(env, (char *)"from Native Code String");
7 : }






Makefile 「Android.mk」の作成

androidの個別ビルド用Makefile 「Android.mk」 の作成を行います。



Android.mk



01 : LOCAL_PATH:= $(call my-dir)
02 :
03 : include $(CLEAR_VARS)
04 :
05 : LOCAL_SRC_FILES := \
06 : getTestStringFromNative.c
07 :
08 : LOCAL_C_INCLUDES := \
09 : $(JNI_H_INCLUDE) \
10 :
11 : LOCAL_MODULE := libJNItestNative
12 :
13 : LOCAL_PRELINK_MODULE := false
14 :
15 : include $(BUILD_SHARED_LIBRARY)



5・6行目にソースファイル名、11行目にライブラリモジュール名を定義しています。


上記をふまえ、androidでJNIを実現する上において、最も注目すべき点は、以下の3点です。




  • JNIヘッダをインクルードするための定義(9行目)

  • prelinkを解除するための定義(13行目)

  • 共有ライブラリをビルドするための定義(15行目)


prelink関連の情報については、後述のNote:でまとめます。





共有ライブラリのビルド

端末コンソールを起動の上、以下のコマンドを実行し、ディレクトリ内のみのビルドを行えるように、~/mydroid/build/ にある、envsetup.sh を評価しておきます。



$cd ~/mydroid
$. build/envsetup.sh


続いて、以下のコマンドを実行し、共有ライブラリ位置のビルドを行います。



$cd external/libJNItestNative/
$mm


ビルドが成功すると、以下のようにログが表示されます。



make: ディレクトリ `/home/kenken/mydroid' に入ります
build/core/product_config.mk:211: WARNING: adding test OTA key
============================================
TARGET_PRODUCT=generic
TARGET_BUILD_VARIANT=eng
TARGET_SIMULATOR=
TARGET_BUILD_TYPE=release
TARGET_ARCH=arm
HOST_ARCH=x86
HOST_OS=linux
HOST_BUILD_TYPE=release
BUILD_ID=
============================================
build/core/main.mk:180: implicitly installing apns-conf_sdk.xml
target thumb C: libJNItestNative <= /home/kenken/mydroid/external/libJNItestNative/getTestStringFromNative.c
target SharedLib: libJNItestNative (out/target/product/generic/obj/SHARED_LIBRARIES/libJNItestNative_intermediates/LINKED/libJNItestNative.so)
target Non-prelinked: libJNItestNative (out/target/product/generic/symbols/system/lib/libJNItestNative.so)
target Strip: libJNItestNative (out/target/product/generic/obj/lib/libJNItestNative.so)
Install: out/target/product/generic/system/lib/libJNItestNative.so
Finding NOTICE files: out/target/product/generic/obj/NOTICE_FILES/hash-timestamp
Combining NOTICE files: out/target/product/generic/obj/NOTICE.html
gzip -c out/target/product/generic/obj/NOTICE.html > out/target/product/generic/obj/NOTICE.html.gz
make: ディレクトリ `/home/kenken/mydroid' から出ます


共有ライブラリ libJNItestNative.so は以下のディレクトリに格納されます。


~mydroid/out/target/product/generic/system/lib/





Note: prelink map 及び、共有ライブラリにおけるprelink定義について

androidの共有ライブラリはデフォルトでprelink mapというテキストファイルに、メモリマップテーブルに固定アドレスでマッピングするように構成されています。


(~/mydroid/build/core/prelink-linux-arm.map)


これは、メモリ上への頻繁なロード・アンロードを避け、速度アップをするための処置となっています。



~/mydroid/build/core/prelink-linux-arm.map (抜粋)



001 :
002 : # 0xC0000000 - 0xFFFFFFFF Kernel
003 : # 0xB0100000 - 0xBFFFFFFF Thread 0 Stack
004 : # 0xB0000000 - 0xB00FFFFF Linker
005 : # 0xA0000000 - 0xBFFFFFFF Prelinked System Libraries
006 : # 0x90000000 - 0x9FFFFFFF Prelinked App Libraries
007 : # 0x80000000 - 0x8FFFFFFF Non-prelinked Libraries
008 : # 0x40000000 - 0x7FFFFFFF mmap'd stuff
009 : # 0x10000000 - 0x3FFFFFFF Thread Stacks
010 : # 0x00000000 - 0x0FFFFFFF .text / .data / heap
011 :
012 : # core system libraries
013 : libdl.so 0xAFF00000



112 : libctest.so 0x9A700000
113 : libUAPI_jni.so 0x9A500000
114 : librpc.so 0x9A400000
115 : libtrace_test.so 0x9A300000
116 : libsrec_jni.so 0x9A200000



上記のように、prelink mapに登録するモジュール名及び固定アドレスを列挙して定義を行います。


しかし、固定アドレスにマッピングされるという事は、ビルドの度にシステムイメージまで作成し、入れ替えないといけないという事を意味しています。


これではJNIを使用するアプリケーションはインストールを自由に行うことが極めて困難であると言わざるを得ません。


Android.mkでは、デフォルト動作がprelink map有効となっており、prelink mapに共有ライブラリを登録しないと、ビルドエラーが発生してしまいます。



ビルドエラーの例



01 : ~/mydroid/external/libJNItestNative$ mm
02 : make: ディレクトリ `/home/kenken/mydroid' に入ります
03 : build/core/product_config.mk:211: WARNING: adding test OTA key
04 : ============================================
05 : TARGET_PRODUCT=generic
06 : TARGET_BUILD_VARIANT=eng
07 : TARGET_SIMULATOR=
08 : TARGET_BUILD_TYPE=release
09 : TARGET_ARCH=arm
10 : HOST_ARCH=x86
11 : HOST_OS=linux
12 : HOST_BUILD_TYPE=release
13 : BUILD_ID=
14 : ============================================
15 : build/core/main.mk:180: implicitly installing apns-conf_sdk.xml
16 : target thumb C: libJNItestNative <= /home/kenken/mydroid/external/libJNItestNative/getTestStringFromNative.c
17 : target SharedLib: libJNItestNative (out/target/product/generic/obj/SHARED_LIBRARIES/libJNItestNative_intermediates/LINKED/libJNItestNative.so)
18 : target Prelink: libJNItestNative (out/target/product/generic/symbols/system/lib/libJNItestNative.so)
19 : build/tools/apriori/prelinkmap.c(137): library 'libJNItestNative.so' not in prelink map
20 : make: *** [out/target/product/generic/symbols/system/lib/libJNItestNative.so] エラー 1
21 : make: ディレクトリ `/home/kenken/mydroid' から出ます



上記のビルドエラーの場合、19行目に、「prelink mapに含まれていない」(library 'libJNItestNative.so' not in prelink map)というエラーが確認できます。


prelink mapに登録せず、ビルドを行うためには、Android.mkに以下の1行を追加し、ビルドを行います。(prelink 無効化の定義)



LOCAL_PRELINK_MODULE := false





3.アプリケーションの実行

androidアプリ実行の前に、共有ライブラリ libJNItestNative.so を、あらかじめエミュレータの/sysytem/lib ディレクトリにコピーします。


1. コマンドプロンプトを起動し、androidエミュレータを以下のコマンドで起動します。



>start emulator


2. エミュレータ上のディレクトリ /system/lib への書き込みを有効にするために、以下のコマンドを実行します。



>adb remount


3. 共有ライブラリを /system/lib ディレクトリにコピーします。カレントディレクトリに、「2. 共有ライブラリ libJNItestNative.so の作成」で作成したモジュールをあらかじめ用意した上、以下のコマンドを実行します。



>adb push libJNItestNative.so /system/lib


4. androidエミュレータの起動を維持したままの状態で、eclipseからandroidアプリJNItestを


起動します。


起動に成功すると、以下のように実行結果が表示されます。


f:id:bs-android:20090324120809p:image



以上です。


もし、記述間違いなどがありましたらご指摘いただけると幸いです。




*1:androidのソースコードツリーでシステムイメージがbuild出来る環境。ソースの入手方法・ビルド環境構築方法については、こちらを参照。







VMWareとUbuntuを使ってWindows上でAndroidのコンパイル環境を整える方法を書いたドキュメントをPDFで用意しました。


スクリーンショットが多く、82ページある為、今回はエントリのほうには書きません。


Windows側とUbuntuとのファイル共有方法も盛り込んであります。





Androidのコンパイル環境を整える方法



VMWareとUbuntuを使ってWindows上でAndroidのコンパイル環境を整える方法を書いたドキュメントをPDFで用意しました。


スクリーンショットが多く、82ページある為、今回はエントリのほうには書きません。


Windows側とUbuntuとのファイル共有方法も盛り込んであります。





2009年3月22日日曜日



f:id:bs-android:20090322095729p:image


3/19、20に開催されたAndroid Hackathon(ハッカソン)にチューターとして参加させていただきました。


3/10、11にIdeathon(アイディアソン)として事前ミーティングも実施されており、3/10のミーティングにも参加させていただいています。


今回はITファームさんが協賛しており、よいアイディアがあれば会社設立や投資も行ってくれるという夢のあるイベントになっていました。


Ideathon 3/10


3/19のHackathonの事前ミーティングです。


全員参加必須ではありませんでしたが、ほとんどの方が出席していました。


事前に決められていた



1. News & Weather


2. Specific Device


3. Multimedia


4. Tutorial


5. Lifestyle & Travel



のリストから各自参加するカテゴリを選び、各カテゴリに集まった人どうしでアイディアを考えます。


そして各アイディア毎にプレゼンを行い、当日のトップアイディアを決めるという流れです。


当日出たアイディアは



Lifestyle & Travel

 位置情報と行動履歴を基にしたアプリケーション。次の予定にどのような経路で行くべきかを現在位置を参考にナビゲートしてくれる。


Multimedia

 タッチ操作による画像のスライドショー。コメント入力機能もあり。端末を回転させると文字も追従する。


News & Weather

 画面を見ないで使えるRSSリーダー。Listen& Shake


Specific Device

 モーションジェスチャーのライブラリ化。モーションジェスチャーを利用した、アプリケーション。特定動作で撮影した画像を特定のあて先に送信する、など。


Tutorial

 加速度センサーを利用した占いアプリケーション。



という内容でした。


この作業が終わっていれば、当日まで他のメンバーと作業できる為、事前にかなり作業を進めておくことが出来ます。


去年Hackathonに参加した時は、作成するアプリを決めるだけでかなりの時間をとられてしまい、アプリを作っている時間がほとんど取れなかった為、事前にIdeathonを行っておくのは当日のアプリ製作に時間が割けるので、非常によい構成だと思います。





そして、この日は日本Androidの会から参加したチューターが、一人ずつ各カテゴリのテーブルに分かれてアドバイスを行いました。


私はSpecific Deviceチームのテーブルで一緒にアイディアを考えていました。


30分という短い時間でアイディアを考え、各チームそれぞれアイディアをプレゼンしていきました。


そして投票でトップアイディアが決まったのですが、トップはなんと私が担当していたSpecific Deviceチームでした。


みんなと一緒に、景品としてTシャツをいただきました!


f:id:bs-android:20090322103138j:image


Hackathon 3/19


 Hackathon1日目です。事前に行われたIdeathonで出たアイディアを元にアプリ作成を行います。


当日はHackathon-jpのGoogle Codeのサイトを使い、Subversionでコード共有を行って開発を行いました。


SubclipseというEclipseのSubversionプラグインがオススメということでしたが、インストールしているEclipseの種類によってはインストールが上手くいかない場合が結構ありました。


今後Hackathonに参加される方は事前にインストールして準備をしておくか、普段からSubversionに慣れておくといいと思います。


※もちろん、コード共有ツールはSubversionしか駄目という訳ではありません。


環境設定もIdeathonで済ませておくと、Hackathon当日もスムーズに開発できるのではないかと思いました。


以下は当日のアプリの一覧です。


Ideathonの時よりも少し増えています。



Tutorial

 ・タロット占い。振るとカードがランダム表示。


 ・万歩計


 ・アプリケーション起動時に現在位置をTwitterに発信。


News & Weather

 ・見ないで使えるインターフェース。ポケットの中で使える。


 ・見ないで使える読み上げインターフェース


 ・朝日コムからRSSフィード読み込み


Multimedia

 音楽つきスライドショー。地名やテロップを表示。


Specific Device

 加速度センサーを利用した、かめはめ波。移動の向きを2次元で認識するところまで。


Lifestyle & Travel

 LifeNavi。Google Calendar の予定をもとにリマンダーとナビゲーション。



この日もSpecific Deviceチームのテーブルに張り付いて、アドバイスや環境構築のサポートを行い、アプリで使う画像データやサウンドデータの作成も担当しました。


Subversionの設定が上手くいかなかったり、加速度センサで常に認識する重力加速度が邪魔になったりと難航しましたが、プレゼンまでには何とか、端末を動かした方向を認識して上下左右斜めの8方向の矢印を表示させるところまで動作させることが出来ました。


そして、トップアプリはTutorialチームの「アプリケーション起動時に現在位置をTwitterに発信するアプリ」が優勝となりました。


Androidくん(正式名称は無いそうです)のぬいぐるみが景品として送られました。


写真を撮ってなかったのは残念。


会場の様子は安生さんのレポートをどうぞ。


この日のお弁当です。


f:id:bs-android:20090322112752j:image


この日のコードは


Android20090319から閲覧できます。


Hackathon 3/20


 Hackathon2日目です。(Hackathon1日目とは違う参加者です。)


この日の参加者は休日ということもあって非常に多かったです。


この日開発されたアプリは以下の通りです。



Game

 ・サムライチェス Android 版


Tutorial

 ・トランプシャッフル。手品もできる。


 ・Android 負荷モニタリング


 ・JNI で Hellow World


 ・Google Data APIs の利用を試みた


Social

 ・SNS の Activity をOpenSocialを用いてAndoriodで取得


GPS

 ・ニコンUP + Android(Web Server) を用いたスカウター


Lifestyle

 ・日英・英日テキスト翻訳


Tool

 ・加速度センサーを利用したランチャー。事前に登録したアプリを特定動作で起動。



3/11のIdeathonに参加していなかったのと、各テーブルに顔見知りの猛者がちらばっていた為、この日は全体的なサポートに勤めました。


この日も環境設定でつまずくケースが結構多かったです。


優勝はToolの「加速度センサーを利用したランチャー」アプリでした。


ジェスチャーを認識するサービスを起動させておき、待受け画面などで端末をシェイクすると、ブラウザが起動するというデモが行われ、会場が沸きました。


この日のお弁当


f:id:bs-android:20090322113842j:image


この日のコードは


Android20090320から閲覧できます。


Hackathonを終えて


2日間ともAndroid Devphone 1を所持している方が非常に多かったです。


会場は和気あいあいとした雰囲気で、Hackathonが終わった後も連絡を取り合ったりしており、非常に有意義かつ楽しく過ごせました。


このようなイベントを弊社でも開催したいと常々思っていたので、GoogleのChrisさんにAndroid Devphone 1をカスタマイズするHackathonを弊社で開催したいと申し出たところ、協力していただけるとのことでした。


Chrisさんは4月中はアメリカの為、5月に開催したいと思います!


乞うご期待!!





最後に


2日間ともお弁当おいしかったです!





2009/3/19、20 Android Hackathon レポート



f:id:bs-android:20090322095729p:image


3/19、20に開催されたAndroid Hackathon(ハッカソン)にチューターとして参加させていただきました。


3/10、11にIdeathon(アイディアソン)として事前ミーティングも実施されており、3/10のミーティングにも参加させていただいています。


今回はITファームさんが協賛しており、よいアイディアがあれば会社設立や投資も行ってくれるという夢のあるイベントになっていました。


Ideathon 3/10


3/19のHackathonの事前ミーティングです。


全員参加必須ではありませんでしたが、ほとんどの方が出席していました。


事前に決められていた



1. News & Weather


2. Specific Device


3. Multimedia


4. Tutorial


5. Lifestyle & Travel



のリストから各自参加するカテゴリを選び、各カテゴリに集まった人どうしでアイディアを考えます。


そして各アイディア毎にプレゼンを行い、当日のトップアイディアを決めるという流れです。


当日出たアイディアは



Lifestyle & Travel

 位置情報と行動履歴を基にしたアプリケーション。次の予定にどのような経路で行くべきかを現在位置を参考にナビゲートしてくれる。


Multimedia

 タッチ操作による画像のスライドショー。コメント入力機能もあり。端末を回転させると文字も追従する。


News & Weather

 画面を見ないで使えるRSSリーダー。Listen& Shake


Specific Device

 モーションジェスチャーのライブラリ化。モーションジェスチャーを利用した、アプリケーション。特定動作で撮影した画像を特定のあて先に送信する、など。


Tutorial

 加速度センサーを利用した占いアプリケーション。



という内容でした。


この作業が終わっていれば、当日まで他のメンバーと作業できる為、事前にかなり作業を進めておくことが出来ます。


去年Hackathonに参加した時は、作成するアプリを決めるだけでかなりの時間をとられてしまい、アプリを作っている時間がほとんど取れなかった為、事前にIdeathonを行っておくのは当日のアプリ製作に時間が割けるので、非常によい構成だと思います。





そして、この日は日本Androidの会から参加したチューターが、一人ずつ各カテゴリのテーブルに分かれてアドバイスを行いました。


私はSpecific Deviceチームのテーブルで一緒にアイディアを考えていました。


30分という短い時間でアイディアを考え、各チームそれぞれアイディアをプレゼンしていきました。


そして投票でトップアイディアが決まったのですが、トップはなんと私が担当していたSpecific Deviceチームでした。


みんなと一緒に、景品としてTシャツをいただきました!


f:id:bs-android:20090322103138j:image


Hackathon 3/19


 Hackathon1日目です。事前に行われたIdeathonで出たアイディアを元にアプリ作成を行います。


当日はHackathon-jpのGoogle Codeのサイトを使い、Subversionでコード共有を行って開発を行いました。


SubclipseというEclipseのSubversionプラグインがオススメということでしたが、インストールしているEclipseの種類によってはインストールが上手くいかない場合が結構ありました。


今後Hackathonに参加される方は事前にインストールして準備をしておくか、普段からSubversionに慣れておくといいと思います。


※もちろん、コード共有ツールはSubversionしか駄目という訳ではありません。


環境設定もIdeathonで済ませておくと、Hackathon当日もスムーズに開発できるのではないかと思いました。


以下は当日のアプリの一覧です。


Ideathonの時よりも少し増えています。



Tutorial

 ・タロット占い。振るとカードがランダム表示。


 ・万歩計


 ・アプリケーション起動時に現在位置をTwitterに発信。


News & Weather

 ・見ないで使えるインターフェース。ポケットの中で使える。


 ・見ないで使える読み上げインターフェース


 ・朝日コムからRSSフィード読み込み


Multimedia

 音楽つきスライドショー。地名やテロップを表示。


Specific Device

 加速度センサーを利用した、かめはめ波。移動の向きを2次元で認識するところまで。


Lifestyle & Travel

 LifeNavi。Google Calendar の予定をもとにリマンダーとナビゲーション。



この日もSpecific Deviceチームのテーブルに張り付いて、アドバイスや環境構築のサポートを行い、アプリで使う画像データやサウンドデータの作成も担当しました。


Subversionの設定が上手くいかなかったり、加速度センサで常に認識する重力加速度が邪魔になったりと難航しましたが、プレゼンまでには何とか、端末を動かした方向を認識して上下左右斜めの8方向の矢印を表示させるところまで動作させることが出来ました。


そして、トップアプリはTutorialチームの「アプリケーション起動時に現在位置をTwitterに発信するアプリ」が優勝となりました。


Androidくん(正式名称は無いそうです)のぬいぐるみが景品として送られました。


写真を撮ってなかったのは残念。


会場の様子は安生さんのレポートをどうぞ。


この日のお弁当です。


f:id:bs-android:20090322112752j:image


この日のコードは


Android20090319から閲覧できます。


Hackathon 3/20


 Hackathon2日目です。(Hackathon1日目とは違う参加者です。)


この日の参加者は休日ということもあって非常に多かったです。


この日開発されたアプリは以下の通りです。



Game

 ・サムライチェス Android 版


Tutorial

 ・トランプシャッフル。手品もできる。


 ・Android 負荷モニタリング


 ・JNI で Hellow World


 ・Google Data APIs の利用を試みた


Social

 ・SNS の Activity をOpenSocialを用いてAndoriodで取得


GPS

 ・ニコンUP + Android(Web Server) を用いたスカウター


Lifestyle

 ・日英・英日テキスト翻訳


Tool

 ・加速度センサーを利用したランチャー。事前に登録したアプリを特定動作で起動。



3/11のIdeathonに参加していなかったのと、各テーブルに顔見知りの猛者がちらばっていた為、この日は全体的なサポートに勤めました。


この日も環境設定でつまずくケースが結構多かったです。


優勝はToolの「加速度センサーを利用したランチャー」アプリでした。


ジェスチャーを認識するサービスを起動させておき、待受け画面などで端末をシェイクすると、ブラウザが起動するというデモが行われ、会場が沸きました。


この日のお弁当


f:id:bs-android:20090322113842j:image


この日のコードは


Android20090320から閲覧できます。


Hackathonを終えて


2日間ともAndroid Devphone 1を所持している方が非常に多かったです。


会場は和気あいあいとした雰囲気で、Hackathonが終わった後も連絡を取り合ったりしており、非常に有意義かつ楽しく過ごせました。


このようなイベントを弊社でも開催したいと常々思っていたので、GoogleのChrisさんにAndroid Devphone 1をカスタマイズするHackathonを弊社で開催したいと申し出たところ、協力していただけるとのことでした。


Chrisさんは4月中はアメリカの為、5月に開催したいと思います!


乞うご期待!!





最後に


2日間ともお弁当おいしかったです!





Related Posts Plugin for WordPress, Blogger...