2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Androidアプリケーション技術者認定試験ベーシックの試験範囲の知識をまとめた(14)

Posted at

ネイティブ

NDK

AndroidSDKとNDKを使用していC/C++で開発したネイティブモジュールを同梱させる方法がある

NDKとは

apkファイルにC/C++で開発したネイティブモジュールを同梱できる。
NDK(Natie Development Kit)とはネイティブモジュールをビルドするための開発ツール。

メリット

  1. 新たに開発したネイティブモジュールをAndroidアプリケーションに組み込める
  2. 既存資産でのネイティブモジュールをAndroidアプリケーションに組み込める
  3. パフォーマンスの改善が見込まれるため、負荷の高い(ゲーム開発など)で利用できる

デメリット

  1. NDK単独ではアプリケーションの開発が出来ない
  2. ネイティブモジュールはJavaで開発されたアプリケーションの1モジュールなので他のアプリケーションでは利用できない
  3. ネイティブとJavaのやり取りはJNIを使用するため、JNIによるオーバヘッドを考慮する必要がある。そのため必ず改善するとは限らない
  4. 実行されるターゲット端末のCPUごとにネイティブモジュールを作る必要がある
  5. 使用できるC/C++のライブラリに制限がある。

開発環境

ネイティブモジュールの開発環境

項目 必要な環境
OS Windows XP, Windows Vista以降(+cygwin), Mac OSX, Linux
Java JDK JDK6以降
Android SDK Android SDK 1.5以上
ツール Cygwin: gmake, gcc, Linux: GNU Make, GNU AwkまたはNawk

NDKの開発コンポーネント

ビルドツール

ネイティブモジュールのビルドを簡単にすることが出来るツール類(シェルスクリプト)
NDKの解凍フォルダの/buildフォルダ配下に含まれている。
通常ビルドに使うのは解凍フォルダ直下にあるndk-buildコマンド。

デバッグツール

NDKにはgdbserver1、gdbが含まれており、使用してデバッグが出来る
gdbでデバックできるようにするにはndk-buildでビルドする際に-B NDK_DEBUG=1オプションをつけてビルドし、またアプリケーションのAndroidManifest.xmlでdebuggable="true"を指定しておく。

デバッグ対象のアプリケーションがエミュレータか実機で起動したあと、コマンドラインからndk-gdbコマンドで起動する

クロスコンパイラ

ネイティブモジュールモジュールはターゲットボードに搭載されているCPUアーキテクチャ用のコンパイラでコンパイルしてモジュールを作る必要がある。Android NDK r8ではARM(ARMv5TE, ARM-v7a), MIPS, X86のクロスコンパイラが提供されている。コンパイルオプション(Android.mkファイルの記述)で指定できる

C/C++ライブラリ群

開発に必要なC/C++のライブラリが含まれている
Cはlibc(標準ライブラリ), libm(算術ライブラリ), JNI(Java Native Interface), libz(データの圧縮および伸張機能ライブラリ),liblog(Androidのロギングライブラリ)など
C++はlibstd++が使用できる。コンパイルオプションによってSTLPortベースのC++STLや例外、RTTIがサポートされる
他にOpenGL/ES(3D描画エンジンライブラリ), OpenSL/ES(オーディオライブラリ), OpenMAX(組み込み機器向け汎用ストリーミングメディアライブラリ)、他にAndroidのネイティブアプリケーション用のAPI(ネイティブによるアクティビティ作成や入出力のサブシステム、センサデータアクセス)がサポートされる。

NDKの使い方

NDKを使ってネイティブモジュールを同梱したアプリケーションを作成する手順

  1. Eclipseなどを使ってAndroidアプリプロジェクトを作る
  2. プロジェクトのパス直下にjniフォルダを作成し、その下にAndroid.mkファイルを作成する
  3. 必要であればApplication.mkファイルを作成する
  4. ネイティブコード(C, C++)はjniフォルダ配下に格納する
  5. Android.mkにビルドに必要な設定を記述するLOCAL_MODULEいは作成するネイティブモジュール名, LOCAL_SRC_FILESにはビルド対象のソースコードを設定。
  6. ndk-buildコマンドを実行してネイティブコードをコンパイルしネイティブモジュールをビルド。
  7. 成功すると、プロジェクトのlibs/eabiフォルダが作成される。その中にlib.soが作成される。
  8. Eclipse上でビルドをして、apkファイルを作成する。

