Android NDK と NativeActivity

Android OS 2.3、API Level 9 から NativeActivity が利用出来るようになります。
画面の初期化やイベントの取得も Java コードを通らずに C/C++ だけで
記述することが可能です。

とは言え実際にアプリケーションを記述する手段はこれまでとほとんど変わりません。
jni フォルダに C/C++ コードを置いて ndk-build を使います。
生成されるバイナリも従来同様 Dynamic Link Library (dll) ~.so です。

・今までの NDK (jni)
  Java 上で dll をロードし、interface class を経由して呼び出し

・NativeActivity
  システムが直接 dll をロードし dll 内のエントリポイントを直接呼び出す

●エントリポイントの指定

最初に呼ばれる関数名を AndroidManifest.xml に記述します。

・Java コードを含まないことを宣言
   のアトリビュートに android:hasCode=”false”

・dll 名の指定
   宣言内に で指定する。
  例えば libappmain.so の場合


・エントリポイント名の指定
  例えば関数 Main_onCreate() から開始する場合


これで Activity の起動時に libappmain.so 内の Main_onCreate() が
直接呼び出されるようになります。

●イベント

Java と全く同様に NativeActivity も onStart, onResume, onPause, onStop,
onDestroy, onRestart 等のイベントが呼ばれます。
あらかじめイベントごとに Callback 関数を登録しておく必要があります。

onCreate のみ特別で、Callback ではなく Activity 起動時のエントリ関数として
AndroidManifest.xml に記述します。
AndroidManifest.xml に func_name の記述がない場合は関数名
ANativeActivity_onCreate() とみなします。
この関数の実体はアプリケーション側で記述しておく必要があります。

(1) onCreate で AndroidManifest.xml に記述した関数が呼ばれる
(2) onCreate 内部で他のイベントの Callback 関数を登録する
(3) 各イベントで Callback 関数が呼ばれる

●android_native_app_glue

ndk の sample/native-activity や NativeActivity の Reference に
掲載されてるコードは android_native_app_glue を使っています。
これはサンプルに含まれる Utility Library です。
内部では下記の動作を行っています。

1. 各イベントごとの Callback 関数を登録する
2. NativeActivity 用のスレッドを生成する
3. イベントを格納するキューを作る
4. ユーザー定義関数 android_main() をスレッドから呼び出す

つまり、これにより android_main をイベント待ちのループとして記述できる
ようになります。Win32 API とかでよくあるスタイルです。

●static 領域の初期化

NativeActivity でも従来の jni 経由の NDK (dll) 呼び出しと全く同じです。
Activity が onDestroy で破棄されても dll 自体はしばらくメモリ上に
常駐する可能性があります。
この場合再び onCreate しても static 変数の値が初期化されずに以前の値を
残しています。

onCreate 時に自分で初期化するか前回試したような dll の分離が必要となります。

参考ページ
NativeActivity

関連エントリ
Android NDK の初期化と dll の分離
Android アプリケーションとプロセス

Android NDK と NativeActivity」への6件のフィードバック

  1. vector

    初めまして。

    NativeActivityの詳しい情報ありがとうございます。
    少し疑問が残るので、もしよろしければお答えいただけないでしょうか。

    VC++のみで米塩を得てきたものですが、androidに進もうと決心しました。
    Linux、Javaはまったく知りません。
    std::***はメインのライブラリで使っており、ネットワークはboost:::asioになじんでおります。

    android2.3以降では対応ということなので、c++のみでの開発に希望を持ちました。

    jiniのボトルネックを避けうること、nativeのスピードを維持できることは可能でしょうか?
    debugはnativeレベルで可能でしょうか?

    よろしくお願い申し上げます。

    vector

  2. oga 投稿作成者

    NDK はリリース毎に徐々に C/C++ でできる範囲が拡がっています。
    ですが Java と全く同じ機能や Lib が C/C++ に提供されている
    わけではないです。
    おそらくアプリケーションや用途によってまだまだ Java と
    使い分ける必要があると思います。

    Android で C/C++ を使うメリットとしては
    ・既存コード資産を活用できる
    ・他のプラットフォームとの互換性、共通言語として
    ・GC の影響を受けない
    があります。

    OS 2.3 での拡張は、サンプルを見ても EGL/OpenGL ES 2.0 を
    使ってることからゲーム用途が中心ではないでしょうか。
    それ以外は Java が必要だと思います。

    NDK デバッグは gdb を使えば Native で可能です。
    ただ個人的にはまだうまく安定して使いこなせていない状態です。

    NDK も Eclipse や VisualStudio を使ってビルドする方法も
    あるようです。

  3. vector

    ogaさん、回答ご丁寧にありがとうございました。

    >おそらくアプリケーションや用途によってまだまだ Java と
    >使い分ける必要があると思います。

    ゲーム制作を想定していないので、C++オンリーでは難しそうですね...。
    android命と思い切ってJavaに挑戦して見ようかと考えます。
    しかしやはりガベージコレクションがあるんですね...。
    ゆくゆくはJava並の機能やライブラリが提供されるだろうと淡い期待をもちながら、やってみようと思います。

  4. vector

    ogaさん、お久しぶりです。
    その後、java、jni、Android SDK/NDKの順に自習してきました。
    (といってもエミュレータだけですが…)
    NDKは、そのサンプルやunzip、jpeg解凍の解説ページを参考にしました。

    でやはりC/C++のデバッグの問題に行き当たりました。
    ググると、EclipseのCDTとDDDがよさげですが、CDTでも~.soをjavaから起動してその後にアタッチできるのでしょうか?
    ogaさんはgdbだということですが、cuiですか?

    実機は考え中ですが、銀河S2かxperiaになりそうです。

    よろしくお願い申し上げます。

  5. oga 投稿作成者

    NVIDIA が公開している Tegra 用のツールにも
    ndk デバッグ用の Eclipse plug-in があります。
    CDT は Windows だと cygwin path との変換が問題に
    なるようで、このプラグインもパス変換してました。
    まだあまり試せておらず実は環境構築もぜんぜん
    進んでおりません。

  6. vector

    >CDT は Windows だと cygwin path との変換が問題に
    >なるようで、このプラグインもパス変換してました。

    そんなことがあるんですね。
    しかしgdbはコマンドラインでも感動ものですが、大規模デバッグにはとてもですね。
    いっそ、javaフレーム部分をc++で書きいておいて、VisualStudioで作業をしてからが初心には楽かもと。

コメントは停止中です。