【Android Studio】NDKを使ってHelloWorld_手動ビルド【日本語】

この度、NDKを使う機会が出てきたので、AndroidStudioでNDKを使ってHelloWorldを表示させる備忘録です。

NDKの導入方法から記載していきます。

尚、この記事はC言語のファイルをndk-buildコマンドを使い、手動でビルドしてます。

CMakeを使って自動でビルドする場合はこちらをご参照ください。

 

他のプログラミングに関する記事はこちら

スポンサーリンク


 

【前提:NDKとは】

NDKとは、Native Development Kitの略で、AndroidでCやC++の言語を使えるようにするツールです。

本来AndroidはJava(もしくはKotlin)で開発しますが、NDKを使うことでCやC++が使えるようになります。

 

【前提:なぜNDKを使うのか】

なぜNDKを使うのか、公式によると以下2つの理由があげられます(めっちゃ意訳)

 

・処理速度が遅くなるレベルの重い処理を早く処理させたい場合
・CやC++でしか使えないライブラリを使いたい場合

 

後者はそのままの意味ですが、前者については以下サイトの速度比較がわかりやすかったです。

結論から先に言えば、Javaに比べてCの処理速度はめっちゃ早いです。

https://qiita.com/Lily0727K/items/26d3e68d66a6a641b010

なので、ゲームや物理学シミュレーション等、何か画面の内容がバリバリ動くような重い処理を行うときにNDKを使った方がいい感じになりそうです。

 

逆に言えば、

 

・重い処理がそこまでない(画面の内容がそんな変わらない……スケジュール管理アプリ等?)
・CやC++でしか使えないライブラリを使う予定がない

 

上記のようなアプリを作る場合は、NDKを使わずに基本通りJavaかKotlinを使って開発すべきと感じます。

 

【NDKでHelloWorld】

それでは早速、NDKを使ってHelloWorldを表示させてみます。

以下の手順で説明していきます。

 

・NDKの導入
・実際に作っていく

 

尚、前準備として空のプロジェクト(新規でプロジェクトを作成し、その後何も手をつけてない状態……小さい文字で「Hello World!」と表示されるアプリが出来ている状態)を作成しておいてください。

※空のプロジェクト作成については、こちらの1の手順参照

 

【NDKの導入】

1.AndroidStudioのメニュー「Tools」>SDK Managerをクリックします。

 

2.Android SDKタブ>SDK Toolsタブ>NDK(Side by side)にチェック>Apply でインストールされます(所要時間20分ぐらい)

 

3.インストール後、手順2の画像のSDK Toolsタブのちょっと上にある「Android SDK Location」のディレクトリを開きます

 

4.そこから更にndk>[数字の羅列のフォルダ]と遷移し、そこのパスをコピーします

 

5.手順4で取得したパスを環境変数のPathに設定します(パスを通します)

 

6.コマンドプロンプトで「set path」と打ち、環境変数Pathにちゃんと設定されているか確認します

もし設定したパスが反映されていない場合はPC再起動で反映される場合がありますので、試しにPC再起動してみてください

 

以上でNDKの導入は完了です。

パスが通っているかは当たり前ですが重要なことなので、しっかりと確認してから次の手順に進んでください。

私はうまくパスが通ってなかったせいで、無駄に時間がかかってしまいました。

 

【実際に作っていく】

NDKの導入は完了したので、あとはどう使うかを説明していきます。

※自動でビルドするようにしたい場合はこちらをご参照ください。NDK導入までは手動ビルドでも自動ビルドでも必要な手順ですが、以下からの記述は手動ビルド用の内容です。

 

1.appを右クリック>New>Directoryをクリックします

 

2.src\main\jniと入力しEnterします(これでsrc\main\jniディレクトリが出来ます)

 

3.手順2を行うとcppというのが画面左に表示されます(AndroidStudioのバージョンによっては、src\main\jni?)

このcppを右クリック>New>Fileをクリックします

 

4.hello.cと入力し、Enterします。

この拡張子cの前の文字がライブラリ名になります。

 

5.hello.cの中身を以下の通り作成します。

