Android NDK 〜導入編〜
はじめに
本日は弊社創立記念日です。
せっかくなので過去記事を探してもあまり無い、NDKについて書いていきたいと思います。
諸注意
前提条件として、Android Studioにて通常の開発が可能な状態まで整っていること。とさせて頂きます。
また、Gradleのバージョンによって記述が少し変わります。正常に動作しない場合は、環境をご確認ください。
今回は以下の環境で実施します。(どこで使うかは後述)
gradle-wrapper.properties
distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
build.gradle
classpath 'com.android.tools.build:gradle-experimental:0.2.0'
Java
JDK 7で実行してください。
導入
NDKの導入
画像では既にインストール済みですが、特に注意する点はありません。
サクッとNDKをインストールしましょう。
インストールが完了したら、パスを通しておきます。(インストール箇所は適宜読み替えてください)
export PATH=$PATH:/Users/ユーザ名/Library/Android/sdk/ndk-bundle/
ターミナルにて、ndk-buildのコマンドが利用できればOKです。
gradleのバージョンを変更
gradleのバージョンを変更する必要があります。
gradle-wrapper.propertiesの該当箇所を変更します。
distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
一度、gradle syncして正常にインストールされるか確認しましょう。
(Project Structure > Project > Gradle version からでも変更できます。)
build.gradleの書き換え
gradleのバージョンを変更したことにより、build.gradleの記述方法が変わります。
Experimental Plugin User Guide - Android Studio Project Site
ここが分かりづらい所だと思います。導入では最小限の記載で進めましょう。
apply plugin: 'com.android.model.application' model { android { compileSdkVersion = 23 buildToolsVersion = "23.0.3" defaultConfig.with { applicationId = "jp.maruyama.cm.ndksample" minSdkVersion.apiLevel = 16 targetSdkVersion.apiLevel = 23 versionCode = 1 versionName = "1.0" } } android.sources { main { jni { source { srcDirs = [file("src/main/jni")] } } jniLibs { source { srcDirs = [] srcDir "src/main/libs" } } } } android.ndk { moduleName = "app" } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:23.4.0' }
ここまで来たら、もう一度syncしましょう。
正常にビルドが完了すれば、下準備は終了です!
nativeメソッドの追加
Javaソースに、nativeメソッドを追加します。
package jp.maruyama.cm.ndksample.util; public class SampleUtil { static { System.loadLibrary("hello"); } public native String hello(); }
記述完了後、Javaのビルドを行ってください。hファイル作成時に利用します。
hファイルの作成
hファイルは今回必要ないのですが、メソッド名をコピペするために作成します。
まず、Android Studioでターミナルを開いてください。
何もしていなければ、プロジェクトルートで起動するはずです。
その後、以下のコマンドを実行します。(パッケージ名は適宜読み替え)
javah -classpath app/build/intermediates/classes/debug -d app/src/main/jni クラスのパッケージ名.SampleUtil
正常に動作すれば、main配下のjniディレクトリに以下のようなhファイルが作成されます。
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class jp_maruyama_cm_ndksample_util_SampleUtil */ #ifndef _Included_jp_maruyama_cm_ndksample_util_SampleUtil #define _Included_jp_maruyama_cm_ndksample_util_SampleUtil #ifdef __cplusplus extern "C" { #endif /* * Class: jp_maruyama_cm_ndksample_util_SampleUtil * Method: hello * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_jp_maruyama_cm_ndksample_util_SampleUtil_hello (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
作成できない場合は、javahコマンドを確認してください。
また、Javaをビルドしてクラスファイルを作成していないと怒られます。
hファイルの名前は、hello.hにしておきましょう。
cファイルの作成
ここでようやくC言語の出番です。(たまに書くと楽しい!)
hello.c という名前でsrc/main/jni に作成します。
#include <jni.h> // // Created by maruyama.kenya on 2016/07/04. // JNIEXPORT jstring JNICALL Java_jp_maruyama_cm_ndksample_util_SampleUtil_hello(JNIEnv *env, jobject thiz) { return (*env)->NewStringUTF(env, "Hello World JNI!!"); }
hファイルから定義はコピってきましょう。引数名の書き忘れに注意してください。
あとincludeも忘れないようにしましょう。
次にmkファイルの作成です。コンパイル指示書みたいなものです。
src/main/jni に Android.mk というファイルを作成し以下を記述します。
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello LOCAL_SRC_FILES := hello.c include $(BUILD_SHARED_LIBRARY)
makefileの詳細については、追々考えるとして今は気にせずコピペしてください。
ここまで来たら、ビルドしてみましょう。
Android Studio > Terminal
:NDKsample maruyama.kenya$ cd app/src/main/jni/ :jni maruyama.kenya$ ndk-build
カレントをjniにし、ndk-buildしてください。
正常にコンパイルされれば、soファイルが生成されます。
javaから呼び出し
準備ができましたので、Javaから実行してみましょう!
package jp.maruyama.cm.ndksample; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.widget.TextView; import jp.maruyama.cm.ndksample.util.SampleUtil; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); SampleUtil util = new SampleUtil(); TextView view = (TextView) findViewById(R.id.jni_text); if (view != null) { view.setText(util.hello()); } } }
正常に表示されました!お疲れ様でした。
よくあるエラー
Java実行時のエラーが発生した際には、以下を確認しましょう。
- JDKのバージョンが8系ではないか
-
build.gradleの記述にミスがないか
-
ndk-buildに失敗していないか
最後に
以上で、導入を終わります。
お気づきの点があれば、コメントに記載をお願い致します。