Android.mk

ネイティブモジュールを作成するのに必要な設定はこのファイルに設定する。

Android.mkの例

LOCAL_PATH := $(call my-dir) 
include $(CREAR_VARS)
LOCAL_MODULE := hello-ndk
LOCAL_SRC_MODULE := hello-ndk.c
include $(BUILD_SHARED_LIBRARY)

1行目、my-dirはマクロ変数でAndroid.mkファイルの存在するカレントフォルダを指している。ファイルの先頭で必ず設定すること
2行目、変数のクリアを実施する
3行目、ネイティブモジュール名を指定(ファイル名はlibhello-ndk.soのようになる)
4行目、ソースコードファイル名を指定する。複数の場合はスペースで区切る
5行目、共有ライブラリ(.so)を生成する設定をする。BUILD_STATIC_LIBRARYを設定した場合はスタティックライブラリ(.a)の生成が定義できる

Android.mkのその他のモジュール詳細記述変数

変数 説明
TARGET_ARCH ターゲットとするアーキテクチャを指定"arm"
TARGET_PLATFORM ターゲットとするAndroidプラットフォームを指定"android"
TARGET_ARCH_ABI ターゲットとするARMのABIを指定"armeabi":Armv5TE用、"armeabi-v7a":Armv7用
TARGET_ABI $(TARGET_PLATFORM) -$(TARGET_ARCH_ABI)と同義。"android--armeabi"
LOCAL_CPP_EXTENSION C++ファイルの拡張子を設定。".cxx"
LOCAL_C_INCLUDES includeファイルのパスを設定
LOCAL_CFLAGS Cのコンパイルオプションの設定
LOCAL_CXXFLAGS(CPPFLAGS) C++のコンパイルオプションの設定
LOCAL_STATIC_LIBRARIES LOCAL_MODULEとリンクするスタティックライブラリを指定
LOCAL_SHARED_LIBRARIES LOCAL_MODULEとリンクする共有ライブラリを設定
LOCAL_LDLIBS リンカに渡すオプション
LOCAL_ARM_NEON NEON命令の利用を許可するか指定

Application.mkとは

アプリケーションで必要なネイティブモジュールの設定を行うファイル。設定しないオプションがなければ必須ではない。

最小構成としては、APP_PROJECT_PATHを指定するのみ。アプリケーションのルートディレクトリの絶対パスを指定する。

Application.mkでオプション設定をするための変数

変数 説明
APP_MODULES モジュール名の設定(スペース区切りでリスト記述可能)
APP_ABI ABIの設定
APP_PLATFORM アプリケーションプラットフォームの設定

JNI

JNIとは

JNI(Java Native Interface)はJavaとネイティブコードを連携する仕組みである。

JNIの仕組み

ネイティブコードはjni.hで定義されたJNI関数を呼び出してJava仮想マシン機能にアクセスする。
JNIEnv型のJNIインターフェースポインタを用いる。

JNIのインターフェース規約

ネイティブコードがJava仮想マシン機能にアクセスできるように、インターフェース規約が定められている

JNIの型の規約

Javaのプリミティブ型や参照型はネイティブコードでは別名で定義されている。

