ここから本文です

この知恵ノートを「知恵コレクション」に追加しました。

追加した知恵ノートはMy知恵袋の「知恵コレクション」ページで確認できます。

知恵コレクション」に登録済みです。

再登録しました。

追加に失敗しました。

ノートに戻り、もう一度やり直してください。

すでに1,000件のノートが登録されています。

新しく追加したい場合は、My知恵袋の「知恵コレクション」ページで登録されているノートを削除してください。

追加できませんでした。

ノートは削除されました。

Android NDKを使った開発環境の構築

ライターさん(最終更新日時:2014/3/16)投稿日:

  • ナイス!:

    7

  • 閲覧数:72550

印刷用のページを表示する

Android NDKとは

Android NDK(Native Development Kit)とは、Androidアプリケーションの一部または全部をC/C++言語で開発するためのキットです。Java言語で作られたプログラムは仮想マシン上で実行されるため、どうしてもオーバーヘッドが生じます。そこで、速度の要求が厳しい部分についてはC/C++言語で記述した関数で処理することで、高効率なアプリケーション開発を行うことができます。また、数学ライブラリやOpenGLなどのマルチメディアAPIに対応しているため、これらを活用したアプリケーションの開発も可能になります。


かつては、Windows上でNDKを用いた開発を行うためには、CygwinをインストールしてLinuxエミュレーション環境を作る必要がありました。現在でも、その方法で環境構築を紹介している書籍もあるかと思います。しかし、EclipseとNDKを連携するプラグインが公開され、EclipseのみでNDKを用いたアプリケーションの開発が可能になりました。


なお、このノートは既にAndroid SDKによるアプリケーション開発環境の構築を終えている人に向けて記しています。 これから開発環境を構築したい方は、下記拙筆ノートをご参照ください。



開発環境

Android NDKのダウンロードとインストール

http://developer.android.com/tools/sdk/ndk/index.html

Android NDKは、SDKと同じくAndroid Developersのサイトからダウンロードできます。上記のアドレスから、お使いのPCのプラットフォーム(32bitか64bitか)に合ったリンクをクリックしてダウンロードしましょう。インストーラーは存在しません。任意の場所に解凍するだけです。 

1.png


NDKプラグインのインストール

まず、EclipseにAndroid NDT(Native Development Tools)プラグインをインストールします。なお、ADTプラグイン同梱版で環境構築をした場合は、NDTプラグインも既に導入されていますので、この作業はスキップしてください。


Eclipseの「ヘルプ」から「新規ソフトウェアのインストール」を選択します。SDK開発環境を構築したときのADTプラグインの場所を選べば、リストに「NDK Plugins」がありますので、これを選択してインストールします。なお、NDTプラグインはEclipseのC/C++ Development Tools(CDT)プラグインに依存しているため、CDTプラグインが入っていない場合は同時にインストールすることが求められます。インストール後、Eclipseを再起動します。 

2.png


Eclipseの設定

メニューの「ウィンドウ」から「設定」を選び、「Android」のリストを展開して「NDK」を選ぶと、NDKの場所を入力するようになっています。圧縮ファイルを解凍した場所を指定してください。 

3.png


これで環境構築は完了です。呆気無いほど簡単です。  


簡単なアプリケーションの作成

プロジェクトの作成

NDKを使った簡単なアプリケーションを作ってみましょう。通常のアプリケーション開発を始めるときと同じく、Androidアプリケーションプロジェクトを新規作成します。ここでは、以下の画面のような設定としました。NDKはAPIレベルとの依存性が強いため、最小必須SDK、ターゲット、「次でコンパイル」を全てAPI 10(Android 2.3.3)に設定しました。「次でコンパイル」がこのレベルだとテーマを使用できないので、Noneを選択しています。この画面以降は、すべてデフォルト設定のままとしました。なお、この設定でアプリケーションを作成しても、2.3.3以降のプラットフォームでも正常動作します。 

4.png


注意

  • Android SDK Platformは、APIレベルごとにコンパイラが含まれています。「次でコンパイル」(日本語化していなければ「Compile With」)は、このアプリケーションに使用するコンパイラを選択するものです。このため、低いAPIレベルを選択すると、そのコンパイラが持っていない機能を利用することは当然できません。上記のテーマの選択でエラーになるのもそのためです。Androidのコンパイラは過去のAPIレベルと互換性があるとされているので、通常はその時点でインストールされている最新のAPIレベルを選択すれば問題はありません。


