Android Studio 2.1.2 で C++ ライブラリを作ってみた
2016-07: Android Studio の C++ 対応状況
- Android Studio で新しいプロジェクトを作ると Gradle Plugin のバージョンは 2.1.2 、 Grade のバージョンは 2.10 になってる
-
Experimental Gradle Plugin に差し替えれば C++ をビルドできる
- Google のサンプル では gradle-experimental 0.7.0 を使ってるが、0.7.2 がリリースされてる
- 2016-08-08: ソースはこれかな?
- チケットはこれかな? (でも 2016 年のチケットが見当たらない...)
- 2016-08-12: ソースはここからもダウンロードできるっぽい
- 従来の Glade Plugin と Experimental Plugin を混在させることができる
- まだリリースされてない Android Studio 2.2 では Gradle ではなく ndk-build または CMake を使った C++ 開発を改善する
- ndk-build: build.grade の externalNativeBuild で Android.mk を指定できる
- cmake: build.grade の externalNativeBuild で CMakeLists.txt を指定できる
- コンパイルオプションなども指定できる
方針
-
メインとなる Java コードに C++ を追加することを想定し
- Java アプリは従来の Glade Plugin でビルド
- C++ 用のライブラリモジュールを別に作って Experiment Gradle Plugin でビルド
-
Experimental Gradle Plugin の 0.7.2 を使ってみる
環境
- Mac OS X 10.11.5 (英語)
- Oracle JDK 1.8.0_91
- Android Studio 2.1.2
- Android NDK r12b
手順
-
Android Studio で Empty Activity の新しいプロジェクトを作成
-
./build.gradle に gradle-experimental を追加
// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.1.2' classpath 'com.android.tools.build:gradle-experimental:0.7.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { repositories { jcenter() } } task clean(type: Delete) { delete rootProject.buildDir }
-
新しい Android Library モジュールを作成
-
./app/build.gradle にライブラリモジュールへの依存を追加 (
compile project
)apply plugin: 'com.android.application' android { compileSdkVersion 24 buildToolsVersion "24.0.0" defaultConfig { applicationId "jp.kenichi.androidapp04" minSdkVersion 15 targetSdkVersion 24 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile project(':mylibrary') compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:24.0.0' }
-
./mylibrary/build.gradle を gradle-experimental 用に書き換え
apply plugin: 'com.android.model.library' model { android { compileSdkVersion 24 buildToolsVersion "24.0.0" defaultConfig { minSdkVersion.apiLevel 15 targetSdkVersion.apiLevel 24 versionCode 1 versionName "1.0" } //buildTypes { // release { // minifyEnabled false // proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' // } //} ndk { moduleName "mylibrary" platformVersion 15 cppFlags.addAll(['-std=c++11', '-fexceptions', '-Wall']) ldLibs.addAll(['log']) stl = "gnustl_shared" } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:24.0.0' }
-
com.android.library
をcom.android.model.library
へ変更 -
android
ブロックをmodel
で囲む-
dependencies
はmodel
の外
-
-
minSdkVersion
とtargetSdkVersion
に.apiLevel
を追加 -
android
ブロックにndk
を追加 - ライブラリなので ``buildTypes``` をコメントアウト
-
addAll
ではなく+=
を使うと紛らわしいエラーが出る:Error:Unable to load class 'com.android.build.gradle.managed.NdkConfig$Impl'.
-
-
ライブラリモジュールに Java Class を追加し native メソッドを追加
public static native String getStringFromJni();
-
赤字になったメソッド名を選択して、左の赤い「!」から
Create function
-
jni フォルダと C ソースが作成される
-
JNI メソッドが生成されなかったので、仕方なく自分で記述
#include <jni.h> JNIEXPORT jstring JNICALL Java_jp_kenichi_mylibrary_LibCppClass_getStringFromJni(JNIEnv *env, jobject instance) { return (*env)->NewStringUTF(env, "Hello 世界"); }
-
-
MainActivity で定義した native メソッドを使う
-
ライブラリをロード
static { System.loadLibrary("mylibrary"); }
-
layout で TextView に id を付ける
-
その TextView に JNI から取得した文字列を設定
((TextView)findViewById(R.id.messageTextView)).setText(jp.kenichi.mylibrary.LibClass.getStringFromJni());
-
-
そのまま Run したら
couldn't find "libmylibrary.so"
エラーが出たが Android Studio を再起動して再度 Run したら動いた -
C を C++ に変更
-
h
#include <jni.h> extern "C" { JNIEXPORT jstring JNICALL Java_jp_kenichi_mylibrary_LibClass_getStringFromJni(JNIEnv *env, jobject instance); }
-
cpp
#include "libclass.h" JNIEXPORT jstring JNICALL Java_jp_kenichi_mylibrary_LibClass_getStringFromJni(JNIEnv *env, jobject instance) { return env->NewStringUTF("Hello 世界++"); }
参考
- gradle-experimental 0.7.0 を使う方法
- Android Studio で Hello-JNI を作る方法
- Android N では STL を 3 個の実装から選べる
- LLVM libc++
- GNU STL
- libstlport
- 各実装の説明