182
180

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Android StudioのNDK開発機能を使おう!

Posted at

@eaglesakura です。

5月のGoogle IOでAndroid StudioのNDK対応が発表されてからずっとNDK対応するする詐欺を1ヶ月半されてきましたが、7/10のアップデート(Android Studio 1.3 RC1)でようやく待望のNDK対応アップデートが行われました。

使った感じはかなり良いのですが、前提条件やハマりどころが多いので、自分用のメモを兼ねて投稿します。

準備

準備を行わずにASのアップデートのみを行っても、NDK機能は全く動作してくれません。また、ビルドも行ってくれません。

それを回避するためには、前提条件をクリアする必要があります。

  1. Android Studio 1.3 RC1をインストールする
  2. JDK 1.7をインストールする
  • Android Studioの環境変数もちゃんとJDK1.7に変更しておきましょう。
  1. Gradle 2.5をインストールする
  • 最近GradleがC/C++対応したのはコレ関係かもしれないですね。

スクリーンショット 2015-07-11 9.29.21.png

新Pluginに合わせてbuild.gradleをかなり書き換える

NDK対応を行うためか次のステップのためかはわかりませんが、Android StudioのNDK機能を利用するためには、"実験用"とされてるPluginを利用する必要があります。

このPluginではbuild.gradleの記述がかなり変更されているため、実案件で使うと将来痛い目に会うかもしれません。また、確認した限りいくつかのバグがまだあります。

まず、experimental用のGradlePluginは今までとは別なPluginとして扱われるので、classpathを書き換える(もしくは追記する)必要があります。

root/build.gradle
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        // classpathが変わった
        classpath 'com.android.tools.build:gradle-experimental:0.1.+'
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

さらに、プロジェクトをビルドするためのbuild.gradleが大胆に変更されています。Plugin名も変わっています。

記述方法は、従来は"compileSdkVersion 22"のように記述していた部分が、"compileSdkVersion = 22"のように"="で記述するようになりました。実装的には、メソッドではなくて変数に書き換わったかと思います。

  • 全ての変数がそうなのか?というとそうではなくて、一部は従来のようにメソッドのままなので、多少統一感がありません。今後変更される可能性があります。

他にも"defaultConfig"ブロックが"defaultConfig.with"のように書き換えが必要だったり、結構変更は多いです。
そもそもandroidブロック全体を"model"ブロックが包んだりしているので、互換性とかありません。ガンバって書き換えましょう。

root/プロジェクト/build.gradle
// Plugin名が変わった
apply plugin: 'com.android.model.application'

model {
    android {
        compileSdkVersion = 22
        buildToolsVersion = "23.0.0 rc3"

        defaultConfig.with {
            applicationId = "com.example.eaglesakura.ndk.helllo_ndk"
            minSdkVersion.apiLevel = 15
            targetSdkVersion.apiLevel = 22
            versionCode = 1
            versionName = "1.0"
        }

        // package除外は多少法則が乱れる。ややこしい。
        packagingOptions.with {
            exclude 'LICENSE.txt'
            exclude 'META-INF/LICENSE'
            exclude 'META-INF/LICENSE.txt'
            exclude 'META-INF/NOTICE'
            exclude 'androidannotations-api.properties'
            exclude 'services/com.fasterxml.jackson.core.JsonFactory'
            exclude 'services/com.fasterxml.jackson.core.ObjectCodec'
        }
    }

    android.buildTypes {
        debug {
            isJniDebuggable = true
        }

        release {
            isMinifyEnabled = false
            proguardFiles += file('proguard-rules.pro')
        }
    }


    android.sources {
        main {
            jni {
                source {
                    // JNIのソースディレクトリを変更したい場合、コレで追加削除できる
                    srcDirs = [file("src/main/jni"), file("ndk")]
                }
            }
        }
    }

    android.ndk {
        moduleName = "app"
    }
    android.productFlavors {
        // 特定のabiだけビルドしたい
        create("arm7") {
            ndk.abiFilters += "armeabi-v7a"
        }

        // 全部のabiをビルドしたい
        create("fat") {
        }
    }
}
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.1.1'
}

これでAndroid Studioが新Pluginを利用してくれて、NDK機能が有効化されるはずです。あとはjniのディレクトリのhoge.cppを入れておけば、勝手にビルドしてくれます。