レイアウト

レイアウトは次のようにButtonを2個とTextViewを2個配置したものとします。Buttonにはbutton1とbutton2、TextViewにはtextview1とtextview2というIDを与えています。 

5.png


Native Supportの設定

プロジェクト・エクスプローラーのプロジェクト名の上でマウスを右クリックし、「Androidツール」のサブメニューから「Add Native Support」を選択します。 

6.png


すると、次のようなダイアログが表示されます。デフォルトではプロジェクト名がそのまま入っています。ここではすべて小文字に書き換えましたが、大文字が入ってはいけないという制約はありませんので、そのままでも構いません。 

7.png


完了すると、下図のようにjniというフォルダーが追加され、ライブラリ名として入力した名前の拡張子がcppになったファイルと、Android.mkというファイルが用意されます。このAndroid.mkには、先のダイアログで設定したlibndksample.soというライブラリーファイルを生成するためのルールが記述されています。 

8.png


注意

  • 「Add Native Support」を実行したときに、Eclipseのコンソールに下図のようなエラーメッセージが表示されますが、これは無視しても問題ありません。cygpathとは、Cygwinに含まれているパスの表記をWindows形式とLinux形式に相互変換するためのコマンドの名前ですが、NDTプラグインを利用してコンパイルするに当たってはこのコマンドは必要ありません。これはCygwinを必要としていたときの名残りと思われます。 9.png

Javaのソースコード

Javaのソースコード


MainActivity.javaのソースは次の通りです。


package com.example.ndksample;


import android.app.Activity;

import android.os.Bundle;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.TextView;


public class MainActivity extends Activity implements OnClickListener {


    TextView text1, text2;

    Button btn1, btn2;

    final String[] msgList = 

        { "日本", "アメリカ", "イギリス", "フランス", "ロシア", "中国" };

    int count = 0;


    static {

        System.loadLibrary("ndksample");

    }


    public native String msgFromNDK(int count);


    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        text1 = (TextView) findViewById(R.id.textView1);

        text1.setText(msgList[0]);


        text2 = (TextView) findViewById(R.id.textView2);

        text2.setText("");


        btn1 = (Button) findViewById(R.id.button1);

        btn1.setText("Java");

        btn1.setOnClickListener(this);


        btn2 = (Button) findViewById(R.id.button2);

        btn2.setText("Navite");

        btn2.setOnClickListener(this);

    }


    @Override

    public void onClick(View v) {

        if (v.getId() == R.id.button1) {

            text1.setText(msgFromJava());

        } else {

            text2.setText(msgFromNDK(count));

        }

    }


    String msgFromJava() {

        String msg = new String();

        if (++count >= msgList.length) {

            count = 0;

        }

        msg = msgList[count];

        return msg;

    }

}  


System.loadLibrary()の引数には、呼び出すライブラリーファイルの頭のlibと拡張子部分を除いた文字列を記述します。また、native修飾子を付けたメソッドが、C/C++で記述する関数となります。ここまで記述して、一旦ソースファイルを保存します。


C/C++ヘッダーファイルを作成

JavaとC/C++(或いはその他の言語)によるプログラムの間で相互に連携をするためには、JNI(Java Native Interface)という仕様に沿う必要があります。この仕様では、C/C++側の関数名は頭にJava_を付け、その後ろにパッケージ名、クラス名、メソッド名を並べ、ドットをアンダーバーに置き換えた名前にします。前述のようなJavaソースであれば、msgFromNDKメソッドに対応する関数名は


Java_com_example_ndksample_MainActivity_msgFromNDK


のようになります。今回のようにメソッドが1つだけであれば手入力でも良いのですが、大量のメソッド、複数のパッケージに渡るアプリケーションとなると、これだけでも大変な作業になります。そこで、JDKに含まれるjavahというコマンドを使います。javahコマンドを使ってヘッダーファイルを作成する方法を、2つ紹介します。


1.コマンドプロンプトを使う


まず、コマンドプロンプトでプロジェクトのルートフォルダーに移動します。Windows 8ならば、エクスプローラーでプロジェクトのフォルダーを開き、メニューの「ファイル」→「コマンドプロンプトを開く」で、目的のフォルダーで簡単に開くことができます。


ここで、


C:\Users\hogehoge\workspace\NDKSample>javah -o jni/ndksample.hpp -classpath bin/classes com.example.ndksample.MainActivity