#include <string.h>
#include <jni.h>

jstring
Java_com_example_ndk_MainActivity_stringFromJNI( JNIEnv* env, jobject thiz ) {
    return (*env)->NewStringUTF(env, "Hello JNI !");
}

当たり前ですが、hello.cはC言語で書きます。

内容としては、「Hello JNI !」の文字列を返す簡単な内容です。

 

ここで重要なポイントがあります。

関数名(5行目の記述)は、以下のルールで設定してください。

Java_[パッケージ名]_[呼び出し元のアクティビティ名]_[関数名]

 

今回の例でいうと、Java_com_example_ndk_MainActivity_stringFromJNIと記載していますが、

Javaは固定……お決まりの文字列です。

com_example_ndkはパッケージ名の.を_に変えたものです。

パッケージ名は適当なアクティビティ(以下図はMainActivity.java)を開き、一番上に表示されているpackageを見ればわかります。

MainActivityは呼び出したいアクティビティ名です。

今回はMainActivityから呼び出す予定なので、MainActivityとしています。

stringFromJNIは関数名です(ここは自由に設定していい)

 

6.「hello.c」を作成したら、cppを右クリック>New>Fileをクリックします。

 

7.「Android.mk」と入力しEnterします

 

8.初めてmkファイルを作成するので、何で表示するか求められる場合があります。

もし何で表示するか求められたらTextで問題ないので、そのままOKします。

 

9.Android.mkファイルを以下の通り作成します。

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE    := hello
LOCAL_SRC_FILES := hello.c

include $(BUILD_SHARED_LIBRARY)

mkファイルはこの後に行う「ndk-build」をする際に必要な設定情報です。

詳しく知りたい場合は、こちらの記事がわかりやすかったです。

 

10.cppを右クリック>Directory Pathをクリックします

 

11.Show in Explorerウィンドウが表示されるので、appをクリックします

 

12.appディレクトリがエクスプローラーで開くので、そこからsrc>main>jniと遷移し、そこのディレクトリパスをコピーします(先ほど作ったhello.cとAndroid.mkがあるディレクトリパスが取れれば方法は何でもいいです)

 

13.AndroidStudioの画面下部にあるTerminal>cd [先ほど取得したディレクトリパス]と入力し、hello.cとAndroid.mkがあるディレクトリに移動します(多分このあたりのコマンドを打つ作業はコマンドプロンプトでやっても同じです)

 

14.ndk-buildコマンドを打ちます

ndk-buildをすると、jniディレクトリ(hello.cとかがある場所)と同じ位置にあるlibsディレクトリ内に、soファイルが入った各フォルダがビルドされます。

私はここでndk-buildしたタイミングでコマンドがありませんと出てはまりました(環境変数にndkのディレクトリがうまく設定されてなかっただけでした)

 

15.build.gradle(Moduleの方)を開き、android内のdefaultConfigに、以下を設定します。

sourceSets {
    main {
        jni.srcDirs = []
        jniLibs.srcDir "src/main/libs"
    }
}

全体的な感じは以下の通りです。

 

16.MainActivityクラスを以下の通り記述します。

public class MainActivity extends AppCompatActivity {

    // hello.soの読み込み
    static {
        System.loadLibrary("hello");
    }

    // helloライブラリにあるメソッドの定義
    public native String stringFromJNI();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // メソッドの呼び出し
        String text = stringFromJNI();
        // 表示
        new AlertDialog.Builder(this).setMessage(text).show();
    }
}

追加したのは3~6行目、8~9行目、16~19行目です。

 

3~6行目で、hello.cからビルドされたsoファイルを読み込みます。

8~9行目で、stringFromJNI関数をMainActivityから呼び出せるように設定してます。

16~17行目で、stringFromJNI関数を呼び出し戻り値(Hello JNI!)を受け取ってます。

18~19行目で、メッセージボックスで受け取った値「Hello JNI !」を表示しています。

 

17.これでHelloWorld的なアプリは作成完了です。

試しにエミュ等でアプリを起動すれば、うまく文字が表示されるはずです。

 

他のプログラミングに関する記事はこちら

スポンサーリンク