ネイティブ ライブラリ プロジェクトを Gradle ビルド依存関係として組み込むには、CMake または ndk-build のスクリプト ファイルへのパスを Gradle に指定する必要があります。アプリをビルドすると、Gradle は CMake または ndk-build を実行し、アプリと共有ライブラリをパッケージ化します。さらに、ビルド スクリプトも使って、Android Studio プロジェクトに含めるファイルも判別するため、[Project] ウィンドウからそれらのファイルにアクセスできます。ネイティブ ソースのビルド スクリプトがない場合は、次の手順に進む前に CMake ビルド スクリプトを作成する必要があります。
Android プロジェクト内の各モジュールがリンクできるのは、それぞれ 1 つのスクリプト ファイル(CMake または ndk-build)に限られます。そのため、たとえば複数の CMake プロジェクトからビルドして出力をパッケージ化する場合、1 つの CMakeLists.txt
ファイルを最上位の CMake ビルド スクリプトとして使用し(Gradle をそれにリンクし)、そのビルド スクリプトの依存関係として、その他の CMake プロジェクトを追加する必要があります。ndk-build を使用する場合も同様に、最上位の Android.mk
スクリプト ファイルにその他の makefile を含めることができます。
Gradle をネイティブ プロジェクトにリンクすると、Android Studio では [Project] ペインが更新され [cpp] グループにソースファイルとネイティブ ライブラリが表示され、[External Build Files] グループに外部ビルド スクリプトが表示されます。
注: Gradle の設定を変更したときは、必ずツールバーのプロジェクトの同期アイコン をクリックして変更を適用してください。また、Gradle にリンクした後に CMake または ndk-build のスクリプト ファイルを変更したときは、メニューバーから [Build] > [Refresh Linked C++ Projects] を選択して、Android Studio と変更内容を同期する必要があります。
Android Studio UI を使用する
Android Studio UI を使用して Gradle を外部の CMake または ndk-build のビルド プロジェクトにリンクすることが可能です。
- IDE の左側の [Project] ペインを開き、[Android] ビューを選択します。
- app モジュールなど、ネイティブ ライブラリにリンクするモジュールを右クリックし、メニューから [Link C++ Project with Gradle] を選択します。図 4 に示すようなダイアログが表示されます。
- プルダウン メニューから [CMake] または [ndk-build] を選択します。
- [CMake] を選択した場合は、[Project Path] の横にあるフィールドで、外部 CMake プロジェクト用の
CMakeLists.txt
スクリプト ファイルを指定します。 - [ndk-build] を選択した場合は、[Project Path] の横にあるフィールドで、外部 ndk-build プロジェクト用の
Android.mk
スクリプト ファイルを指定します。Android Studio は、Android.mk
ファイルと同じディレクトリに配置されているApplication.mk
ファイルがあれば、それも対象に含めます。
- [CMake] を選択した場合は、[Project Path] の横にあるフィールドで、外部 CMake プロジェクト用の
- [OK] をクリックします。
Gradle を手動で設定する
Gradle をネイティブ ライブラリにリンクするように手動で設定するには、externalNativeBuild
ブロックをモジュール レベルの build.gradle
ファイルに追加し、cmake
ブロックまたは ndkBuild
ブロックを使って設定する必要があります。
Groovy
android { ... defaultConfig {...} buildTypes {...} // Encapsulates your external native build configurations. externalNativeBuild { // Encapsulates your CMake build configurations. cmake { // Provides a relative path to your CMake build script. path "CMakeLists.txt" } } }
Kotlin
android { ... defaultConfig {...} buildTypes {...} // Encapsulates your external native build configurations. externalNativeBuild { // Encapsulates your CMake build configurations. cmake { // Provides a relative path to your CMake build script. path = file("CMakeLists.txt") } } }
注: Gradle を既存の ndk-build プロジェクトにリンクする場合は、cmake
ブロックではなく ndkBuild
ブロックを使用して、Android.mk
ファイルへの相対パスを指定します。Gradle は、Android.mk
ファイルと同じディレクトリに配置されている Application.mk
ファイルがあれば、それも対象に含めます。
オプション構成を指定する
CMake または ndk-build のオプションの引数やフラグを指定するには、モジュール レベルの build.gradle
ファイルの defaultConfig
ブロック内に別の externalNativeBuild
ブロックを設定します。defaultConfig
ブロック内のその他のプロパティと同様に、ビルド設定のプロダクト フレーバーごとに、これらのプロパティをオーバーライドできます。
たとえば、CMake または ndk-build のプロジェクトで複数のネイティブ ライブラリや実行可能ファイルを定義する場合、targets
プロパティを使用して、特定のプロダクト フレーバーのアーティファクトのサブセットのみをビルドしてパッケージ化することが可能です。設定できるプロパティの一部を、次のサンプルコードに示します。
Groovy
android { ... defaultConfig { ... // This block is different from the one you use to link Gradle // to your CMake or ndk-build script. externalNativeBuild { // For ndk-build, instead use the ndkBuild block. cmake { // Passes optional arguments to CMake. arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang" // Sets a flag to enable format macro constants for the C compiler. cFlags "-D__STDC_FORMAT_MACROS" // Sets optional flags for the C++ compiler. cppFlags "-fexceptions", "-frtti" } } } buildTypes {...} productFlavors { ... demo { ... externalNativeBuild { cmake { ... // Specifies which native libraries or executables to build and package // for this product flavor. The following tells Gradle to build only the // "native-lib-demo" and "my-executible-demo" outputs from the linked // CMake project. If you don't configure this property, Gradle builds all // executables and shared object libraries that you define in your CMake // (or ndk-build) project. However, by default, Gradle packages only the // shared libraries in your app. targets "native-lib-demo", // You need to specify this executable and its sources in your CMakeLists.txt // using the add_executable() command. However, building executables from your // native sources is optional, and building native libraries to package into // your app satisfies most project requirements. "my-executible-demo" } } } paid { ... externalNativeBuild { cmake { ... targets "native-lib-paid", "my-executible-paid" } } } } // Use this block to link Gradle to your CMake or ndk-build script. externalNativeBuild { cmake {...} // or ndkBuild {...} } }
Kotlin
android { ... defaultConfig { ... // This block is different from the one you use to link Gradle // to your CMake or ndk-build script. externalNativeBuild { // For ndk-build, instead use the ndkBuild block. cmake { // Passes optional arguments to CMake. arguments += listOf("-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang") // Sets a flag to enable format macro constants for the C compiler. cFlags += listOf("-D__STDC_FORMAT_MACROS") // Sets optional flags for the C++ compiler. cppFlags += listOf("-fexceptions", "-frtti") } } } buildTypes {...} productFlavors { ... create("demo") { ... externalNativeBuild { cmake { ... // Specifies which native libraries or executables to build and package // for this product flavor. The following tells Gradle to build only the // "native-lib-demo" and "my-executible-demo" outputs from the linked // CMake project. If you don't configure this property, Gradle builds all // executables and shared object libraries that you define in your CMake // (or ndk-build) project. However, by default, Gradle packages only the // shared libraries in your app. targets += listOf("native-lib-demo", // You need to specify this executable and its sources in your CMakeLists.txt // using the add_executable() command. However, building executables from your // native sources is optional, and building native libraries to package into // your app satisfies most project requirements. "my-executible-demo") } } } create("paid") { ... externalNativeBuild { cmake { ... targets += listOf("native-lib-paid", "my-executible-paid") } } } } // Use this block to link Gradle to your CMake or ndk-build script. externalNativeBuild { cmake {...} // or ndkBuild {...} } }
プロダクト フレーバーとビルド バリアントの設定方法については、ビルド バリアントを設定するをご覧ください。arguments
プロパティを使用して CMake で設定できる変数のリストについては、CMake 変数を使用する場合の説明をご覧ください。
ビルド済みのネイティブ ライブラリを組み込む
外部ネイティブ ビルドで使用されていないビルド済みネイティブ ライブラリを Gradle でパッケージ化する場合、それをモジュールの src/main/jniLibs/ABI
ディレクトリに追加します。
バージョン 4.0 より前の Android Gradle プラグインでは、CMake の IMPORTED
ターゲットをアプリに組み込むには、それを jniLibs
ディレクトリに含める必要がありました。以前のバージョンのプラグインから移行する場合には、次のようなエラーが発生する可能性があります。
* What went wrong:
Execution failed for task ':app:mergeDebugNativeLibs'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade
> More than one file was found with OS independent path 'lib/x86/libprebuilt.so'
Android Gradle プラグイン 4.0 を使用している場合、CMake の IMPORTED
ターゲットが使用するライブラリを jniLibs
ディレクトリから移動することでこのエラーを回避できます。
ABI を指定する
Gradle はデフォルトでは、NDK がサポートするアプリケーション バイナリ インターフェース(ABI)の個々の .so
ファイルにネイティブ ライブラリをビルドし、それをすべてアプリにパッケージ化します。Gradle を使ってネイティブ ライブラリの特定の API 設定のみビルドしてパッケージ化したい場合は、下記に示すように、モジュール レベルの build.gradle
ファイル内で ndk.abiFilters
フラグを使って指定できます。
Groovy
android {
...
defaultConfig {
...
externalNativeBuild {
cmake {...}
// or ndkBuild {...}
}
// Similar to other properties in the defaultConfig
block,
// you can configure the ndk block for each product flavor
// in your build configuration.
ndk {
// Specifies the ABI configurations of your native
// libraries Gradle should build and package with your app.
abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a',
'arm64-v8a'
}
}
buildTypes {...}
externalNativeBuild {...}
}
Kotlin
android {
...
defaultConfig {
...
externalNativeBuild {
cmake {...}
// or ndkBuild {...}
}
// Similar to other properties in the defaultConfig
block,
// you can configure the ndk block for each product flavor
// in your build configuration.
ndk {
// Specifies the ABI configurations of your native
// libraries Gradle should build and package with your app.
abiFilters += listOf("x86", "x86_64", "armeabi", "armeabi-v7a",
"arm64-v8a")
}
}
buildTypes {...}
externalNativeBuild {...}
}
ほとんどの場合、必要なのは上記のように ndk
ブロックに abiFilters
を指定することだけです。この設定によって Gradle はネイティブ ライブラリの目的のバージョンを対象に、ビルドとパッケージ化の両方を行うからです。ただし、アプリにパッケージ化する対象とは別個に、Gradle がビルドする対象を制御する場合は、defaultConfig.externalNativeBuild.cmake
ブロック(または defaultConfig.externalNativeBuild.ndkBuild
ブロック)内で別の abiFilters
フラグを設定します。Gradle はその ABI 構成をビルドしますが、パッケージ化するのは defaultConfig.ndk
ブロック内で指定したものだけに限られます。
ダウンロード時に配信されるのは、ユーザーのデバイスの ABI に一致するネイティブ ライブラリだけであるため、アプリのサイズをさらに小さくするために、Android App Bundle を使用して公開することをおすすめします。
APK を使用して旧式アプリ(2021 年 8 月より前に作成)を公開する場合は、ABI に基づくマルチ APK を設定することをおすすめします。ネイティブ ライブラリのすべてのバージョンを組み込んだ単一の大きな APK を作成するのではなく、サポート対象の ABI ごとに Gradle で個別の APK を作成し、各 ABI に必要なファイルだけをパッケージ化するようにします。上記のサンプルコードに示すように、abiFilters
フラグを指定せずに、ABI ごとに複数の APK を設定する場合、ネイティブ ライブラリについて、サポート対象のすべての ABI バージョンが Gradle でビルドされますが、パッケージ化されるのは、マルチ APK 設定で指定するものだけです。不要なバージョンのネイティブ ライブラリをビルド対象から除外するには、abiFilters
フラグと ABI ごとのマルチ APK 設定の両方に、ABI の同じリストを指定します。