と入力します。-oは出力先、-classpathは参照するクラスパス、その後に続くのは対象のクラスを完全修飾名で記述したものです。Androidのプロジェクトが自動ビルドになっていると、Javaのソースファイルを保存した時点でbin/classes以下にclassファイルが生成されますので、これを参照させます。 

10.png


このコマンドを入力すると、プロジェクトのjniフォルダーの下にndksample.hppが生成されます。外部コマンドによりファイルが追加されたので、すぐには表示に反映されないため、F5キーを押してリフレッシュしてみましょう。


2.Eclipseの外部ツール構成を使う


前項のコマンドプロンプトによる操作の代わりに、Eclipseの外部ツール呼び出しの機能を使ってヘッダーファイルを作成することもできます。そのためには「外部ツール構成」を作成します。まずEclipseのツールバーにある「外部ツール」アイコン右側の黒三角をクリックして、「外部ツールの構成」を選択します。

16.png


表示された「外部ツール構成」の画面で、左側の「プログラム」の部分をクリックし、左上の方にある「新規作成」アイコンをクリックします。すると、「新規構成」という項目が作成されます。その画面を、下図のように編集します。 

14.png


項目設定
名前NDK create header(適当な名前で良い)
ロケーション${system_path:javah}
作業ディレクトリー${project_loc}
引数-d jni -classpath bin/classes ${java_type_name}

${}で囲まれている項目は、Eclipse内における環境変数を意味します。「変数」というボタンをクリックするとリストが出てくるので、その中から選択することで打ち間違いを防ぐこともできます。


また、「ビルド」タブをクリックして、「起動前にビルド」のチェックを外しておきます。 

15.png


ここまで設定したら、「適用」ボタンをクリックし、閉じます。そして、Javaソースファイルを開いてテキストエディターがアクティブの状態で再び上記の画面を開き、「実行」ボタンを押します。これでjavahが実行され、jniフォルダーの下にヘッダーファイルが生成されます。こちらもプロジェクトにはすぐに反映されないため、F5キーを押してリフレッシュしましょう。


生成されたヘッダーファイルは、対象のクラスの完全修飾クラス名を元にした名前(今回の例で言えばcom_example_ndksample_MainActivity.h)になるため、その都度適当な名前にリネームしましょう。対象ファイル名の上でマウス右クリックをして、コンテキストメニューの「リファクタリング」から「名前変更」を選ぶことで、リネームができます。ここでは、ndksample.hppにリネームします。


一度でも実行した構成は、次回からは「外部ツール」アイコン右側をクリックしたときの「起動ヒストリー」に加わるので、ここから選択することも可能です。 

17.png


2つの方法によるヘッダーファイルの生成方法を紹介しましたが、どちらを利用するかはお好みで良いでしょう。いずれの方法を採っても、下図のような関数プロトタイプ宣言が作られるので、この部分をndksample.cppにコピーペーストします。

11.png


注意

  • (2013/07/07追記)
  • Java 6が開発終了となりました。Java 7を用いてAndroidアプリケーションを開発することは可能なのですが、Java 7のJDKに含まれるjavahを用いると上記の操作ではヘッダーファイルが作成できなくなっています。これについての説明を記述した知恵ノート「Android開発をJava 7で行う」を作成しました。複数ページに跨り申し訳ありませんが、そちらを参照してください。


C++のソースファイル

ndksample.cppのソースファイルは次の通りです。cppなので本来はC++ソースファイルなのですが、前掲のヘッダーファイルを見れば分かる通り、関数のプロトタイプ宣言がextern "C"で囲まれているので、C言語で記述することができます。もちろん、C++に則ってクラスを使ったコーディングをすることもできますが、今回はそこまでしていません。


先に生成したヘッダーファイルのインクルードと、仮引数名の追記を忘れないようにします。


#include <jni.h>

#include <assert.h>

#include <ndksample.hpp>


JNIEXPORT jstring JNICALL Java_com_example_ndksample_MainActivity_msgFromNDK

(JNIEnv *env, jobject thiz, jint count) {

    const char *capital[] = { "東京", "ワシントン", "ロンドン", "パリ", "モスクワ", "北京" };

    jstring jstr = env->NewStringUTF(capital[count]);

    assert(jstr);

    return jstr;

}