Javaの型 Javaのシグニチャの型 JNIの型 備考
Boolean Z jboolean 符号なし8ビット
byte B jbyte 符号付き8ビット
char C jchar 符号なし16ビット
short S jshort 符号付き16ビット
int I jint 符号なし32ビット
long J jlong 符号付き32ビット
float F jfloat 32ビット
double D jdouble 64ビット
Objectおよびそのサブクラス Ljava/lang/Object; jobject
java.lang.Class Ljavalang/Class; jclass
java.lang.String Ljava/lang/String; jstring
Object[] [Ljava/lang/Object; jobjectArray
boolean[] [Z jbooleanArray
byte[] [B jbyteArray
char[] [C jcharArray
short[] [S jshortArray
int[] [I jintArray
long[] [J jlongArray
float[] [F jfloatArray
double[] [D jdoubleArray
void V

Javaのシグニチャとは、メソッド名、引数の個数、各引数の型の組み合わせのこと。Javaのクラスで定義したメソッドのシグニチャはjavap -s コマンドで確認できる

JNIのメソッド命名規約

JavaのクラスからネイティブのJNIメソッドを呼び出す場合はnaitive修飾子を用いてネイティブのJNIメソッドを宣言する

呼び出されるネイティブメソッドは、Java_<呼び出し元Javaのクラスの完全修飾名を.でなく_でつないだもの>_<ネイティブメソッド名>となる。ex. Java_ace_sample_jni_SampleJni_getName(){}

Javaのクラスで宣言したネイティブメソッド名はJDKのjavahツールでヘッダファイルを作成することで確認できる

JNIのメソッド引数

JNIのネイティブメソッドの第一引数と第二引数は決まっている。
第一引数はJNIEnv型のポインタ、第二引数はjobject型(呼び出し元Javaクラスのインスタンス参照値)またはjclass型(呼び出し元のJavaクラスのclassオブジェクト)が渡される。
ネイティブメソッドの引数がある場合は第三引数以降に記述する。

JNI関数

JNIEnv型のポインタで使用できるJNI関数の一部

JNI関数 説明 引数
jstring NewStringUTF(JNIEnv *env, const char *bytes:) UTF-8にエンコードした文字列の参照ポインタからjava.lang.Stringオブジェクトを生成
void REleaseStringUTFChars(JINEnv env, jstring string, char bytes): 確保した文字列配列のメモリを解放
jintArray NewIntArray(JNIEnv *env, jsize length): int配列を生成
void ReleaseIntArrayElements(JNIEnv env, jinitArray array, jint elems, jint mode): 確保したint配列のメモリを開放する
jclass FindClass(JNIEnv *env, const char *name): クラス名からjclassを取得
jclass GetObjectClass(JNIEnv *env, jobject obj): Java classオブジェクト取得
jmethodID GetMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig): メソッドのIDを取得
jmethodID GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig) StaticメソッドのIDを取得
NativeType Call<type>Method(JNIEnv *env, jobject obj, jmethodID methodID, ...: メソッドIDが示すJavaのメソッドを呼び出す。<type>はメソッドの戻り値の型名。NativeTypeはメソッド戻り値の型のJNIの別名定義の型
NativeType CallStatic<type>Method(JNEnv *env, jclass clazz, jmethodID methodID, ...): メソッドIDが示すJavaのstaticメソッドを呼び出す。<type>はメソッドの戻り値の型名。NativeTypeはメソッド戻り値の型のJNIの別名定義の型

ネイティブコードではメモリ管理を自分で行う必要がある。使用後は明示的に開放すること。

仮想マシン(VM)の参照

JNIEnv型のポインタはネイティブメソッドの呼び出しの間だけ有効。呼び出し以外のネイティブコードでJNIEnv型のポインタを使いたい場合は、何らかの方法で取得する必要がある。
通常のJavaの場合はJINI_CreateJavaVMメソッドを使用することでできるが、AndroidのDalvikVMではできない。
スレッドを生成し、その中でAttachCurrentThreadメソッドを使用することで取得する。不要になったら明示的にDetachCurrentThreadメソッドを呼び出して切断する。すでにVMに接続済みであればGetEnvメソッドで取得できる。

AttatchCurrentThreadメソッドによる接続には、JavaVMの参照ポインタが必要となる。参照ポインタはJNI_OnLoadメソッドで取得しておく。このメソッドはJavaでSystem.loadLivraryが実行されるタイミングで呼ばれる関数である。

JNI_OnLoadとJNI_OnUnLoad

JNI_OnLoadはオプションで提供されている関数。ネイティブライブラリ内に記述しておくことで、Java側でSystem.loadLibraryが実行された際に呼ばれるのでネイティブの初期化処理をするのに適している。
JNI_OnUnLoadも同様で、ガベージコレクションされる際にVMから呼ばれるので、メモリの開放やVMとの切断処理などを実装するのに適している。


ASE

ASEとは

ASE(Android Scripting Environment)とはAndroid端末上でスクリプト言語の編集や実行を可能にする環境。
SL4A(Scripting Layer for Android)というものが開発されている。

ASEでサポートされているスクリプト言語(2012年5月時点)

  • BeanShell
  • JRuby
  • Lua
  • PHP
  • Perl
  • Python
  • Rhino(JavaScriptのインタプリタ)
  • シェルスクリプト(bsh)

ASEでサポートされているスクリプト言語からはAndroidフレームワークのAPI(Intentの利用やActivityの起動、電話やSMSの発信、バーコードのスキャン、位置情報やセンサデータの取得)にアクセスできる。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?