この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
本日は弊社創立記念日です。
せっかくなので過去記事を探してもあまり無い、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に失敗していないか
最後に
以上で、導入を終わります。
お気づきの点があれば、コメントに記載をお願い致します。