ポイント

  • JNIEXPORTとJNICALLは、実は記述しなくても問題なく動作します。Windows上で動作するJavaアプリケーションを作成するときにJNIを用いるときはいずれも意味があるようですが、LinuxをベースとするAndroidではどちらも必要ありません(厳密に言うとJNIEXPORTはちょっとだけ意味があるようですが)。参考書でも、どちらも記述していないものが多いようです。ただ、あっても害があるわけでもなく、いちいち除去するのも面倒なので、そのままコピーペーストしておけば良かろうかと思います。

コンパイルしよう

C/C++によるソースファイルは、Javaと異なり自動コンパイルはされません。EclipseのパースペクティブをC/C++に切り替え、プロジェクト・エクスプローラーのプロジェクト名の上でマウスを右クリックすると、コンテキストメニューがJavaのときとは変わっています。この中から「プロジェクトのビルド」を選択するとコンパイルされます。また、「プロジェクトをクリーンにする」を選択すると、C/C++による中間ファイルやライブラリーが削除されます。なお、アプリケーション実行時にも自動的にコンパイルは行われるので、いきなり実行に進んでも構いません。 

12.png


さあ実行しよう!

これでコーディングは完了です。実機またはAVDを用意して、実行してみましょう。一つ注意ですが、この時点では作られるネイティブコードはARMアーキテクチャ向けになります。よって、実機であればARMプロセッサ搭載機、AVDであればCPU/ABIにARMを選択したものである必要があります。ここでは、Android 2.3.3のAVDで動かしてみます。 

13.png


Javaボタンを押す度に国名が変わり、Naviveボタンを押すとその首都が表示されるというものです。はい、つまらないアプリケーションですね(汗)


Javaで設定した変数がCに渡り、Cで記述した文字列がJavaに渡っていることがこれで確認できるでしょう。


他のアーキテクチャで実行するには

標準ではARMアーキテクチャ専用のライブラリーのみ生成されますが、他のアーキテクチャ向けのライブラリーを作るには、jniフォルダーにApplication.mkというファイルを新規作成し、


APP_ABI := x86


のようにAPP_ABIという環境変数を設定します。x86と指定すればIntel x86向け、mipsと指定すればMIPS向けのライブラリーが作られます。allと指定すれば全アーキテクチャ向けのライブラリーが作られます。複数のアーキテクチャに対応した配布パッケージを作りたいときには有効です。


なお、Application.mkに記述できる環境変数は他にも多数ありますが、今回は環境構築が主題ですので省きます。


トラブルシューティング

「Add Native Support」を選択すると、本来はC/C++ソースファイルのインクルードパスが自動設定されるのですが、これが正しく設定されないケースがあるようです。C/C++ソースファイルでインクルードファイルの参照エラーなどが発生するときは、jniフォルダー上でマウス右クリックし、「プロパティー」を選択して下図のように「パスおよびシンボル」にパスが設定されているかを確認してください。もし、この欄が真っ白だった場合は、一度Eclipseを終了して再起動するか、一度プロジェクトを閉じて開き直すことでパスが正しく設定されるようです。なお、手動でパスを追加するのは事態をさらに悪化させる可能性が高いので、避けた方が良いでしょう。

18.png


NDKは奥が深い!

ここまでの内容は、NDKの超入門でしかありません。NDKの全容は非常に奥が深いものになっています。しかし、NDKを活用することで、Androidアプリケーションの世界は一気に広がります。ぜひともトライしてみてはいかがでしょうか。


改版履歴

(2012/12/06)初版

(2013/05/02)体裁崩れ修正、NDK改版に伴う記述修正、画像全面張替え

(2013/05/07)Eclipseの外部ツール構成によるヘッダーファイル作成方法を追記

(2013/07/07)Java 7についての記述追加

(2014/03/16)サンプル作成で表記の言語が合ってないことを修正、「次でコンパイル」の機能について注釈追加


このノートのライターが設定した関連知恵ノート

このノートについて質問する

このノートについてライターの方に質問できます。

※ライターの方から必ず回答をいただけるとは限りません

※別ウィンドウで開きます

この知恵ノートのライター

アップロード写真

グレード知恵ノートのグレード:3-3

カテゴリマスター

keicha_hrsさん

ピックアップ

【パズドラ】無課金プレイで強...
無課金で、あまり無茶なリセマラをせずにパズドラで強くなり...
Androidの標準ブラウザーでYaho...
 はじめにAndroidの標準ブラウザーの検索窓で、Yahoo!検索を...
幼稚園の補助金について -私立...
この知恵ノートについて 私が幼稚園の補助金、「私立幼稚園就...
本文はここまでです このページの先頭へ