NDK機能はJavaの"native"メソッドをチェックして、もしCPP側に実装されていなかったら警告を出すようにしてくれるので、非常に親切です。

ブレークポイントで止める

無事にビルドできたら、次はブレークポイントで止めてみたくなりますね。ブレークポイントの設定はJava側と同じです。

スクリーンショット 2015-07-11 9.28.08.png

JNIデバッグをONにする

ドキュメントのどこにも見つかりませんでしたが、JNIのデバッグをONにするためには、android.buildTypesブロックの中でisJniDebuggable=trueをする必要があります。

次に"Edit Cofigures"でAndroid Nativeの実行設定を作成して、それに切り替えます。

スクリーンショット 2015-07-11 9.28.46.png

スクリーンショット 2015-07-11 9.26.11.png

あとはいつものようにデバッグボタンを押して実行すると、JNIのデバッグ接続が行われます。

起動直後は停止できない

NDK用のデバッガ(LLDB)は、アプリが起動後に接続される(しかも数秒かかる)ため、onCreate等の起動直後のブレークポイントはそのままでは捉えることが出来ません。接続されているかどうかをチェックするためには、Debugのログを観察しましょう。

"Debugger attached to process XXXX"と表示されたタイミングから、ブレークポイントで止めることが出来ます。

スクリーンショット 2015-07-11 9.36.03.png

起動直後のブレークポイントで停止させる

起動直後のブレークポイントで止めたい場合、少しだけ工夫が必要です。Androidの開発者機能で"デバッグアプリを選択"をして、デバッグしたいアプリを選択します。

device-2015-07-11-093830.png

次に"デバッガを待機"を有効化します。

device-2015-07-11-093931.png

これでデバッガが接続されるまで、アプリの起動を保留することが出来ます。この状態で再度実行すると、こんな感じで止まります。

device-2015-07-11-094059.png

ただしNDKのデバッガ(LLDB)が接続されても、AndroidはLLDBをデバッガと認識しないため、いつまでたっても起動しません。そこで、Java側のデバッガも追加でアタッチします。

メニューの"Attach debugger to Android process"を選択して、接続したいアプリのpackageを選択してOKします。

  • 画像の一番右側 スクリーンショット 2015-07-11 9.40.45.png

スクリーンショット 2015-07-11 9.43.09のコピー.png

するとAndroidはデバッガ接続を認識してアプリ起動を続行してくれるので、あとはブレークポイントを待てばOKです。Javaのデバッガも同時接続しているので動作は緩慢になりますが、この方法であればNDK/SDK両方のデバッグを行えます。便利ですね。

  • C++のブレークポイントで止められる
  • スクリーンショット 2015-07-11 9.45.14.png
  • 値を見ることが出来る
  • スクリーンショット 2015-07-11 9.45.18.png
  • 値の強制的な書き換えもできる(私の環境だと変数を指定してF2ボタン)
  • スクリーンショット 2015-07-11 9.46.45.png
  • スクリーンショット 2015-07-11 9.46.37.png

現行バージョンのGradleプロジェクトとの連携

実際の開発で使おうと思うと非常に問題となるのは、「そもそもbuild.gradleの構成が違いすぎる」ということです。例えば、android-aptのPluginは正常に動作しませんでした。

これはライブラリプロジェクトを併用することで回避できます。具体的には、Java側をライブラリプロジェクトに移行して、C++側だけを新しいプロジェクト構成にすればOKです。

現状のASはライブラリプロジェクトもデバッガを接続でき、なおかつ従来構成のgradleも今までどおり利用できます。併用を出来るようにしてくれたのは、非常にありがたい点でした。

現状での不明な機能

  • 指定した*.cppや*.cをビルドから除外する
  • ビルドはディレクトリ単位で突っ込まれるので、もしOSS等でtest用のcppがディレクトリに含まれていると、ビルドが壊れる原因になる。
  • glmとか。

現状の困った不具合

  • clangでビルドすると、成果物にapkが含まれない

困ったときのLink

最後に

  • 別な環境だと別な点でドはまりするかもしれません。
  • 何かあったら追記していきます。
182
180
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
182
180

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?